Docs de Autonomy
Integraciones

CircleCI

Ejecuta Autonomy desde CircleCI con una URL de previsualización web o un build móvil y condiciona el pipeline al veredicto.

Usa CircleCI para poner en cola ejecuciones de Autonomy después de un despliegue o un build móvil. Esta página incluye el script de API, las configuraciones completas y la comprobación del veredicto.

Ubicación del flujo

Ejecuta Autonomy cuando la previsualización sea accesible o exista el artefacto móvil. Cada configuración es una alternativa completa de .circleci/config.yml; copia la de tu plataforma. En un flujo existente, conserva el job de despliegue y haz que el job de Autonomy dependa de él con requires. Pasa la URL final del despliegue, no el localhost de un contenedor de CI.

Secretos requeridos

En CircleCI, abre Project Settings → Environment Variables y añade las entradas siguientes. CircleCI las inyecta en el shell del job; no escribas la clave de API en el YAML. También puedes guardarlas en un contexto restringido: asígnalo con context en la entrada del job dentro de workflows, no dentro de jobs.

  • AUTONOMY_API_URL: la URL base de la API de Autonomy, sin /api, con la URL HTTP de Convex que termina en .convex.site.
  • AUTONOMY_API_KEY: una clave de API de organización aut_ del mismo despliegue y organización que el plan.
  • AUTONOMY_TEST_PLAN_ID: abre un plan existente en Test Plans y copia su ID de /test-plans/<id> en la URL del dashboard. El plan debe contener al menos un caso de prueba de la plataforma elegida. Es el ID del plan, no el de un caso de prueba individual.
  • Web: PREVIEW_URL, la URL HTTPS accesible del despliegue.
  • Móvil: APP_IDENTIFIER, el bundle ID de iOS o el nombre del paquete de Android que corresponde al artefacto.
  • Casos de prueba que puedan ejecutarse con estos objetivos explícitos, sin valores de ejecución ni credenciales que solo aporte un Environment guardado. Debe haber un runner disponible para la plataforma elegida.

Usa un plan separado para cada plataforma. Las configuraciones esperan que AUTONOMY_TEST_PLAN_ID y APP_IDENTIFIER correspondan a la receta elegida. Si combinas plataformas, proporciona los valores adecuados mediante contextos separados o variables específicas por plataforma. Consulta Planes de prueba para agrupar los casos.

URL de previsualización web

Crea .ci/ en el repositorio, guarda el bloque siguiente como .ci/autonomy.sh y añádelo al control de versiones junto con .circleci/config.yml. Los jobs lo ejecutan con Bash, por lo que el archivo no necesita permiso de ejecución. Requiere Bash, curl y jq, incluidos en las imágenes de Linux utilizadas aquí.

#!/usr/bin/env bash
set -euo pipefail
set +x
: "${AUTONOMY_API_URL:?Set the API base URL, without /api}"
: "${AUTONOMY_API_KEY:?Set an aut_ organization API key}"
: "${AUTONOMY_TEST_PLAN_ID:?Set the Test Plans ID for this platform}"
: "${AUTONOMY_REQUEST_ID:?Set a unique CI job/attempt ID}"
platform="${1:-web}"
api="${AUTONOMY_API_URL%/}"
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

post() {
  curl --fail-with-body --silent --show-error \
    --connect-timeout 15 --max-time 90 \
    -X POST "$api$1" \
    -H "Authorization: Bearer $AUTONOMY_API_KEY" \
    -H 'Content-Type: application/json' --data-binary "$2"
}

