Autonomy Docs
Integrations

GitHub Actions

Trigger Autonomy from GitHub Actions after a preview or staging target is ready.

Use GitHub Actions when your deployment provider does not have a direct integration, when you build preview URLs in custom scripts, or when you want Autonomy to run as part of an existing CI pipeline.

Workflow placement

Place Autonomy after build, deploy, and preview URL discovery. The run should receive the final URL a reviewer would open. Keep branch filters explicit so long-running plans do not run on every push.

Required secrets

Workflow inputs

  • An Autonomy project connected to the repository.
  • Preview deployment URL from the hosting workflow.
  • Optional protected preview bypass token.
  • Pull request number or commit SHA for publishing evidence back to GitHub.

Branch and event strategy

Run short smoke plans on pull requests. Reserve broader suites for release branches, scheduled runs, or manual workflow dispatch. If the plan touches paid services or scarce test data, make the trigger explicit.

Mobile artifact handoff

GitHub Actions is also the recommended way to wire up mobile runs when the project is not on Expo EAS. The pattern is the same as for web preview URLs, but the input to Autonomy is a build artifact instead of a URL: a simulator .app for iOS or an .apk / .aab for Android.

Mobile workflow inputs

  • Autonomy API key, API URL, test plan id, and platform identifiers stored as repository secrets.
  • Autonomy test plan id for the mobile plan you want to run.
  • For iOS: a macOS runner that can build the Simulator app.
  • For Android: a Linux runner with the Android SDK to build the APK.

iOS

Split the job into two stages: build on macOS, then trigger Autonomy on Linux. Pass the .app between them as an actions artifact so you do not burn macOS minutes on a network call.

.github/workflows/ios-tests.ymlyaml
name: iOS Tests

on:
push:
  branches: [main]
pull_request:
workflow_dispatch:

jobs:
build:
  name: Build iOS Simulator app
  runs-on: macos-latest
  steps:
    - uses: actions/checkout@v5
    - name: Build .app
      shell: bash
      run: |
        set -euo pipefail
        xcodebuild \
          -workspace ios/MyApp.xcworkspace \
          -scheme MyApp \
          -configuration Release \
          -sdk iphonesimulator \
          -destination 'generic/platform=iOS Simulator' \
          -derivedDataPath ios/build \
          build
        mkdir -p .build
        cp -R ios/build/Build/Products/Release-iphonesimulator/MyApp.app .build/MyApp.app
    - uses: actions/upload-artifact@v5
      with:
        name: ios-simulator-app
        path: .build/MyApp.app
        retention-days: 1

test:
  name: Run Autonomy iOS plan
  needs: build
  runs-on: ubuntu-latest
  steps:
    - uses: actions/download-artifact@v5
      with:
        name: ios-simulator-app
        path: ./build/MyApp.app
    - name: Upload and trigger
      env:
        AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
        AUTONOMY_API_URL: ${{ secrets.AUTONOMY_API_URL }}
        AUTONOMY_TEST_PLAN_ID: ${{ secrets.AUTONOMY_IOS_TEST_PLAN_ID }}
        AUTONOMY_IOS_BUNDLE_ID: ${{ secrets.AUTONOMY_IOS_BUNDLE_ID }}
      run: |
        set -euo pipefail
        (cd ./build && zip -qr MyApp.app.zip MyApp.app)
        UPLOAD_URL=$(curl -fsS -X POST "$AUTONOMY_API_URL/api/artifacts/upload-url" \
          -H "Authorization: Bearer $AUTONOMY_API_KEY" \
          -H "Content-Type: application/json" | jq -r '.uploadUrl')
        STORAGE_ID=$(curl -fsS -X POST "$UPLOAD_URL" \
          -H "Content-Type: application/zip" \
          --data-binary "@./build/MyApp.app.zip" | jq -r '.storageId')
        SCAN_BODY=$(jq -n \
          --arg storageId "$STORAGE_ID" \
          '{ storageId: $storageId, platform: "ios", fileName: "MyApp.app.zip", contentType: "application/zip" }')
        curl -fsS -X POST "$AUTONOMY_API_URL/api/artifacts/scan" \
          -H "Authorization: Bearer $AUTONOMY_API_KEY" \
          -H "Content-Type: application/json" \
          -d "$SCAN_BODY"
        TRIGGER_BODY=$(jq -n \
          --arg testPlanId "$AUTONOMY_TEST_PLAN_ID" \
          --arg storageId "$STORAGE_ID" \
          --arg bundleId "$AUTONOMY_IOS_BUNDLE_ID" \
          --arg branch "$GITHUB_REF_NAME" \
          --arg commitSha "$GITHUB_SHA" \
          '{
            testPlanId: $testPlanId,
            platforms: ["ios"],
            branch: $branch,
            targets: { ios: { storageId: $storageId, sourceMode: "upload", bundleId: $bundleId, fileName: "MyApp.app.zip" } },
            deployment: { provider: "github-actions", branch: $branch, commitSha: $commitSha }
          }')
        curl -fsS -X POST "$AUTONOMY_API_URL/api/trigger" \
          -H "Authorization: Bearer $AUTONOMY_API_KEY" \
          -H "Content-Type: application/json" \
          -d "$TRIGGER_BODY"

