Bitrise
Dispara ejecuciones de Autonomy desde Bitrise y condiciona el flujo a su resultado para web, iOS Simulator o Android.
Usa un paso Script de Bitrise para subir un build móvil o probar una previsualización web desplegada, y mantén el flujo abierto hasta que Autonomy devuelva un veredicto.
Ubicación del flujo
Añade el paso de Autonomy después de los pasos existentes de build y despliegue. Para web, publica la URL pública final como PREVIEW_URL desde el paso de despliegue con envman add --key PREVIEW_URL --value "$PREVIEW_URL"; los pasos posteriores podrán leerla. Para móvil, conserva el build y la subida en el mismo flujo para que el artefacto siga en el directorio de trabajo.
Las configuraciones completas siguientes son alternativas para bitrise.yml. Copia la de tu plataforma o integra sus pasos en el flujo existente. Configura Bitrise para leer bitrise.yml del repositorio y guarda .ci/autonomy.sh junto a él. El flujo web también puede ejecutarse localmente en un repositorio clonado.
Secretos requeridos
Antes de la primera ejecución
- Crea una clave de API de organización de Autonomy que empiece por aut_ en Settings → API Keys, en la organización que contiene tu plan.
- Crea un plan de test en Test Plans con al menos un caso de prueba ejecutable para la plataforma seleccionada y copia su ID.
- Usa casos de prueba que no referencien variables de entorno en tiempo de ejecución en esta receta con objetivos explícitos.
- Ten un runner de Autonomy disponible para la plataforma y una URL de previsualización accesible desde ese runner.
En Workflows → Secrets, añade AUTONOMY_API_KEY. Deja desactivadas Expose for pull requests y Replace variables in inputs. Los secretos se convierten automáticamente en variables de entorno del shell; no incluyas la clave en bitrise.yml.
En Workflows → Env Vars, establece estos valores para el flujo seleccionado:
| Variable | Valor |
|---|---|
AUTONOMY_API_URL | La URL HTTP base de tu despliegue, como https://your-deployment.convex.site, sin /api. No uses .convex.cloud. |
AUTONOMY_TEST_PLAN_ID | El ID copiado de Test Plans, que contiene los casos a ejecutar, no el ID de un caso de prueba individual. Usa un plan distinto por plataforma. |
PREVIEW_URL | Solo web: la URL final desplegada, sin inicio de sesión ni protección de previsualización. También puede proporcionarla el paso de despliegue. |
APP_IDENTIFIER | Solo móvil: el ID de bundle de iOS o el ID de aplicación de Android correspondiente al artefacto. |
AUTONOMY_WAIT_SECONDS | Opcional: tiempo máximo de espera en segundos; por defecto, 1200. |
URL de previsualización web
Crea un directorio .ci en el repositorio y guarda este script completo como .ci/autonomy.sh. Necesita Bash, curl 7.76 o posterior y jq; los stacks alojados seleccionados los incluyen. Instala estas herramientas para una ejecución local con la CLI. Mantén este archivo idéntico en todas las plataformas.
#!/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 bitrise.yml. Establece las variables del flujo anteriores y elige Start build → web después de desplegar la previsualización. El paso de clonación se ejecuta en Bitrise; la CLI local usa el repositorio que ya has clonado.
format_version: '13'
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
workflows:
web:
meta:
bitrise.io:
stack: linux-docker-android-22.04
machine_type_id: standard
steps:
- activate-ssh-key@4:
run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
- git-clone@8:
run_if: '{{getenv "BITRISE_IO" | eq "true"}}'
- script@1:
title: Autonomy
inputs:
- content: |-
#!/usr/bin/env bash
set -euo pipefail
set +x
: "${PREVIEW_URL:?Set the deployed preview URL}"
curl --fail --silent --show-error --retry 12 \
--retry-delay 5 --retry-connrefused --max-time 20 \
"$PREVIEW_URL" > /dev/null
attempt="$(cat /proc/sys/kernel/random/uuid 2>/dev/null || uuidgen)"
export AUTONOMY_REQUEST_ID="bitrise:${BITRISE_BUILD_SLUG:-local}:${BITRISE_TRIGGERED_WORKFLOW_ID}:$attempt"
export AUTONOMY_BRANCH="${BITRISE_GIT_BRANCH:-$(git branch --show-current)}"
export AUTONOMY_COMMIT_SHA="$(git rev-parse HEAD)"
bash .ci/autonomy.sh webPara usar el runner local, instala la CLI de Bitrise y guarda lo siguiente como .bitrise.secrets.yml junto a bitrise.yml. Sustituye los cuatro valores de ejemplo por tu clave de API, URL del despliegue, ID del plan y URL de previsualización accesible:
envs:
- AUTONOMY_API_KEY: 'aut_REPLACE_WITH_ORG_KEY'
opts:
is_expand: false
- AUTONOMY_API_URL: 'https://your-deployment.convex.site'
opts:
is_expand: false
- AUTONOMY_TEST_PLAN_ID: 'REPLACE_WITH_TEST_PLANS_ID'
opts:
is_expand: false
- PREVIEW_URL: 'https://your-preview.example.com'
opts:
is_expand: falseEjecuta estos comandos desde la raíz del repositorio. Excluye el archivo de secretos del control de versiones. La CLI local se ejecuta en tu equipo; la selección del stack en meta solo se aplica a los builds alojados.
printf '\n.bitrise*\n' >> .gitignore
chmod 600 .bitrise.secrets.yml
bitrise setup
bitrise run webTransferencia de artefactos móviles
Usa el mismo .ci/autonomy.sh anterior. Solicita una URL de subida, envía el binario mediante PUT, exige un análisis limpio y dispara la ejecución con el ID de almacenamiento recibido. El build y la subida comparten el directorio de trabajo; no necesitas configurar transferencias de artefactos entre flujos.
iOS
Esta alternativa completa de bitrise.yml usa un stack de Xcode en macOS. Establece AUTONOMY_TEST_PLAN_ID con tu plan de iOS y APP_IDENTIFIER con su ID de bundle. Sustituye ios/MyApp.xcodeproj, MyApp y el nombre del .app resultante por tu proyecto, esquema compartido y nombre de producto. Si tu app usa un workspace, sustituye -project ios/MyApp.xcodeproj por -workspace ios/MyApp.xcworkspace. Conserva los pasos existentes de instalación de dependencias antes de xcodebuild.
Construye un .app para Simulator y comprímelo en ZIP; aquí no sirve un .ipa para dispositivos. La subida y la espera del veredicto también se ejecutan en macOS y consumen tiempo de build.
format_version: '13'
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
workflows:
ios:
meta:
bitrise.io:
stack: osx-xcode-26.4.x
machine_type_id: g2.mac.medium
steps:
- activate-ssh-key@4:
run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
- git-clone@8:
run_if: '{{getenv "BITRISE_IO" | eq "true"}}'
- script@1:
title: Autonomy
inputs:
- content: |-
#!/usr/bin/env bash
set -euo pipefail
set +x
xcodebuild -project ios/MyApp.xcodeproj -scheme MyApp \
-configuration Release -sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath .build/ios CODE_SIGNING_ALLOWED=NO build
mkdir -p .build/artifacts
ditto -c -k --sequesterRsrc --keepParent \
.build/ios/Build/Products/Release-iphonesimulator/MyApp.app \
.build/artifacts/MyApp.app.zip
export ARTIFACT_PATH="$PWD/.build/artifacts/MyApp.app.zip"
attempt="$(cat /proc/sys/kernel/random/uuid 2>/dev/null || uuidgen)"
export AUTONOMY_REQUEST_ID="bitrise:${BITRISE_BUILD_SLUG:-local}:${BITRISE_TRIGGERED_WORKFLOW_ID}:$attempt"
export AUTONOMY_BRANCH="${BITRISE_GIT_BRANCH:-$(git branch --show-current)}"
export AUTONOMY_COMMIT_SHA="$(git rev-parse HEAD)"
bash .ci/autonomy.sh iosAndroid
Esta alternativa completa de bitrise.yml usa el stack de Android en Linux. Establece AUTONOMY_TEST_PLAN_ID con tu plan de Android y APP_IDENTIFIER con su ID de aplicación. Se presupone un proyecto Android en android/, un wrapper de Gradle incluido en el repositorio y el módulo app. Adapta conjuntamente el directorio, la tarea y la ruta del APK si usas otro módulo o variante de build. Conserva las versiones de JDK y Android SDK que requiere tu build actual.
format_version: '13'
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
workflows:
android:
meta:
bitrise.io:
stack: linux-docker-android-22.04
machine_type_id: standard
steps:
- activate-ssh-key@4:
run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
- git-clone@8:
run_if: '{{getenv "BITRISE_IO" | eq "true"}}'
- script@1:
title: Autonomy
inputs:
- content: |-
#!/usr/bin/env bash
set -euo pipefail
set +x
(cd android && bash ./gradlew --no-daemon assembleDebug)
export ARTIFACT_PATH="$PWD/android/app/build/outputs/apk/debug/app-debug.apk"
attempt="$(cat /proc/sys/kernel/random/uuid 2>/dev/null || uuidgen)"
export AUTONOMY_REQUEST_ID="bitrise:${BITRISE_BUILD_SLUG:-local}:${BITRISE_TRIGGERED_WORKFLOW_ID}:$attempt"
export AUTONOMY_BRANCH="${BITRISE_GIT_BRANCH:-$(git branch --show-current)}"
export AUTONOMY_COMMIT_SHA="$(git rev-parse HEAD)"
bash .ci/autonomy.sh androidBitrise incluye actualmente macOS Medium y Linux Medium en su plan gratuito Hobby, con 300 créditos al mes y un límite de 90 minutos por build. Los ejemplos seleccionan g2.mac.medium y standard, respectivamente. Un bitrise run ios local sigue necesitando tu propio Mac con Xcode; seleccionar un stack de macOS en YAML no crea un Mac remoto. Revisa los créditos disponibles antes de los builds móviles alojados. Consulta los precios de Bitrise.
Condicionar el pipeline al veredicto
El script muestra cada ID de ejecución en cola y consulta POST /api/v1/run.get. Una respuesta en cola solo confirma el envío. El flujo termina correctamente únicamente cuando todas las ejecuciones tienen verdict: "passed" y validity: "valid". Un resultado fallido, sin verificar, inválido, cancelado, desconocido, con tiempo agotado o con error HTTP hace fallar el paso Script y detiene los pasos normales posteriores. No añadas is_skippable: true a este paso.
La espera predeterminada es de 20 minutos; aumenta AUTONOMY_WAIT_SECONDS dentro del límite de Bitrise si tu plan lo necesita. Agotar la espera no cancela la ejecución de Autonomy. Abre la ejecución en Runs con el ID mostrado para ver sus evidencias. Cada invocación crea un UUID nuevo junto al slug del build y el ID del flujo, por lo que cada reintento o invocación local pone en cola una ejecución nueva.
Estrategia de ramas y eventos
Los ejemplos son flujos manuales sin disparadores automáticos, para que la configuración no exponga una clave de API a código no confiable. Empieza con un plan de smoke reducido y configura después un disparador de push para una rama de staging o de versión confiable en Bitrise. Añade el paso de Autonomy después del despliegue de ese flujo, conservando sus filtros de rama. Reserva los planes más grandes para ejecuciones programadas o manuales.
Mantén los secretos inaccesibles en builds de pull requests, incluidas las procedentes de forks. Ejecuta QA sobre código revisado cuando llegue a una rama confiable o inicia manualmente un build de un commit revisado. No habilites la exposición de secretos a pull requests para conseguir que la receta funcione. Se envían a Autonomy los metadatos de rama y commit; esta receta no crea comentarios en pull requests.