case "$platform" in
  web)
    : "${PREVIEW_URL:?Set the reachable preview URL after deployment}"
    targets=$(jq -n --arg url "$PREVIEW_URL" '{web:{baseUrl:$url}}')
    ;;
  ios|android)
    : "${ARTIFACT_PATH:?Set the path to the app archive or APK}"
    : "${APP_IDENTIFIER:?Set the bundle ID or Android package name}"
    test -s "$ARTIFACT_PATH"
    file=$(basename "$ARTIFACT_PATH")
    bytes=$(wc -c < "$ARTIFACT_PATH" | tr -d '[:space:]')
    content_type=application/zip
    if [ "$platform" = android ]; then
      content_type=application/vnd.android.package-archive
    fi
    upload=$(post /api/artifacts/upload-url "$(jq -n \
      --arg platform "$platform" --arg fileName "$file" \
      --arg contentType "$content_type" --argjson declaredBytes "$bytes" \
      '{platform:$platform,fileName:$fileName,contentType:$contentType,declaredBytes:$declaredBytes}')")
    url=$(jq -er '.uploadUrl | strings | select(length > 0)' <<< "$upload")
    storage=$(jq -er '.storageId | strings | select(length > 0)' <<< "$upload")
    intent=$(jq -er '.intentId | strings | select(length > 0)' <<< "$upload")
    jq -e '.method == "PUT"' <<< "$upload" > /dev/null
    curl --fail-with-body --silent --show-error \
      --connect-timeout 15 --max-time 600 -X PUT "$url" \
      -H "Content-Type: $content_type" --data-binary "@$ARTIFACT_PATH"
    scan=$(post /api/artifacts/scan "$(jq -n \
      --arg storageId "$storage" --arg intentId "$intent" \
      '{storageId:$storageId,intentId:$intentId}')")
    if ! jq -e '.status == "clean"' <<< "$scan" > /dev/null; then
      echo 'Artifact scan did not pass; refusing to trigger.' >&2
      exit 1
    fi
    targets=$(jq -n --arg platform "$platform" --arg storageId "$storage" \
      --arg fileName "$file" --arg identifier "$APP_IDENTIFIER" \
      '{($platform):({storageId:$storageId,sourceMode:"upload",fileName:$fileName} +
        (if $platform == "ios" then {bundleId:$identifier} else {packageName:$identifier} end))}')
    ;;
  *) echo 'Usage: bash .ci/autonomy.sh web|ios|android' >&2; exit 2 ;;
esac

body=$(jq -n --arg testPlanId "$AUTONOMY_TEST_PLAN_ID" \
  --arg platform "$platform" --argjson targets "$targets" \
  --arg branch "${AUTONOMY_BRANCH:-manual}" \
  --arg commitSha "${AUTONOMY_COMMIT_SHA:-}" \
  --arg key "$AUTONOMY_REQUEST_ID:$platform" \
  '{testPlanId:$testPlanId,platforms:[$platform],targets:$targets,
    branch:$branch,deployment:{branch:$branch,commitSha:$commitSha},idempotencyKey:$key}')
post /api/v1/run.trigger "$body" > "$work/trigger.json"
jq -e '.runIds | type == "array" and length > 0' "$work/trigger.json" > /dev/null
jq -er '.runIds[] | strings | select(length > 0)' "$work/trigger.json" > "$work/run-ids"
printf 'Queued Autonomy runs:\n'
cat "$work/run-ids"

deadline=$((SECONDS + ${AUTONOMY_WAIT_SECONDS:-1200}))
while IFS= read -r run_id; do
  while :; do
    if (( SECONDS >= deadline )); then
      echo "Timed out waiting for $run_id; failing the CI job." >&2
      exit 1
    fi
    result=$(post /api/v1/run.get "$(jq -n --arg runId "$run_id" '{runId:$runId}')")
    status=$(jq -er '.status' <<< "$result")
    case "$status" in
      queued|running|retrying) sleep 10 ;;
      passing|failed|unverified|invalid|canceled)
        printf '%s: %s\n' "$run_id" "$status"
        if ! jq -e '.verdict == "passed" and .validity == "valid"' <<< "$result" > /dev/null; then
          echo "Autonomy gate failed for $run_id." >&2
          exit 1
        fi
        break ;;
      *) echo "Unexpected run status: $status" >&2; exit 1 ;;
    esac
  done
done < "$work/run-ids"
echo 'Every Autonomy run passed.'

Guarda esta configuración como .circleci/config.yml. Para la primera ejecución, establece PREVIEW_URL con una previsualización ya desplegada y haz push de los archivos a staging. La comprobación HTTP debe completarse antes de disparar Autonomy.

Para previsualizaciones por commit, exporta PREVIEW_URL y ejecuta el script en el mismo paso run. Un export por sí solo no persiste en otro paso. Para usar un paso run posterior del mismo job, añade esta línea después de obtener la URL en el paso de despliegue; CircleCI carga BASH_ENV en los pasos posteriores:

printf 'export PREVIEW_URL=%q\n' "$PREVIEW_URL" >> "$BASH_ENV"

Para jobs separados, guarda la URL obtenida en una sola línea en /tmp/autonomy-preview/preview-url.txt. Usa persist_to_workspace con root: /tmp/autonomy-preview y paths: [preview-url.txt] en el job de despliegue. En el job de Autonomy, usa attach_workspace con at: /tmp/autonomy-preview y ejecuta export PREVIEW_URL="$(cat /tmp/autonomy-preview/preview-url.txt)" antes de la comprobación HTTP. BASH_ENV no transfiere valores entre jobs.