Android

Android builds run on Linux, so the whole workflow fits in one job. No artifact hand-off is needed.

.github/workflows/android-tests.ymlyaml
name: Android Tests

on:
push:
  branches: [main]
pull_request:
workflow_dispatch:

jobs:
test:
  name: Build and run Autonomy Android plan
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v5
    - uses: actions/setup-java@v4
      with:
        distribution: temurin
        java-version: '17'
    - name: Build debug APK
      shell: bash
      run: |
        set -euo pipefail
        cd android
        ./gradlew assembleDebug
    - name: Upload and trigger
      env:
        AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
        AUTONOMY_API_URL: ${{ secrets.AUTONOMY_API_URL }}
        AUTONOMY_TEST_PLAN_ID: ${{ secrets.AUTONOMY_ANDROID_TEST_PLAN_ID }}
        AUTONOMY_ANDROID_PACKAGE_NAME: ${{ secrets.AUTONOMY_ANDROID_PACKAGE_NAME }}
      run: |
        set -euo pipefail
        APK_PATH="android/app/build/outputs/apk/debug/app-debug.apk"
        UPLOAD_URL=$(curl -fsS -X POST "$AUTONOMY_API_URL/api/artifacts/upload-url" \
          -H "Authorization: Bearer $AUTONOMY_API_KEY" \
          -H "Content-Type: application/json" | jq -r '.uploadUrl')
        STORAGE_ID=$(curl -fsS -X POST "$UPLOAD_URL" \
          -H "Content-Type: application/vnd.android.package-archive" \
          --data-binary "@$APK_PATH" | jq -r '.storageId')
        SCAN_BODY=$(jq -n \
          --arg storageId "$STORAGE_ID" \
          '{ storageId: $storageId, platform: "android", fileName: "app-debug.apk", contentType: "application/vnd.android.package-archive" }')
        curl -fsS -X POST "$AUTONOMY_API_URL/api/artifacts/scan" \
          -H "Authorization: Bearer $AUTONOMY_API_KEY" \
          -H "Content-Type: application/json" \
          -d "$SCAN_BODY"
        TRIGGER_BODY=$(jq -n \
          --arg testPlanId "$AUTONOMY_TEST_PLAN_ID" \
          --arg storageId "$STORAGE_ID" \
          --arg packageName "$AUTONOMY_ANDROID_PACKAGE_NAME" \
          --arg branch "$GITHUB_REF_NAME" \
          --arg commitSha "$GITHUB_SHA" \
          '{
            testPlanId: $testPlanId,
            platforms: ["android"],
            branch: $branch,
            targets: { android: { storageId: $storageId, sourceMode: "upload", packageName: $packageName, fileName: "app-debug.apk" } },
            deployment: { provider: "github-actions", branch: $branch, commitSha: $commitSha }
          }')
        curl -fsS -X POST "$AUTONOMY_API_URL/api/trigger" \
          -H "Authorization: Bearer $AUTONOMY_API_KEY" \
          -H "Content-Type: application/json" \
          -d "$TRIGGER_BODY"

Use a separate test plan per platform so failures point at the right surface. If the artifact is already available at a short-lived HTTPS URL, skip the upload step and pass targets.ios.artifactUrl or targets.android.artifactUrl with sourceMode: "url".

Troubleshooting

The web run starts before the preview is ready

Split deployment and QA into separate jobs and pass the deployment URL through job outputs. Autonomy should only run after the preview URL is known.

No PR comment appears

Confirm the pull request context is available, the Autonomy GitHub App is installed for the repository, and the commit SHA was passed to Autonomy.

The iOS upload is rejected as a device build

The macOS build step is producing an .ipa instead of a Simulator .app. Confirm -sdk iphonesimulator is on the xcodebuild command and the destination is a Simulator destination.

The Android build fails to find the SDK

GitHub-hosted Ubuntu runners ship with the Android SDK preinstalled. If you self-host, add actions/setup-android (or install the command-line tools) before the Gradle step.

Mobile uploads accumulate

Use explicit run targets for short-lived CI artifacts and saved environments for builds that should be reused. Reserve dashboard uploads for builds a release manager picks for production runs.

On this page