Skip to main content
No Result Found
Get your setup working faster. Join our Discord for optimisation tips from elite testers. Join our DiscordJoin our Discord

Run the CLI in a CI/CD pipeline

Run a Test Companion CLI workflow from GitHub Actions, Jenkins, or another CI/CD pipeline when an event such as a merged pull request occurs.

In your terminal, you give the Test Companion CLI, tc, a task and read the result. In a pipeline, an event gives tc the task instead. A pull request merges, or a build fails, and the pipeline runs a workflow for you. The workflow generates test cases, finds the root cause of a failure, or fixes failing tests. It returns the result as a pull request or a summary file.

Prerequisites

Ensure you have the following:

  • A CI/CD pipeline that can run shell commands, such as GitHub Actions or Jenkins. The installer needs curl and tar on the runner.
  • Your BrowserStack username and access key stored as secrets in your CI provider. Find both values on the Account and profile page.
  • Write access to the repository for the pipeline, with git installed and a Git identity configured on the runner. The automate and fix workflows open a pull request. The automate, fix, and generate workflows also push a Git reference to the origin remote to detect a duplicate run.

Workflows you can run

Run tc workflow list to see every workflow available to your account. The list includes the built-in workflows and your enabled skills. The following built-in workflows run from a pipeline:

Workflow Description
generate Generate test cases for the project or for a URL.
automate Turn saved Test Management test cases into automated tests.
test Run the test suite of the project on BrowserStack.
rca Analyze the root cause of a failing build.
fix Diagnose and fix the failing tests in a build.
validate Validate test cases by path or by description.
results Fetch the test results of a BrowserStack build.
mobile generate Explore a mobile app on a real device and generate test cases for it.
mobile run Run a mobile testing task on a real BrowserStack device.
tm projects, tm folders, and tm cases List projects, folders, and test cases in BrowserStack Test Management.

The pr workflow also appears in the list. It needs an interactive terminal, so it cannot run from a pipeline.

How it works

A pipeline run uses two parts. A step in your pipeline reports the event. A configuration file in your repository decides what to do about it.

  • The pipeline step installs tc, signs in, and runs tc workflow run with the event name and its details. The step rarely changes after you add it.
  • The configuration file maps each event to a workflow. It also sets the branches, inputs, mode, and limits of that workflow. You change this file as your needs change, with no change to the pipeline.

The tc command reads the event details only from the --context flag. It does not read the environment variables of your CI provider. The same command behaves the same way in GitHub Actions, in Jenkins, and in your terminal.

Create the configuration file

Commit a file named testcompanion-pipeline.yml to the root of your repository:

workflows:
  - name: generate-on-merge          # A label for this entry
    workflow: generate               # The workflow to run
    on: pr_merged                    # The event this entry responds to
    when: { branches: [main] }       # Run only on these branches
    input: { save-to-tm: "true" }
    mode: preview                    # Remove this line to write for real
    limits: { time: 15m, cost_usd: 5 }
    enabled: true                    # Set to false to pause this entry

  - name: rca-on-fail
    workflow: rca
    on: build_failed
    limits: { time: 10m, cost_usd: 3 }

Start every entry with mode: preview. In preview mode, tc skips the pull request and the duplicate-run marker. The warning in Command-line flags describes what preview mode does not stop. After you review a few runs, remove the mode line. The following fields are available:

Field Description
name A label for the entry. The tc command does not read it.
workflow The workflow to run. Use any name from tc workflow list.
on The event the entry responds to. The tc command matches it against the --event value from your pipeline.
when.branches Run only when the branch value in --context is in this list.
when.paths Run only when a path in the paths value of --context matches one of these patterns. A pattern can end in /** to match a folder and everything under it.
when.status Run only when the build_status value in --context is in this list.
input Inputs for the workflow, such as save-to-tm: "true". An --input flag on the command replaces this whole map.
mode Set to preview to run the entry in preview mode. Omit the field to write for real.
limits.time The maximum run time, such as 15m. The run stops when it reaches this limit. A value without a unit fails validation.
limits.cost_usd The maximum spend in US dollars. Applies only to runs that use --json.
enabled Set to false to pause the entry without deleting it. An omitted field means enabled.

When tc workflow run receives an --event flag, it reads this file. It runs the first entry that matches the workflow, the event, and the when conditions. When no entry matches, or the file is missing, the command exits with the message no binding for <event>. A file that does not parse stops the run before any work starts.

To try a workflow before you bind it to an event, run tc workflow run <name> without the --event flag. The command ignores the configuration file and runs the workflow on demand.

To store the file elsewhere, pass --config <path> or set the TC_PIPELINE_CONFIG environment variable.

Pass event details to the workflow

Each workflow reads specific keys from --context and --input. A missing required key stops the run with a usage error. The following keys are available:

Workflow Context keys Input keys
generate sha scopes generation to that commit. pr adds the pull request number. subject replaces both. url generates for a live page. save-to-tm=true saves the cases to Test Management.
test instructions for the test run. None.
rca build, the build URL or number. Required. None.
fix build, the build ID, or description, the failure text. One is required. None.
validate target, a path or a description. Required. target, when not passed in the context.
results build, the build ID. None.
automate cases, a comma-separated list of test case IDs. Required. project selects the Test Management project.
mobile generate app, a bs:// ID or a file path. Required. instructions for the exploration. save-to-tm=true saves the cases to Test Management.
mobile run app and task. Both required. None.
tm projects and tm folders None. project selects the project.
tm cases None. project and folder select the folder to list.

For a skill, tc passes every context and input value to the agent as labeled data, not as instructions. For a built-in workflow, the command rejects a free-text value that starts with -. A subject or a description cannot be read as a flag.

Sign in from the pipeline

The pipeline has no browser, so sign in with your BrowserStack username and access key. Set the BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY environment variables from your CI secrets, then run tc auth login. For the full procedure, see Sign in without a browser.

Do not write the username or access key in the pipeline file. Reference the CI secrets instead, as the examples on this page show.

Pin the CLI version

The CLI updates itself before most commands run. In a pipeline, pin the version so that every run uses the release you tested. Pinning takes two settings:

  • The installer must install the pinned release.
  • The tc command must refuse any other release.

Set both as follows:

export TC_PIN_VERSION="<version>"
export TC_SHA256="<sha256>"
curl -fsSL -o /tmp/tc-install.sh https://test-companion.browserstack.com/cli/install.sh
TC_VERSION="$TC_PIN_VERSION" sh /tmp/tc-install.sh

Replace <version> with the release number without a v prefix, such as 1.1.2. Replace <sha256> with the checksum of that release for the operating system and CPU of your runner. The installer refuses a pinned install without a checksum.

With TC_PIN_VERSION set, tc does not check for updates. If the installed release does not match the pinned one, every tc command exits with code 4. It prints both versions first. This includes tc auth login. It does not run a different release.

To use the latest release instead, remove TC_PIN_VERSION, TC_SHA256, and TC_VERSION, and set TC_NO_AUTO_UPGRADE=1. The pipeline then keeps the release it installed for the rest of the run.

GitHub Actions example

The following workflow file runs the generate workflow after a pull request merges into the default branch. Save it as .github/workflows/tc-workflow.yml:

name: tc-workflow

on:
  pull_request:
    types: [closed]

jobs:
  run-tc:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    timeout-minutes: 25
    # The tc command pushes a Git reference and opens a pull request,
    # so the default read-only GITHUB_TOKEN is not enough.
    permissions:
      contents: write
      pull-requests: write
    env:
      BROWSERSTACK_USERNAME: $
      BROWSERSTACK_ACCESS_KEY: $
      TC_PIN_VERSION: "<version>"
      TC_SHA256: "<sha256>"
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2

      # GitHub-hosted runners set no Git identity. The tc command
      # needs one to create the reference it pushes.
      - name: Configure Git identity
        run: |
          git config --global user.email "tc-ci@users.noreply.github.com"
          git config --global user.name "tc-ci"

      - name: Install tc
        run: |
          curl -fsSL -o /tmp/tc-install.sh https://test-companion.browserstack.com/cli/install.sh
          TC_VERSION="$TC_PIN_VERSION" sh /tmp/tc-install.sh
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Sign in
        timeout-minutes: 2
        run: tc auth login

      - name: Run tc workflow
        env:
          TC_SHA: $
          TC_BASE_BRANCH: $
        run: |
          tc workflow run generate --event pr_merged \
            --context "sha=$TC_SHA,branch=$TC_BASE_BRANCH" \
            --json --yolo --max-time 15m \
            --summary-file tc-summary.md

      - name: Publish summary
        if: always()
        run: cat tc-summary.md >> "$GITHUB_STEP_SUMMARY" 2>/dev/null || true

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: tc-summary
          path: tc-summary.md
          if-no-files-found: ignore

The example passes every GitHub context value through an env: block instead of writing it into the shell command. Follow the same pattern in your pipeline. Some context values, such as a pull request title, are free text. A free-text value written directly into a shell command can run as a command.

When the run finishes, the job summary shows the content of tc-summary.md. The same file is attached to the run as an artifact named tc-summary.

Jenkins example

The following Jenkinsfile runs the generate workflow after a merge to main and the rca workflow after a failed build:

pipeline {
    agent any
    environment {
        BROWSERSTACK_USERNAME = credentials('browserstack-username')
        BROWSERSTACK_ACCESS_KEY = credentials('browserstack-access-key')
        TC_PIN_VERSION = '<version>'
        TC_SHA256 = '<sha256>'
    }
    stages {
        // An agent that starts fresh on every build has no Git identity.
        // The tc command needs one. Skip this stage on a persistent agent.
        stage('Configure Git identity') {
            steps {
                sh '''
                    git config --global user.email || git config --global user.email "tc-ci@users.noreply.github.com"
                    git config --global user.name || git config --global user.name "tc-ci"
                '''
            }
        }

        stage('Install tc') {
            steps {
                sh '''
                    curl -fsSL -o /tmp/tc-install.sh https://test-companion.browserstack.com/cli/install.sh
                    TC_VERSION="$TC_PIN_VERSION" sh /tmp/tc-install.sh
                '''
            }
        }

        stage('Sign in') {
            steps {
                // The Jenkins timeout step works on every agent. The shell
                // timeout command does not.
                timeout(time: 2, unit: 'MINUTES') {
                    sh '"$HOME/.local/bin/tc" auth login'
                }
            }
        }

        stage('Generate on merge') {
            // A multibranch pipeline sets GIT_BRANCH to 'main'. Other job
            // types set it to 'origin/main', which matches neither this
            // check nor the config file's branch list.
            when { expression { env.CHANGE_ID == null && env.GIT_BRANCH == 'main' } }
            steps {
                sh '''
                    "$HOME/.local/bin/tc" workflow run generate \
                      --event pr_merged \
                      --context sha=$GIT_COMMIT,branch=$GIT_BRANCH \
                      --summary-file tc-summary.md --json --yolo
                '''
            }
            post { always { archiveArtifacts artifacts: 'tc-summary.md', allowEmptyArchive: true } }
        }

        stage('RCA on failure') {
            when { expression { currentBuild.previousBuild?.result == 'FAILURE' } }
            steps {
                sh '''
                    "$HOME/.local/bin/tc" workflow run rca \
                      --event build_failed \
                      --context build=$BUILD_URL \
                      --summary-file tc-summary.md --json --yolo
                '''
            }
        }
    }
}

When a build finishes, Jenkins archives tc-summary.md with the build. Open the build page to read it.

Command-line flags

Pass the following flags to tc workflow run in your pipeline step, along with --event and --context. A flag value takes precedence over the same setting in the configuration file.

Flag Description
--event <name> The event that occurred. The tc command matches it against the on field in the configuration file.
--context k=v,... Details of the event, such as sha, branch, build, or paths. See the keys each workflow reads.
--input k=v,... Inputs for this run, such as save-to-tm=true. Replaces the input map from the configuration file.
--preview Run the workflow in preview mode.
--max-time <duration> Stop the run after this much time, such as 15m.
--max-cost <amount> Stop the run after it spends this amount in US dollars. Applies only with --json.
--summary-file <path> Write a short summary of the run to this file.
--config <path> Read the configuration file from this path instead of testcompanion-pipeline.yml.
--force Replace a stale duplicate-run marker left by a run that was killed. Do not use it to rerun a workflow that succeeded.
--json Print machine-readable output, one JSON object per line.
--yolo Approve every action automatically. Required for an unattended run.

Preview mode does not stop every write. For a built-in workflow, it skips only two actions: opening the pull request and pushing the duplicate-run marker. Every other write still happens. For example, generate with save-to-tm: true still saves test cases to Test Management. For a skill, preview mode asks the agent to report each write instead of performing it. Leave save-to-tm unset until you are ready for a real run.

Read the summary file

When you pass --summary-file, tc writes the file on every exit. An early exit for a missing binding or an unknown workflow also writes it. The file lists the workflow, the event, the preview flag, the context, the input, the duration, and the outcome. The outcome is one of the following values:

  • succeeded: The workflow completed its task.
  • failed: The workflow completed, but the test it wrote or fixed did not pass.
  • broke: The run stopped before completion. When a limit stopped it, the file also shows error_type: ceiling_exceeded.

To tell these outcomes apart in a script, check the exit code instead.

Safeguards

The following behavior applies to every pipeline run:

  • The automate and fix workflows deliver their change as a pull request from a branch named tc/<workflow>/<sha>. They never commit to the branch under test.
  • The automate, fix, and generate workflows run once per commit. A second run for the same commit prints already done, writes nothing, and exits with code 0. Pass --force only to recover from a run that was killed before it could finish.
  • When a run reaches its time limit, it stops. A --json run then exits with code 4.
  • The cost limit applies only when the run uses --json. The tc command checks the total after each model call. The final spend can exceed the limit by the cost of one call.

Next steps

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback

Is this page helping you?

Yes
No

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback!

Talk to an Expert
Download Copy Check Circle