version: 2.1

jobs:
  autonomy-web:
    docker:
      - image: cimg/base:current
    steps:
      - checkout
      - run:
          name: Check preview and run Autonomy
          no_output_timeout: 30m
          command: |
            set -euo pipefail
            set +x
            : "${PREVIEW_URL:?Set the deployed preview URL}"
            curl --fail --silent --show-error --location \
              --connect-timeout 15 --max-time 30 \
              --retry 10 --retry-delay 3 --retry-all-errors \
              --output /dev/null "$PREVIEW_URL"
            export AUTONOMY_BRANCH="${CIRCLE_BRANCH:-local}"
            export AUTONOMY_COMMIT_SHA="${CIRCLE_SHA1:-$(git rev-parse HEAD)}"
            export AUTONOMY_REQUEST_ID="circleci:${CIRCLE_WORKFLOW_ID:-local}:${CIRCLE_BUILD_NUM:-$(date +%s)-$$}:web"
            bash .ci/autonomy.sh web

workflows:
  preview-qa:
    jobs:
      - autonomy-web:
          filters:
            branches:
              only: staging

Para una comprobación local en macOS o Linux, inicia Docker y descarga la versión oficial de la CLI anterior v0.1.47860. Elige el archivo .tar.gz para tu sistema (darwin para macOS, linux para Linux) y procesador (arm64 para Apple silicon o ARM, amd64 para Intel o AMD). Extráelo y coloca el ejecutable circleci-v0 en un directorio de tu PATH. La CLI v1 actual eliminó la ejecución local; por eso los comandos siguientes usan el binario anterior.

Exporta las cuatro entradas en tu shell local y ejecuta estos comandos desde el repositorio con los archivos confirmados. CircleCI no importa secretos del proyecto ni contextos en local; cada -e es necesario. La configuración 2.1 debe procesarse antes de ejecutarla.

circleci-v0 config validate .circleci/config.yml
circleci-v0 config process .circleci/config.yml > /tmp/autonomy-circleci.yml
circleci-v0 local execute -c /tmp/autonomy-circleci.yml \
  -e "AUTONOMY_API_URL=$AUTONOMY_API_URL" \
  -e "AUTONOMY_API_KEY=$AUTONOMY_API_KEY" \
  -e "AUTONOMY_TEST_PLAN_ID=$AUTONOMY_TEST_PLAN_ID" \
  -e "PREVIEW_URL=$PREVIEW_URL" \
  -e "AUTONOMY_WAIT_SECONDS=${AUTONOMY_WAIT_SECONDS:-1200}" \
  autonomy-web

La ejecución local solo ejecuta este job de Docker. No demuestra la programación del flujo, las restricciones de contexto, la ejecución en macOS ni la transferencia del workspace de iOS.

Transferencia de artefactos móviles

El script solicita una URL de subida con el tamaño del archivo, sube con PUT y analiza con storageId e intentId. Solo dispara la ejecución después de un análisis clean. Conserva .ci/autonomy.sh y sustituye .circleci/config.yml por la configuración correspondiente.

iOS

Construye el .app de simulador en macOS y comprímelo antes de transferirlo para preservar los permisos de ejecución y los enlaces simbólicos. Pasa el ZIP a un job de Linux con persist_to_workspace y attach_workspace. La subida y la espera consumen créditos de Linux.

El ejemplo supone un proyecto nativo de Xcode en ios/MyApp.xcodeproj, un esquema compartido MyApp y un producto MyApp.app. Sustituye esos nombres por los de tu proyecto. Si utilizas un workspace de Xcode, cambia -project por -workspace y su ruta; conserva los pasos de instalación de dependencias antes de xcodebuild. No subas un .ipa para dispositivos.

CircleCI documenta actualmente 27.0.0 en m4pro.medium. macOS está disponible en el plan Free dentro de su límite de créditos; comprueba el saldo antes de ejecutar builds. circleci-v0 local execute no puede ejecutar este job de macOS.

version: 2.1

