Docs Autonomy
Intégrations

GitHub Actions

Lancez des exécutions Autonomy depuis un workflow GitHub Actions pour une prévisualisation web ou un APK Android, et faites échouer le workflow si une exécution ne réussit pas.

Utilisez GitHub Actions quand vous voulez qu'Autonomy soit une étape de votre propre workflow : après un script de déploiement personnalisé, pour un build mobile ou avant un job de release. Le workflow lance les exécutions, attend leurs résultats et échoue si une exécution n'est pas Passed.

Pour exécuter un plan de test sur chaque pull request sans fichier de workflow, utilisez plutôt l'application GitHub. Elle exécute le plan de pull request du projet sur le déploiement de prévisualisation et publie un check GitHub. Voir Tests de pull request.

Placement du workflow

Placez l'étape Autonomy après le job qui déploie la prévisualisation ou construit l'application. L'exécution doit recevoir l'URL finale qu'un relecteur ouvrirait, ou le fichier de build lui-même. L'exemple web ci-dessous prend une URL déjà déployée ; il ne déploie pas votre application.

Chaque workflow ci-dessous est un fichier complet. Pour l'ajouter à un workflow existant, conservez vos jobs de build et de déploiement, et faites pointer needs vers le job qui produit l'URL ou le build.

Secrets requis

Dans Settings → Secrets and variables → Actions du dépôt, ajoutez :

NomTypeValeur
AUTONOMY_API_KEYSecretUne clé API d'organisation commençant par aut_. Les propriétaires et les administrateurs créent les clés dans Organization → API keys.
AUTONOMY_TEST_PLAN_IDVariableLe plan de test à exécuter. Ouvrez-le dans Test plans du projet : l'identifiant est la dernière partie de l'URL de la page, /p/<project>/plans/<id>.
PREVIEW_URLVariableWeb uniquement : une URL HTTPS déployée qu'Autonomy peut atteindre depuis Internet, pas localhost.
AUTONOMY_IOS_BUNDLE_IDVariableiOS uniquement : le bundle ID de l'application construite.
AUTONOMY_ANDROID_PACKAGE_NAMEVariableAndroid uniquement : l'application ID de l'APK construit.

Valeurs facultatives lues par le script :

  • AUTONOMY_TEST_CASE_ID : exécuter un seul cas de test au lieu d'un plan. Son identifiant est la dernière partie de /p/<project>/tests/<id>. Définissez exactement l'une des deux variables AUTONOMY_TEST_CASE_ID et AUTONOMY_TEST_PLAN_ID.
  • AUTONOMY_ENVIRONMENT_SLUG : exécuter sur un environnement enregistré du même projet, avec ses cibles et ses valeurs d'environnement, au lieu de l'URL ou du build de ce job. Le script saute alors le téléversement.
  • AUTONOMY_WAIT_SECONDS : le temps d'attente total pour toutes les exécutions, 1 200 secondes par défaut.

Sans environnement, une exécution n'a pas de valeurs d'environnement : une étape qui utilise {{env.NAME}} se termine en Couldn't start. Définissez AUTONOMY_ENVIRONMENT_SLUG, ou utilisez des cas de test qui n'ont pas besoin de valeurs d'environnement. Utilisez un plan de test distinct pour chaque plateforme, afin qu'un résultat désigne la bonne application.

URL de prévisualisation web

Créez un dossier .ci à la racine du dépôt et enregistrez ce script sous .ci/autonomy.sh. Tous les workflows de cette page, ainsi que les recettes GitLab, Jenkins, Bitrise et CircleCI, utilisent ce même fichier. Il nécessite Bash, jq et curl 7.76 ou ultérieur ; les runners hébergés par GitHub en disposent.

.ci/autonomy.sh
#!/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.'

Enregistrez ceci sous .github/workflows/autonomy-web.yml. Lancez-le depuis Actions → Autonomy web → Run workflow, éventuellement avec une URL de prévisualisation.

.github/workflows/autonomy-web.yml
name: Autonomy web

on:
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      preview_url:
        description: Preview URL to test
        required: false

