GitHub Action
Trigger a testsbot test plan (suite) from a GitHub Actions workflow and,
by default, block the job until the plan finishes. The action is a thin
composite wrapper over the CLI's plans run command — it inherits
the same auth, timeout, and CI exit-code behavior.
Quick start
# .github/workflows/qa.yml
name: QA
on: [pull_request]
jobs:
test-plan:
runs-on: ubuntu-latest
steps:
- uses: testsbot/run-action@v1
with:
api_token: ${{ secrets.TESTSBOT_API_TOKEN }}
test_plan_id: 00000000-0000-0000-0000-000000000000
blocking: "true"
Create the API key in the app under Settings → API keys
(settings/api-keys). Keys start with tb_live_ and need the read/write
scope to trigger runs. Store it as the TESTSBOT_API_TOKEN
repository secret
— the action passes it to the CLI purely through the environment and never
prints it to the logs.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
api_token | yes | — | testsbot API key (tb_live_…, read/write scope). Pass it from a secret. |
test_plan_id | yes | — | Test plan id (UUID) to run. |
blocking | no | "true" | When true, wait for the plan and fail the step on a failed result. |
api_url | no | https://api.testsbot.com | API base URL (override for staging / self-hosted stacks). |
timeout | no | "600" | Blocking deadline in seconds. Ignored when blocking is false. |
run_mode | no | — | Optional run-mode override (ci | nightly). Defaults to the plan setting. |
Outputs
| Output | Description |
|---|---|
run_created | "true" when the plan run was created, "false" otherwise. |
run_id | The created plan run id. |
run_url | Deep link to the plan run (<api_url>/plan-runs/<id>). |
run_status | Final status in blocking mode (running | done); empty otherwise. |
run_result | Final result in blocking mode (passed | failed); empty otherwise. |
Blocking and exit behavior
In blocking mode the action polls the plan run until it is done and maps
the result to the step's exit code — the same contract as
runs follow:
| Result / state | Step exit code | Effect |
|---|---|---|
passed | 0 | Step succeeds; downstream jobs run. |
failed | 1 | Step fails; downstream jobs are blocked. |
| timeout | 2 | Step fails after timeout seconds. |
A failed plan run therefore blocks any deployment that lists the test step
in its needs:.
PR gating example
Block a deploy job until the test plan passes:
name: Deploy
on:
push:
branches: [main]
jobs:
test-plan:
runs-on: ubuntu-latest
outputs:
result: ${{ steps.qa.outputs.run_result }}
steps:
- id: qa
uses: testsbot/run-action@v1
with:
api_token: ${{ secrets.TESTSBOT_API_TOKEN }}
test_plan_id: 00000000-0000-0000-0000-000000000000
blocking: "true"
timeout: "900"
deploy:
needs: test-plan # only runs when the test-plan step exits 0
runs-on: ubuntu-latest
steps:
- run: echo "Tests passed (${{ needs.test-plan.outputs.result }}) — deploying"
Fire-and-forget example
Trigger the plan without waiting (blocking: false) — for example to kick off
a nightly suite. The step exits 0 immediately and run_result is empty:
- uses: testsbot/run-action@v1
with:
api_token: ${{ secrets.TESTSBOT_API_TOKEN }}
test_plan_id: 00000000-0000-0000-0000-000000000000
blocking: "false"
run_mode: nightly
Using the CLI directly
The action wraps these CLI commands, which you can also run locally or in any CI:
# Trigger a plan and block until it finishes (CI exit codes 0/1/2)
npx @testsbot/cli plans run <plan-id>
# Trigger only, do not wait
npx @testsbot/cli plans run <plan-id> --no-block
# Follow an already-running plan run
npx @testsbot/cli plans follow <plan-run-id>
The CLI reads the API key from QA_CLONE_API_TOKEN (what the action sets) or
from ~/.qa-clone/config.json (written by qa-clone auth). See the
CLI docs for details.