Skip to content

CI/CD integration

The Bitbucket CLI automates pull request (PR) workflows, reports build statuses back to commits, and triggers Bitbucket Pipelines from any CI system.

  1. Store credentials as secrets in your CI/CD platform.

    • BB_USERNAME, your Atlassian account email
    • BB_API_TOKEN, your Bitbucket API token
  2. Install the CLI. The standalone binary needs no Bun, Node.js or npm, so the job skips the runtime install. Verify it against the release’s SHA256SUMS before running it:

    Terminal window
    base=https://github.com/0pilatos0/bitbucket-cli/releases/latest/download
    curl -fsSLO "$base/bb-linux-x64"
    curl -fsSLO "$base/SHA256SUMS"
    sha256sum --check --ignore-missing SHA256SUMS
    install -D -m 755 bb-linux-x64 "$HOME/.local/bin/bb"
    export PATH="$HOME/.local/bin:$PATH"

    Replace latest/download with download/v<version> to pin a release, and bb-linux-x64 with bb-linux-arm64 on arm64 agents. See Installation for the other platforms and for gh attestation verify. The binary needs glibc, so on Alpine use the Bun route below.

    To use the npm package instead, install Bun first. The package is Bun-only; it exits immediately under Node.js.

    Terminal window
    curl -fsSL https://bun.sh/install | bash
    export PATH="$HOME/.bun/bin:$PATH"
    bun install -g @pilatos/bitbucket-cli

    On an image that already ships Bun (oven/bun:latest) skip the curl line and keep the other two, those images contain no Node.js and no npm.

  3. Authenticate. With BB_API_TOKEN set in the environment, bb auth login takes the API-token path and stores the credentials. With no token set it opens a browser for OAuth and waits five minutes for a callback that never arrives in a headless runner.

    Terminal window
    bb auth login
  4. Run commands with explicit workspace and repository flags.

    Terminal window
    bb pr list -w myworkspace -r myrepo --json

List commands return 25 items by default. Pass --limit <n> to raise or lower that cap, or --all to fetch every page. --all overrides --limit.

Terminal window
bb pr list -w myworkspace -r myrepo --all --json

See Global Flags.

--json [fields] and --jq <expression> are global flags. --jq runs an embedded jq, so it works on minimal CI images and on Windows agents that have no jq binary. --jq requires --json.

Terminal window
# Project to a comma-separated field list
bb pr list -w myworkspace -r myrepo --json id,title
# Filter with the embedded jq
bb pr list -w myworkspace -r myrepo --all --json --jq '.pullRequests[].id'

Projection runs before jq, and --json <fields> drops the envelope on list commands, count disappears once you project. See Scripting & Automation.


Each snippet shows the platform-specific part: how secrets reach the job, and how the CLI gets on PATH. The GitHub Actions example uses the standalone binary and the others use Bun; either install from Quick setup works on any of them. The bb auth login step is the same everywhere.

name: Bitbucket PR Check
on:
push:
branches: [main]
pull_request:
jobs:
check-bitbucket-prs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Bitbucket CLI
run: |
base=https://github.com/0pilatos0/bitbucket-cli/releases/latest/download
curl -fsSLO "$base/bb-linux-x64"
curl -fsSLO "$base/SHA256SUMS"
sha256sum --check --ignore-missing SHA256SUMS
install -D -m 755 bb-linux-x64 "$HOME/.local/bin/bb"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: List open PRs
env:
BB_USERNAME: ${{ secrets.BB_USERNAME }}
BB_API_TOKEN: ${{ secrets.BB_API_TOKEN }}
run: |
bb auth login
bb pr list -w myworkspace -r myrepo --all --json --jq '.count'

Appending to $GITHUB_PATH puts bb on PATH for every later step.

stages:
- check
variables:
BB_WORKSPACE: myworkspace
BB_REPO: myrepo
check-prs:
stage: check
image: oven/bun:latest
before_script:
- bun install -g @pilatos/bitbucket-cli
- export PATH="$HOME/.bun/bin:$PATH"
- bb auth login
script:
- bb pr list -w $BB_WORKSPACE -r $BB_REPO --json
- bb repo view -w $BB_WORKSPACE -r $BB_REPO

Define BB_USERNAME and BB_API_TOKEN under Settings > CI/CD > Variables (masked, protected). GitLab exports project variables into the job environment, so no variables: entry is needed for them.

image: oven/bun:latest
pipelines:
default:
- step:
name: Check PRs
script:
- bun install -g @pilatos/bitbucket-cli
- export PATH="$HOME/.bun/bin:$PATH"
- bb auth login
- bb pr list -w $BITBUCKET_WORKSPACE -r $BITBUCKET_REPO_SLUG --json
pull-requests:
'**':
- step:
name: PR Info
script:
- bun install -g @pilatos/bitbucket-cli
- export PATH="$HOME/.bun/bin:$PATH"
- bb auth login
- bb pr view $BITBUCKET_PR_ID -w $BITBUCKET_WORKSPACE -r $BITBUCKET_REPO_SLUG
definitions:
caches:
bun: ~/.bun

Pipelines injects BITBUCKET_WORKSPACE, BITBUCKET_REPO_SLUG, and BITBUCKET_PR_ID, which the snippet above passes to -w, -r, and bb pr view.