jobs:
  autonomy:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v5
      - name: Run Autonomy
        env:
          AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
          AUTONOMY_TEST_PLAN_ID: ${{ vars.AUTONOMY_TEST_PLAN_ID }}
          PREVIEW_URL: ${{ inputs.preview_url || vars.PREVIEW_URL }}
          AUTONOMY_REQUEST_ID: github-actions:${{ github.run_id }}:${{ github.run_attempt }}
          AUTONOMY_BRANCH: ${{ github.head_ref || github.ref_name }}
          AUTONOMY_COMMIT_SHA: ${{ github.sha }}
        run: bash .ci/autonomy.sh web

Si un job précédent déploie la prévisualisation, exposez son URL comme sortie de job, ajoutez ce job à needs et définissez PREVIEW_URL: ${{ needs.deploy.outputs.url }}.

Transmission d'un build mobile

Utilisez le même .ci/autonomy.sh. Pour iOS et Android, il demande une URL de téléversement, téléverse le build, attend que le contrôle de sécurité revienne sans anomalie, puis lance les exécutions avec le build téléversé.

iOS

Les tests iOS arrivent bientôt. Conservez cette section pour le moment où ils seront disponibles. D'ici là, Autonomy ne lance pas d'exécutions sur iOS.

Construisez le .app de simulateur sur macOS, compressez-le sur place pour conserver les permissions et les liens symboliques, et transmettez le zip à un job Linux sous forme d'artefact Actions. Le téléversement et l'attente consomment alors des minutes Linux. Remplacez MyApp et le chemin du workspace par les vôtres ; pour un projet sans workspace, utilisez -project ios/MyApp.xcodeproj. Construisez pour le simulateur, pas un .ipa pour appareil physique.

.github/workflows/autonomy-ios.yml
name: Autonomy iOS

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    runs-on: macos-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v5
      - name: Build and zip the simulator app
        run: |
          set -euo pipefail
          xcodebuild \
            -workspace ios/MyApp.xcworkspace \
            -scheme MyApp \
            -configuration Release \
            -sdk iphonesimulator \
            -destination 'generic/platform=iOS Simulator' \
            -derivedDataPath ios/build \
            CODE_SIGNING_ALLOWED=NO \
            build
          mkdir -p .build
          (cd ios/build/Build/Products/Release-iphonesimulator && \
            zip -qry "$GITHUB_WORKSPACE/.build/MyApp.app.zip" MyApp.app)
      - uses: actions/upload-artifact@v5
        with:
          name: ios-simulator-app
          path: .build/MyApp.app.zip
          retention-days: 1

  autonomy:
    needs: build
    runs-on: ubuntu-latest
    timeout-minutes: 35
    steps:
      - uses: actions/checkout@v5
      - uses: actions/download-artifact@v5
        with:
          name: ios-simulator-app
          path: .build
      - name: Run Autonomy
        env:
          AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
          AUTONOMY_TEST_PLAN_ID: ${{ vars.AUTONOMY_TEST_PLAN_ID }}
          APP_IDENTIFIER: ${{ vars.AUTONOMY_IOS_BUNDLE_ID }}
          ARTIFACT_PATH: .build/MyApp.app.zip
          AUTONOMY_REQUEST_ID: github-actions:${{ github.run_id }}:${{ github.run_attempt }}
          AUTONOMY_BRANCH: ${{ github.ref_name }}
          AUTONOMY_COMMIT_SHA: ${{ github.sha }}
        run: bash .ci/autonomy.sh ios

Android

Les builds Android tournent sous Linux : le build et le téléversement tiennent donc dans un seul job. Si vous utilisez un autre module ou une autre variante de build, ajustez ensemble la tâche Gradle et le chemin de l'APK. Un .aab fonctionne aussi.

.github/workflows/autonomy-android.yml
name: Autonomy Android

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  autonomy:
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '17'
      - name: Build the debug APK
        run: |
          set -euo pipefail
          cd android
          ./gradlew --no-daemon assembleDebug
      - name: Run Autonomy
        env:
          AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
          AUTONOMY_TEST_PLAN_ID: ${{ vars.AUTONOMY_TEST_PLAN_ID }}
          APP_IDENTIFIER: ${{ vars.AUTONOMY_ANDROID_PACKAGE_NAME }}
          ARTIFACT_PATH: android/app/build/outputs/apk/debug/app-debug.apk
          AUTONOMY_REQUEST_ID: github-actions:${{ github.run_id }}:${{ github.run_attempt }}
          AUTONOMY_BRANCH: ${{ github.ref_name }}
          AUTONOMY_COMMIT_SHA: ${{ github.sha }}
        run: bash .ci/autonomy.sh android