jobs:
  build-ios:
    macos:
      xcode: "27.0.0"
    resource_class: m4pro.medium
    steps:
      - checkout
      - run:
          name: Build and archive the Simulator app
          command: |
            set -euo pipefail
            xcodebuild \
              -project ios/MyApp.xcodeproj \
              -scheme MyApp \
              -configuration Release \
              -sdk iphonesimulator \
              -destination 'generic/platform=iOS Simulator' \
              -derivedDataPath ios/build \
              CODE_SIGNING_ALLOWED=NO build
            mkdir -p /tmp/autonomy-ios
            (cd ios/build/Build/Products/Release-iphonesimulator && \
              zip -qry /tmp/autonomy-ios/MyApp.app.zip MyApp.app)
      - persist_to_workspace:
          root: /tmp/autonomy-ios
          paths:
            - MyApp.app.zip

  autonomy-ios:
    docker:
      - image: cimg/base:current
    steps:
      - checkout
      - attach_workspace:
          at: /tmp/autonomy-ios
      - run:
          name: Upload and run Autonomy
          no_output_timeout: 30m
          command: |
            set -euo pipefail
            set +x
            export ARTIFACT_PATH=/tmp/autonomy-ios/MyApp.app.zip
            export AUTONOMY_BRANCH="$CIRCLE_BRANCH"
            export AUTONOMY_COMMIT_SHA="$CIRCLE_SHA1"
            export AUTONOMY_REQUEST_ID="circleci:$CIRCLE_WORKFLOW_ID:$CIRCLE_BUILD_NUM:ios"
            bash .ci/autonomy.sh ios

workflows:
  ios-qa:
    jobs:
      - build-ios:
          filters:
            branches:
              only: staging
      - autonomy-ios:
          requires:
            - build-ios
          filters:
            branches:
              only: staging

Android

La imagen de Android para Linux incluye el SDK, Java, curl y jq. El ejemplo supone un proyecto nativo de Gradle en android/, su gradlew ejecutable incluido en el repositorio y el APK de depuración del módulo app. Ajusta la tarea de Gradle y la ruta del APK para tu módulo o variante. Conserva la preparación de dependencias si la app también necesita JavaScript u otras herramientas de build.

version: 2.1

jobs:
  autonomy-android:
    docker:
      - image: cimg/android:2026.08
    resource_class: medium
    steps:
      - checkout
      - run:
          name: Build the debug APK
          command: |
            set -euo pipefail
            cd android
            ./gradlew --no-daemon :app:assembleDebug
      - run:
          name: Upload and run Autonomy
          no_output_timeout: 30m
          command: |
            set -euo pipefail
            set +x
            export ARTIFACT_PATH=android/app/build/outputs/apk/debug/app-debug.apk
            export AUTONOMY_BRANCH="$CIRCLE_BRANCH"
            export AUTONOMY_COMMIT_SHA="$CIRCLE_SHA1"
            export AUTONOMY_REQUEST_ID="circleci:$CIRCLE_WORKFLOW_ID:$CIRCLE_BUILD_NUM:android"
            bash .ci/autonomy.sh android

workflows:
  android-qa:
    jobs:
      - autonomy-android:
          filters:
            branches:
              only: staging

Condicionar el pipeline al veredicto

Una ejecución en cola no es una prueba superada. El script muestra todos los ID de ejecución y consulta POST /api/v1/run.get. Solo termina correctamente si cada ejecución devuelve verdict: "passed" y validity: "valid"; los fallos, las cancelaciones, las ejecuciones inválidas o sin verificar, los errores de API y los tiempos de espera agotados hacen fallar el job.

El tiempo de espera es de 1200 segundos para todo el plan. Establece AUTONOMY_WAIT_SECONDS si necesitas más e incrementa no_output_timeout de forma acorde. El límite de silencio predeterminado de CircleCI podría detener un bucle de consulta que funciona correctamente. La subida y el análisis preceden a este plazo. Coloca los jobs de publicación después del job de Autonomy con requires para impedir la promoción si la comprobación falla.

Estrategia de ramas y eventos

Estos ejemplos se ejecutan en staging. Amplía filters solo a ramas de confianza. Usa un plan de smoke pequeño para cambios revisados de previsualización y planes más amplios para versiones o ejecuciones programadas. Configura los disparadores de push, pull request o programación en el proyecto de CircleCI para tu VCS; los filtros de rama no crean esos disparadores.

Mantén desactivado Pass secrets to builds from forked pull requests donde esté disponible. Revisa el código no confiable antes de ejecutarlo en un job con la clave de API de organización y restringe los contextos compartidos a los proyectos y actores previstos. El ID de solicitud combina el flujo y el número de job: un nuevo intento puede crear otra ejecución, mientras que una solicitud repetida en ese intento es idempotente.

Referencias del proveedor

Comprobado con la documentación pública de CircleCI el 20 de septiembre de 2026:

On this page