pipeline {
agent any
environment {
BB_USERNAME = credentials('bitbucket-account-email')
BB_API_TOKEN = credentials('bitbucket-token')
}
stages {
stage('Setup') {
steps {
sh 'curl -fsSL https://bun.sh/install | bash'
sh 'export PATH="$HOME/.bun/bin:$PATH" && bun install -g @pilatos/bitbucket-cli'
sh 'export PATH="$HOME/.bun/bin:$PATH" && bb auth login'
}
}
stage('Check PRs') {
steps {
sh '''
export PATH="$HOME/.bun/bin:$PATH"
bb pr list -w myworkspace -r myrepo --all --json --jq '.count'
'''
}
}
}
}

Each sh step is a fresh shell, so PATH has to be exported in every one.

To automate merges from Jenkins, use the checked merge recipe.

trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
- group: bitbucket-credentials # Variable group with BB_USERNAME, BB_API_TOKEN
steps:
- script: |
curl -fsSL https://bun.sh/install | bash
echo "##vso[task.prependpath]$HOME/.bun/bin"
displayName: 'Install Bun'
- script: bun install -g @pilatos/bitbucket-cli
displayName: 'Install Bitbucket CLI'
- script: |
bb auth login
bb pr list -w myworkspace -r myrepo --json
displayName: 'List PRs'
env:
BB_USERNAME: $(BB_USERNAME)
BB_API_TOKEN: $(BB_API_TOKEN)

##vso[task.prependpath] puts ~/.bun/bin on PATH for every later step.


bb status set <sha> creates or updates a build status on a commit. It is idempotent per --key, so calling it again with the same key replaces the previous status instead of adding a second one.

Terminal window
bb status set "$GITHUB_SHA" -w myworkspace -r myrepo \
--key CI --state INPROGRESS --url "$RUN_URL"
# ... run the build ...
bb status set "$GITHUB_SHA" -w myworkspace -r myrepo \
--key CI --state SUCCESSFUL --url "$RUN_URL" --description "All tests passed"

--state accepts INPROGRESS, SUCCESSFUL, FAILED, or STOPPED. --name, --description, and --refname are optional. Read statuses back with bb status list <sha>.

Trigger a Bitbucket pipeline from another CI system

Section titled “Trigger a Bitbucket pipeline from another CI system”
Terminal window
# Latest commit on a branch
bb pipeline run -w myworkspace -r myrepo --branch main
# A custom pipeline from bitbucket-pipelines.yml, with variables
bb pipeline run -w myworkspace -r myrepo \
--pipeline deploy-prod --var ENV=prod --var DRY_RUN=false

bb pipeline watch waits for the latest run on the current branch and exits non-zero unless it passes; bb pipeline logs --follow streams its logs. bb pipeline list --status FAILED, bb pipeline view <id>, bb pipeline logs <id> --step <n>, and bb pipeline stop <id> cover the rest. See bb pipeline.

Run this in a branch build after pushing the source branch. It uses external jq to pass the branch name as data, and lists every open PR before creating one:

Terminal window
set -euo pipefail
BRANCH=${GITHUB_REF#refs/heads/}
EXISTING=$(bb pr list -w myworkspace -r myrepo --all --json | \
jq --arg branch "$BRANCH" '[.pullRequests[] | select(.source.branch.name == $branch)] | length')
if [ "$EXISTING" -eq 0 ]; then
bb pr create -w myworkspace -r myrepo \
-t "chore: $BRANCH" -b "Opened automatically by CI" \
-s "$BRANCH" -d main
fi

Use your platform’s source-branch variable outside GitHub Actions. A concurrent job can create the same PR between the lookup and create call; handle that failure in your job rather than assuming the lookup is a lock.

Use Auto-merge on green CI. It reads every build-status page, checks required status keys, and rechecks the PR head before merging. Repository merge policies must enforce your authoritative requirements. One approval alone does not establish that a PR is ready to merge.

See Reporting and analytics for paginated PR reports and diff statistics.

Commands exit 0 on success and 1 on failure. Interrupted interactive prompts exit 130; disable prompts in automation with --no-input. Set BB_DETAILED_EXIT_CODES=1 to tell usage (2), not found (3), authentication (4) and confirmation required (5) apart.

In --json mode, successful JSON goes to stdout and command errors, argument-parsing errors included, go to stderr as JSON. HTTP traces from BB_DEBUG also go to stderr, so stdout stays parseable.

See Scripting and automation for an error handling example and Error codes for numeric codes.

Create a dedicated CI token with only the permissions its commands require. Use the scope reference rather than copying a broad scope list. Grant read, write, admin, and delete scopes separately as needed.

Store in Settings > Secrets and variables > Actions


✗ Authentication required. Run 'bb auth login'.

Under --json the same failure appears on stderr as {"name":"BBError","code":1001,...}.

Check that both variables reach the job, that BB_USERNAME is the Atlassian account email, and that the token has not expired:

Terminal window
echo "Account email set: $([ -n "$BB_USERNAME" ] && echo 'yes' || echo 'no')"
echo "Token set: $([ -n "$BB_API_TOKEN" ] && echo 'yes' || echo 'no')"

bb auth login only uses the API-token path when BB_API_TOKEN is set (or when you pass -u/-p/--with-token). Otherwise it starts the OAuth browser flow on http://localhost:19872/callback and blocks for five minutes. Set BB_API_TOKEN in the step’s environment.

Add a delay between API calls:

Terminal window
for pr_id in $pr_ids; do
bb pr view "$pr_id" -w myworkspace -r myrepo --json
sleep 2
done

bun install -g puts binaries in ~/.bun/bin, which is not on PATH in a fresh shell. Export it before calling bb, in the same shell invocation:

Terminal window
export PATH="$HOME/.bun/bin:$PATH"
bb --version