Si le build se trouve déjà derrière un lien HTTPS de courte durée, vous pouvez sauter le téléversement : appelez run.trigger avec targets.ios.artifactUrl ou targets.android.artifactUrl et sourceMode: "url". Voir Builds mobiles.

Conditionner le pipeline au résultat

Le script lance les exécutions avec POST /api/v1/run.trigger et affiche leurs identifiants. Un plan de test lance une exécution par cas de test. Le script suit ensuite chaque exécution avec POST /api/v1/run.get, en renvoyant le dernier cursor avec waitMs: 25000, si bien que chaque appel attend que l'exécution évolue. Une réponse avec timedOut: true signifie seulement que rien n'a encore changé. Voir Exécutions et preuves.

Résultat de l'exécutionLe jobCe qu'indique le log
PassedRéussit, si toutes les autres exécutions ont aussi réussi. Une réussite flaky compte comme une réussite.Passed
FailedÉchoue.Ouvrez l'exécution pour voir quelle étape a échoué et pourquoi, y compris un Runner problem.
Couldn't startÉchoue.L'environnement n'a pas pu être testé, par exemple parce que le build ne s'est pas installé ou qu'une valeur manquait. Cela ne dit rien de votre application ; corrigez la cause et relancez.
CancelledÉchoue.Cancelled

Les erreurs d'API, un build qui ne passe pas le contrôle de sécurité et l'épuisement du temps d'attente font aussi échouer le job. AUTONOMY_WAIT_SECONDS est le temps d'attente total pour toutes les exécutions, 1 200 secondes par défaut. Donnez au job de CI une limite de temps supérieure à cette valeur, augmentée du temps de build et de téléversement. Arrêter le job de CI n'annule pas les exécutions déjà lancées.

AUTONOMY_REQUEST_ID, complété par la plateforme, devient l'idempotencyKey de run.trigger : si la même tentative de job renvoie la requête, elle récupère les mêmes exécutions au lieu d'en créer de nouvelles. Donnez à chaque tentative de job son propre identifiant. La partie située avant le premier deux-points est envoyée comme fournisseur de déploiement, et la branche et le commit accompagnent les exécutions. Les formats complets de requête et de réponse figurent dans Opérations.

Stratégie de branches et d'événements

Ces workflows s'exécutent lors des pushs sur main et quand ils sont lancés à la main. Exécutez de courts plans de smoke test sur les pushs ordinaires, et des plans plus larges sur les branches de release, selon une planification ou à la main. Si un plan sollicite des services payants ou des données de test rares, lancez-le à la main.

GitHub ne transmet pas les secrets aux workflows des pull requests issues de forks : ces workflows ne peuvent donc pas s'exécuter pour elles. Pour une exécution sur chaque pull request, sur son déploiement de prévisualisation, utilisez l'application GitHub : voir Tests de pull request.

Dépannage

L'exécution web démarre avant que la prévisualisation soit prête

Séparez le déploiement et les tests en jobs distincts, et transmettez l'URL de déploiement via une sortie de job. Ne lancez Autonomy qu'une fois l'URL connue et répondant.

Le téléversement est refusé

Le script affiche les raisons données par le contrôle de sécurité. Pour iOS, vérifiez que le build a utilisé -sdk iphonesimulator et une destination de simulateur : un .ipa pour appareil physique ne peut pas s'exécuter sur un simulateur. Pour Android, téléversez un .apk ou un .aab.

Les étapes qui utilisent des valeurs d'environnement n'ont pas pu démarrer

Une exécution avec une URL ou un build explicite n'a pas d'environnement. Définissez AUTONOMY_ENVIRONMENT_SLUG sur un environnement enregistré, ou retirez les références {{env.NAME}} de ces cas de test.

Le build Android ne trouve pas le SDK

Les runners Ubuntu hébergés par GitHub incluent le SDK Android. Sur un runner auto-hébergé, installez les outils en ligne de commande avant l'étape Gradle.

Vous n’avez pas trouvé ?

On this page