GitLab CI
Exécutez Autonomy depuis GitLab CI avec une URL de prévisualisation, une app iOS Simulator ou un APK Android et conditionnez le pipeline au verdict.
Déclenchez Autonomy après un déploiement ou un build mobile, puis gardez le job GitLab ouvert jusqu'à ce que chaque cas de test sélectionné obtienne un verdict valide et réussi. Copiez le script partagé et la configuration de la plateforme que vous livrez.
Placement du workflow
Placez Autonomy après le job de déploiement qui obtient l'URL de prévisualisation définitive, ou après le job qui construit l'artefact mobile. L'exemple web ci-dessous accepte une URL déjà déployée et vérifie qu'elle répond. Il ne déploie pas votre application.
Chaque exemple YAML est une alternative complète de .gitlab-ci.yml. Pour l'ajouter à un pipeline existant, conservez vos jobs de build et de déploiement, fusionnez les étapes et dirigez needs vers le job qui produit l'URL ou l'artefact. Exécutez uniquement du code de confiance sur une branche par défaut protégée.
Secrets requis
Dans Settings → CI/CD → Variables, ajoutez ces valeurs avec le type Variable, et non File, et la portée d'environnement *. Protégez les variables et désactivez l'expansion des références de variables. Marquez la clé API Masked and hidden. Protégez la branche par défaut avant d'exécuter les exemples.
-
AUTONOMY_API_KEY: une clé API d'organisation commençant paraut_, créée dans Settings → API Keys d'Autonomy. Elle doit appartenir à l'organisation contenant le plan. Les clés d'organisation incluent actuellement toutes les portées de l'API. -
AUTONOMY_API_URL: copiezCONVEX_SITE_URLouNEXT_PUBLIC_CONVEX_SITE_URLdu déploiement correspondant à votre clé API. Utilisez son URL HTTP Convex exacte, en conservant toute région dans le nom d'hôte, sans/apini chemin final. N'utilisez pas l'URL du tableau de bord ou.convex.cloud. Une clé de développement nécessite l'URL de son déploiement de développement. -
AUTONOMY_TEST_PLAN_ID: l'ID d'un véritable plan dans Test Plans, contenant au moins un cas de test web. Copiez l'ID depuis l'URL du plan. Un ID de Test Cases n'est pas interchangeable avec un ID de plan. -
PREVIEW_URL: l'URL HTTPS de prévisualisation prête pour l'exemple web. Elle doit être accessible depuis le runner Autonomy, et non êtrelocalhostou un service accessible uniquement dans le job CI. - Pour iOS, ajoutez
AUTONOMY_IOS_TEST_PLAN_IDetAUTONOMY_IOS_BUNDLE_ID. Pour Android, ajoutezAUTONOMY_ANDROID_TEST_PLAN_IDetAUTONOMY_ANDROID_PACKAGE_NAME. Chaque plan doit contenir des cas de cette plateforme ; les identifiants doivent correspondre à l'app construite. - Disposez d'un runner Autonomy pour la plateforme demandée et de suffisamment de crédits d'exécution. Pour ces cibles autonomes explicites, utilisez des cas qui ne référencent pas de valeurs d'exécution d'un Environment enregistré.
Les exemples définissent AUTONOMY_REQUEST_ID à partir de CI_JOB_ID, afin qu'un job GitLab relancé reçoive une nouvelle requête. Les métadonnées de branche et de commit proviennent des variables prédéfinies de GitLab. Consultez Test Plans pour organiser les cas sélectionnés.
URL de prévisualisation web
Créez .ci/ à la racine du dépôt, enregistrez le script suivant dans .ci/autonomy.sh, puis commitez-le avec le fichier du pipeline. Toutes les recettes de cette page utilisent ce même script. Il nécessite Bash, jq et curl 7.76 ou ultérieur ; les jobs avec conteneur les installent.
#!/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.'Enregistrez ce qui suit dans .gitlab-ci.yml. Activez les runners Linux hébergés par GitLab pour votre projet ; les jobs web et le job de téléversement iOS sélectionnent explicitement saas-linux-small-amd64. Sur GitLab Self-Managed, remplacez cette étiquette dans chaque job avec conteneur Linux par celle de votre propre runner Linux avec exécuteur Docker. Commencez par Build → Pipelines → New pipeline sur la branche par défaut protégée. Le journal affiche Queued Autonomy runs: et les ID des exécutions lorsque l'API accepte la requête.
stages: [prepare, qa]
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_REF_PROTECTED == "true"'
- when: never
default:
tags: [saas-linux-small-amd64]
image: debian:stable-slim
before_script:
- apt-get update && apt-get install -y --no-install-recommends bash curl jq ca-certificates
preview_ready:
stage: prepare
script:
- |
: "${PREVIEW_URL:?Set the deployed preview URL in CI/CD Variables}"
curl --fail --silent --show-error --location \
--connect-timeout 15 --max-time 60 "$PREVIEW_URL" > /dev/null
printf 'PREVIEW_URL=%s\n' "$PREVIEW_URL" > preview.env
artifacts:
reports:
dotenv: preview.env
expire_in: 1 day
autonomy_web:
stage: qa
timeout: 30m
needs:
- job: preview_ready
artifacts: true
script:
- |
export AUTONOMY_REQUEST_ID="gitlab:$CI_PROJECT_ID:$CI_JOB_ID"
export AUTONOMY_BRANCH="$CI_COMMIT_REF_NAME"
export AUTONOMY_COMMIT_SHA="$CI_COMMIT_SHA"
bash .ci/autonomy.sh webPour une URL créée dans votre job de déploiement existant, déplacez les entrées printf et artifacts:reports:dotenv dans ce job, puis donnez son nom à needs. Supprimez la variable de projet fixe PREVIEW_URL pour qu'elle ne remplace pas la valeur dotenv générée. Ne placez aucun identifiant secret dans preview.env ; GitLab le stocke comme artefact téléchargeable.
Transfert d'artefact mobile
Utilisez le même .ci/autonomy.sh. Le script demande une URL de téléversement signée, téléverse le fichier, exige une analyse saine et transmet l'ID de stockage obtenu à l'exécution. Sélectionnez uniquement la plateforme dont le build existe dans votre dépôt.
iOS
Utilisez un runner macOS auto-hébergé, dédié et protégé, avec l'étiquette macos, l'exécuteur shell Bash, Xcode et le SDK iOS Simulator installés. Désactivez Run untagged jobs pour ce runner et ne lui attribuez pas l'étiquette du runner Linux. Les runners macOS hébergés par GitLab nécessitent Premium ou Ultimate, sauf pour les programmes open source admissibles. Un projet Free standard a besoin de son propre Mac. Linux ne peut pas réaliser ce build Xcode.
Cet exemple natif suppose ios/MyApp.xcodeproj, un schéma partagé MyApp et un produit MyApp.app. Remplacez les trois par les noms de votre projet et installez ses dépendances particulières avant xcodebuild. Pour un projet avec workspace, utilisez -workspace ios/MyApp.xcworkspace à la place de -project. Il construit un .app pour Simulator, pas un .ipa pour appareil.
Le job macOS archive l'app en conservant les permissions d'exécution et les liens symboliques avant que GitLab transporte le ZIP. needs:artifacts télécharge ce ZIP dans le job Linux, qui assure le téléversement et l'attente.
stages: [build, qa]
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_REF_PROTECTED == "true"'
- when: never
build_ios:
stage: build
tags: [macos]
script:
- |
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 .build
(cd ios/build/Build/Products/Release-iphonesimulator && \
zip -qry -y "$CI_PROJECT_DIR/.build/MyApp.app.zip" MyApp.app)
artifacts:
paths:
- .build/MyApp.app.zip
expire_in: 1 day
autonomy_ios:
stage: qa
tags: [saas-linux-small-amd64]
image: debian:stable-slim
timeout: 30m
needs:
- job: build_ios
artifacts: true
before_script:
- apt-get update && apt-get install -y --no-install-recommends bash curl jq ca-certificates
script:
- |
export AUTONOMY_TEST_PLAN_ID="$AUTONOMY_IOS_TEST_PLAN_ID"
export APP_IDENTIFIER="$AUTONOMY_IOS_BUNDLE_ID"
export ARTIFACT_PATH=".build/MyApp.app.zip"
export AUTONOMY_REQUEST_ID="gitlab:$CI_PROJECT_ID:$CI_JOB_ID"
export AUTONOMY_BRANCH="$CI_COMMIT_REF_NAME"
export AUTONOMY_COMMIT_SHA="$CI_COMMIT_SHA"
bash .ci/autonomy.sh iosAndroid
Enregistrez un runner Linux dédié et protégé avec l'étiquette android-linux et l'exécuteur shell Bash. Désactivez Run untagged jobs pour ce runner et ne lui attribuez pas l'étiquette du runner avec conteneur Linux. Installez sur cette machine le JDK requis par votre projet, les outils en ligne de commande Android, vos versions de compile SDK et build-tools, Bash, jq, curl 7.76 ou ultérieur, ainsi que des certificats CA de confiance. Définissez ANDROID_HOME, acceptez les licences du SDK et commitez un android/gradlew exécutable avec ses fichiers wrapper. L'exécuteur shell utilise les outils de l'hôte ; il n'installe pas de SDK Android à votre place.
Cet exemple construit l'APK de débogage du module app et le téléverse dans le même job Linux. Adaptez ensemble la tâche Gradle et ARTIFACT_PATH si votre projet utilise des variantes ou un autre module.
stages: [qa]
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_REF_PROTECTED == "true"'
- when: never
autonomy_android:
stage: qa
tags: [android-linux]
timeout: 60m
script:
- |
set -euo pipefail
(cd android && ./gradlew --no-daemon assembleDebug)
export AUTONOMY_TEST_PLAN_ID="$AUTONOMY_ANDROID_TEST_PLAN_ID"
export APP_IDENTIFIER="$AUTONOMY_ANDROID_PACKAGE_NAME"
export ARTIFACT_PATH="android/app/build/outputs/apk/debug/app-debug.apk"
export AUTONOMY_REQUEST_ID="gitlab:$CI_PROJECT_ID:$CI_JOB_ID"
export AUTONOMY_BRANCH="$CI_COMMIT_REF_NAME"
export AUTONOMY_COMMIT_SHA="$CI_COMMIT_SHA"
bash .ci/autonomy.sh androidConditionner le pipeline au verdict
Le script consulte chaque ID renvoyé par run.trigger via run.get. Il continue d'attendre tant qu'une exécution est queued, running ou retrying, et réussit uniquement lorsque chaque résultat final contient verdict: "passed" et validity: "valid". Une exécution en file d'attente ne suffit pas à valider le pipeline. Les résultats en échec, invalides, non vérifiés, annulés, inattendus ou hors délai font échouer le job.
Le budget d'attente par défaut est de 1 200 secondes pour l'ensemble des exécutions renvoyées. Définissez AUTONOMY_WAIT_SECONDS pour le modifier et gardez les délais du job et du runner GitLab supérieurs à ce budget, augmenté du temps de build et de téléversement. Laissez allow_failure désactivé. Annuler le job GitLab ou atteindre son délai arrête l'interrogation ; cela n'annule pas une exécution Autonomy déjà en file d'attente.
Stratégie de branche et d'événement
Ces configurations autorisent les pushes, les exécutions planifiées et les pipelines lancés manuellement uniquement sur la branche par défaut protégée. Les pipelines de merge requests et le code des forks ne reçoivent pas la clé. Utilisez de courts plans de smoke test pour les déploiements courants ; réservez un déclenchement planifié ou manuel avec un plan plus large aux vérifications de version.
Pour vérifier la prévisualisation d'une merge request, exécutez manuellement la configuration de confiance de la branche par défaut avec l'URL de prévisualisation relue. N'autorisez pas l'accès aux variables protégées pour du code de merge request non fiable. Si vous élargissez les règles de branche, protégez ces branches et examinez d'abord leurs changements de pipeline.
Références du fournisseur
- Référence YAML de GitLab CI/CD : étapes, règles du workflow, étiquettes de runners, délais et
needs. - Variables CI/CD : valeurs de variables, masquage et branches protégées.
- Artefacts de jobs et rapports dotenv : transmission d'un ZIP ou d'une URL entre jobs.
- Variables prédéfinies : ID des jobs, noms de branche et SHA des commits.
- Runners Linux hébergés : étiquette
saas-linux-small-amd64et exécution en conteneur. - Runners macOS hébergés et exécuteur shell : disponibilité des runners et prérequis de l'hôte.