Bitrise
Inicia ejecuciones de Autonomy desde un workflow de Bitrise para una previsualización web o un APK de Android, y haz fallar el build salvo que todas las ejecuciones se superen.
Usa un Script Step de Bitrise para subir un build móvil o probar una previsualización web desplegada, y mantén el workflow abierto hasta que todas las ejecuciones de Autonomy tengan resultado. El step solo se supera cuando todas las ejecuciones son Passed.
Dónde va en el workflow
Añade el step de Autonomy después de tus steps de build y de despliegue existentes. Para web, exporta la URL pública de previsualización definitiva como PREVIEW_URL desde el step de despliegue con envman add --key PREVIEW_URL --value "$PREVIEW_URL"; los steps posteriores pueden leerla. Para móvil, mantén el build y la subida en el mismo workflow para que el build siga en el workspace.
Las configuraciones de abajo son alternativas completas para bitrise.yml. Copia la de tu plataforma o combina sus steps con tu workflow existente. Configura Bitrise para que lea bitrise.yml del repositorio y haz commit de .ci/autonomy.sh a su lado. El workflow web también puede ejecutarse en local en un repositorio descargado.
Secretos necesarios
Antes de la primera ejecución
- Crea una clave de API de la organización que empiece por aut_ en Organization → API keys. Los propietarios y administradores pueden crear claves.
- Crea un plan de pruebas en Test plans con al menos un caso de prueba para la plataforma y copia su ID.
- En esta receta sin entorno, usa casos de prueba que no usen valores del entorno, o define AUTONOMY_ENVIRONMENT_SLUG.
- Haz que la URL de previsualización sea accesible desde internet.
En Workflows → Secrets, añade AUTONOMY_API_KEY. Deja Expose for pull requests desactivado y Replace variables in inputs sin marcar. Los secretos se convierten automáticamente en variables de entorno de la shell; no pongas la clave en bitrise.yml.
En Workflows → Env Vars, define estos valores para el workflow:
| Variable | Valor |
|---|---|
AUTONOMY_TEST_PLAN_ID | El plan de pruebas que ejecutar: la última parte de /p/<project>/plans/<id> en Test plans. Usa un plan distinto para cada plataforma. Para ejecutar un solo caso de prueba, define AUTONOMY_TEST_CASE_ID (de /p/<project>/tests/<id>) y deja esta sin definir. |
PREVIEW_URL | Solo web: la URL desplegada definitiva, sin página de inicio de sesión ni de protección de la previsualización. También puede definirla un step de despliegue. |
APP_IDENTIFIER | Solo móvil: el bundle ID de iOS o el application ID de Android del build. |
AUTONOMY_ENVIRONMENT_SLUG | Opcional: ejecuta contra un entorno guardado del mismo proyecto, con sus objetivos y valores, en lugar de la URL o la app de este build. En ese caso el script omite la subida. |
AUTONOMY_WAIT_SECONDS | Opcional: el tiempo de espera total en segundos, 1200 por defecto. |
Sin un entorno, una ejecución no tiene valores del entorno: un paso que usa {{env.NAME}} termina como Couldn't start.
URL de previsualización web
Crea una carpeta .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 de abajo los incluyen. Para una ejecución local con la CLI, instálalos tú. Mantén este archivo igual para todas las plataformas.
#!/usr/bin/env bash
# Usage: bash .ci/autonomy.sh web|ios|android
# Starts Autonomy runs for this CI job and exits 0 only if every run passed.
set -euo pipefail
set +x
: "${AUTONOMY_API_KEY:?Set an aut_ organization API key}"
: "${AUTONOMY_REQUEST_ID:?Set an ID that is unique for this CI job attempt}"
platform="${1:?Usage: bash .ci/autonomy.sh web|ios|android}"
api="${AUTONOMY_API_URL:-https://api.autonomyqa.com}"
api="${api%/}"
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"
}
# 1. What to run: a test plan or one test case.
if [ -n "${AUTONOMY_TEST_PLAN_ID:-}" ] && [ -z "${AUTONOMY_TEST_CASE_ID:-}" ]; then
what=$(jq -n --arg id "$AUTONOMY_TEST_PLAN_ID" '{testPlanId:$id}')
elif [ -n "${AUTONOMY_TEST_CASE_ID:-}" ] && [ -z "${AUTONOMY_TEST_PLAN_ID:-}" ]; then
what=$(jq -n --arg id "$AUTONOMY_TEST_CASE_ID" '{testCaseId:$id}')
else
echo 'Set exactly one of AUTONOMY_TEST_PLAN_ID or AUTONOMY_TEST_CASE_ID.' >&2
exit 2
fi
# 2. Where to run: a saved environment, or this job's preview URL or build.
if [ -n "${AUTONOMY_ENVIRONMENT_SLUG:-}" ]; then
where=$(jq -n --arg slug "$AUTONOMY_ENVIRONMENT_SLUG" '{environmentSlug:$slug}')
else
case "$platform" in
web)
: "${PREVIEW_URL:?Set PREVIEW_URL, or AUTONOMY_ENVIRONMENT_SLUG}"
where=$(jq -n --arg url "$PREVIEW_URL" '{targets:{web:{baseUrl:$url}}}')
;;
ios|android)
: "${ARTIFACT_PATH:?Set the path to the zipped .app, .apk or .aab}"
: "${APP_IDENTIFIER:?Set the iOS bundle ID or Android package name}"
file=$(basename "$ARTIFACT_PATH")
bytes=$(wc -c < "$ARTIFACT_PATH" | tr -d '[:space:]')
if [ "$platform" = ios ]; then
type=application/zip
else
type=application/vnd.android.package-archive
fi
upload=$(post /api/artifacts/upload-url "$(jq -n \
--arg platform "$platform" --arg fileName "$file" \
--arg contentType "$type" --argjson declaredBytes "$bytes" \
'{platform:$platform,fileName:$fileName,contentType:$contentType,declaredBytes:$declaredBytes}')")
storage=$(jq -er '.storageId' <<< "$upload")
intent=$(jq -er '.intentId' <<< "$upload")
curl --fail-with-body --silent --show-error \
--connect-timeout 15 --max-time 600 \
-X PUT "$(jq -er '.uploadUrl' <<< "$upload")" \
-H "Content-Type: $type" --data-binary "@$ARTIFACT_PATH"
scan=$(post /api/artifacts/scan "$(jq -n \
--arg storageId "$storage" --arg intentId "$intent" \
'{storageId:$storageId,intentId:$intentId}')")
if [ "$(jq -r '.status' <<< "$scan")" != clean ]; then
echo 'The build did not pass the safety check, so no run was started:' >&2
jq -r '.findings[]?.message' <<< "$scan" >&2
exit 1
fi
where=$(jq -n --arg p "$platform" --arg storageId "$storage" \
--arg fileName "$file" --arg id "$APP_IDENTIFIER" \
'{targets:{($p):({storageId:$storageId,sourceMode:"upload",fileName:$fileName}
+ (if $p == "ios" then {bundleId:$id} else {packageName:$id} end))}}')
;;
*) echo 'Usage: bash .ci/autonomy.sh web|ios|android' >&2; exit 2 ;;
esac
fi
# 3. Start the runs. A plan starts one run per test case.
# The request ID's prefix (github, gitlab, ...) names the CI provider.
body=$(jq -n --argjson what "$what" --argjson where "$where" \
--arg platform "$platform" \
--arg branch "${AUTONOMY_BRANCH:-}" --arg pr "${AUTONOMY_PR:-}" \
--arg commitSha "${AUTONOMY_COMMIT_SHA:-}" \
--arg provider "${AUTONOMY_REQUEST_ID%%:*}" \
--arg key "$AUTONOMY_REQUEST_ID:$platform" \
'$what + $where + ({
platforms: [$platform],
branch: $branch,
pr: $pr,
deployment: ({provider: $provider, branch: $branch, commitSha: $commitSha}
| with_entries(select(.value != ""))),
idempotencyKey: $key
} | with_entries(select(.value != "")))')
run_ids=$(post /api/v1/run.trigger "$body" | jq -er '.runIds[]')
printf 'Started Autonomy runs:\n%s\n' "$run_ids"
# 4. Follow each run until it ends. run.get waits up to 25 s for a change;
# sending the last cursor back makes each call wait for something new.
deadline=$((SECONDS + ${AUTONOMY_WAIT_SECONDS:-1200}))
all_passed=true
for run_id in $run_ids; do
cursor=null
while :; do
left=$((deadline - SECONDS))
if [ "$left" -le 0 ]; then
echo "Stopped waiting for run $run_id after AUTONOMY_WAIT_SECONDS. It keeps going in Autonomy." >&2
exit 1
fi
wait_ms=$(( left < 25 ? left * 1000 : 25000 ))
run=$(post /api/v1/run.get "$(jq -n --arg runId "$run_id" \
--argjson cursor "$cursor" --argjson waitMs "$wait_ms" \
'{runId:$runId,cursor:$cursor,waitMs:$waitMs}')")
cursor=$(jq '.cursor' <<< "$run")
status=$(jq -r '.status' <<< "$run")
[ "$status" = queued ] || [ "$status" = running ] || break
done
name="$(jq -r '.testCaseName' <<< "$run") ($run_id)"
case "$status" in
passed)
echo "Passed: $name" ;;
failed)
echo "Failed: $name. Open the run in Autonomy to see which step failed." >&2
all_passed=false ;;
couldnt_start)
echo "Couldn't start: $name. The environment couldn't be tested, so this says nothing about your app. Open the run for the reason, fix it and run again." >&2
all_passed=false ;;
cancelled)
echo "Cancelled: $name." >&2
all_passed=false ;;
*)
echo "Unexpected status $status: $name." >&2
all_passed=false ;;
esac
done
if [ "$all_passed" != true ]; then
echo 'Not every Autonomy run passed.' >&2
exit 1
fi
echo 'Every Autonomy run passed.'Guarda esta configuración como bitrise.yml. Define las variables del workflow de arriba y, después de desplegar la previsualización, elige Start build → web. El step de checkout se ejecuta en Bitrise; la CLI local usa el repositorio que ya descargaste.
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 ejecutarlo en local, instala la CLI de Bitrise y guarda esto como .bitrise.secrets.yml junto a bitrise.yml. Sustituye los tres valores de ejemplo por tu clave de API, el ID del plan de pruebas y la URL de previsualización:
envs:
- AUTONOMY_API_KEY: 'aut_REPLACE_WITH_ORG_KEY'
opts:
is_expand: false
- AUTONOMY_TEST_PLAN_ID: 'REPLACE_WITH_TEST_PLAN_ID'
opts:
is_expand: false
- PREVIEW_URL: 'https://your-preview.example.com'
opts:
is_expand: falseEjecuta estos comandos desde la raíz del repositorio. Mantén el archivo de secretos fuera del control de versiones. La CLI local se ejecuta en tu máquina; el stack de meta solo se aplica a los builds alojados.
printf '\n.bitrise*\n' >> .gitignore
chmod 600 .bitrise.secrets.yml
bitrise setup
bitrise run webEntrega de builds móviles
Usa el mismo .ci/autonomy.sh. Para iOS y Android pide una URL de subida, envía el build con PUT, espera a que el control de seguridad salga limpio e inicia las ejecuciones con el build subido. El build y la subida comparten el workspace, así que no hay que configurar ninguna transferencia de artifacts.
iOS
Las pruebas en iOS llegarán pronto. Guarda esto para cuando estén disponibles. Hasta entonces, Autonomy no inicia ejecuciones en iOS.
Este bitrise.yml alternativo completo usa un stack de macOS con Xcode. Define AUTONOMY_TEST_PLAN_ID con tu plan de iOS y APP_IDENTIFIER con su bundle ID. Sustituye ios/MyApp.xcodeproj, MyApp y el nombre del .app por tu proyecto, tu scheme compartido y tu producto. Para un workspace, sustituye -project ios/MyApp.xcodeproj por -workspace ios/MyApp.xcworkspace. Conserva los steps de instalación de dependencias antes de xcodebuild.
Compila un .app de simulador y comprímelo en zip; no se puede usar un .ipa de dispositivo. La subida y la espera también se ejecutan en macOS y consumen su 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
Este bitrise.yml alternativo completo usa el stack de Android en Linux. Define AUTONOMY_TEST_PLAN_ID con tu plan de Android y APP_IDENTIFIER con su application ID. Da por hecho un proyecto Android en android/, un wrapper de Gradle en el repositorio y el módulo app. Cambia a la vez la carpeta, la tarea y la ruta del APK para otro módulo u otra variante de build. Conserva las versiones del JDK y del SDK de Android que necesita tu build. Un .aab también funciona.
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 ofrece 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. Un bitrise run ios local sigue necesitando tu propio Mac con Xcode; elegir un stack de macOS en el YAML no crea un Mac remoto. Comprueba los créditos que te quedan antes de lanzar builds móviles alojados. Consulta los precios de Bitrise.
Condicionar el pipeline al resultado
El script inicia las ejecuciones con POST /api/v1/run.trigger e imprime sus IDs. Un plan de pruebas inicia una ejecución por cada caso de prueba. Después sigue cada ejecución con POST /api/v1/run.get, devolviendo el último cursor con waitMs: 25000, de modo que cada llamada espera hasta que la ejecución cambia. Una respuesta con timedOut: true solo significa que todavía no ha cambiado nada. Consulta Ejecuciones y evidencia.
| Resultado de la ejecución | El job | Qué dice el log |
|---|---|---|
| Passed | Se supera, si todas las demás ejecuciones también se superaron. Una ejecución superada con reintento (flaky) cuenta como superada. | Passed |
| Failed | Falla. | Abre la ejecución para ver qué paso falló y por qué, incluido un Runner problem. |
| Couldn't start | Falla. | No se pudo probar el entorno, por ejemplo porque el build no se instaló o faltaba un valor. Esto no dice nada de tu app; corrige la causa y vuelve a ejecutar. |
| Cancelled | Falla. | Cancelled |
Los errores de la API, un build que no supera el control de seguridad y agotar el tiempo de espera también hacen fallar el job. AUTONOMY_WAIT_SECONDS es el tiempo de espera total para todas las ejecuciones, 1.200 segundos por defecto. Mantén el límite de tiempo del job de CI por encima de ese valor más el tiempo de build y de subida. Detener el job de CI no cancela las ejecuciones que ya empezaron.
AUTONOMY_REQUEST_ID, con la plataforma añadida, se convierte en el idempotencyKey de run.trigger: si el mismo intento del job vuelve a enviar la petición, recibe las mismas ejecuciones en lugar de otras nuevas. Da a cada intento del job su propio ID. La parte anterior a los primeros dos puntos se envía como proveedor del despliegue, y la rama y el commit acompañan a las ejecuciones. Los formatos completos de petición y respuesta están en Operaciones.
Una salida distinta de cero hace fallar el Script Step y detiene los steps normales posteriores. No le añadas is_skippable: true. Cada inicio del workflow genera un UUID nuevo junto al slug del build y el ID del workflow, así que un reintento o una ejecución local inician ejecuciones nuevas. Abre una ejecución en Runs del proyecto con el ID impreso para ver su evidencia.
Estrategia de ramas y eventos
Los ejemplos son workflows manuales sin disparador automático, así que configurarlos no expone una clave de API a código que no sea de confianza. Empieza con un plan de smoke pequeño y después configura en Bitrise un disparador por push para una rama de staging o de release de confianza. Añade el step de Autonomy después del despliegue en ese workflow y conserva sus filtros de rama. Deja los planes más amplios para ejecuciones programadas o manuales.
Mantén los secretos lejos de los builds de pull requests, incluidas las de forks. Ejecuta las pruebas sobre código revisado cuando llegue a una rama de confianza, o lanza a mano un build de un commit revisado. No actives la exposición de secretos en pull requests para que una receta funcione. La rama y el commit se envían a Autonomy; esta receta no publica ningún comentario en la pull request.
Referencias del proveedor
¿No lo encontraste?
Jenkins
Inicia ejecuciones de Autonomy desde Jenkins para una URL de previsualización o un build móvil, y haz fallar el build salvo que todas las ejecuciones se superen.
CircleCI
Inicia ejecuciones de Autonomy desde CircleCI para una URL de previsualización web o un build móvil, y haz fallar el pipeline salvo que todas las ejecuciones se superen.