Run Bitbucket Pipelines locally. bb-run reads bitbucket-pipelines.yml and runs it in Docker (default) or on the host, including parallel steps, fail-fast, and artifacts.
- Test before pushing - Catch CI failures locally before committing
- Fast iteration - No waiting for Bitbucket's pipeline queue
- Debug easily - Run in verbose mode and inspect output directly
- Two modes - Docker for an environment closer to Bitbucket; host mode needs no Docker
- Parallel steps -
parallel:groups run concurrently; group and per-stepfail-faststop sibling processes when a failing step demands it - Artifacts - Shared / scoped uploads,
capture-on, and selectivedownload(see below) - Small install - One runtime dependency: PyYAML (see
pyproject.toml). Docker is only required for--mode docker
pip install bb-runIf you prefer not to use a project virtualenv:
pipx install bb-runRecommended for most CLI users: pipx keeps bb-run out of system Python and usually puts bb-run on your PATH without extra setup.
After pip install --user or some IDE setups, the script directory may be missing from PATH. Run the same CLI via Python:
python3 -m bbrun --version
python3 -m bbrun --validateThere is no official Homebrew formula in this repository yet. Use pip or pipx above for the supported install path.
To package for Homebrew later: submit a formula to homebrew-core (tagged releases + tests that do not require Docker are typical expectations), or maintain a third-party tap and document it in your fork; see Homebrew docs.
git clone https://github.com/karlhillx/bb-run.git
cd bb-run
pip install -e .To run tests or Ruff locally, use the dev extra (includes pytest, pytest-cov, and ruff):
pip install -e ".[dev]"- Run commands from the repository root (the directory that contains
bitbucket-pipelines.yml), or pass--repo /path/to/that/root. - Prefer
bb-run --validatefirst; it checks the file without Docker. If you do not have Docker, use--mode hostfor runs (see Modes). - On macOS/Linux where
pip installis restricted (PEP 668), use a venv,pipx, or:
python3 -m pip install --user bb-run
(then ensure that user script directory is on yourPATH).
cd /path/to/your/repo # where bitbucket-pipelines.yml lives
bb-run --validatebb-runbb-run --target branches.main
bb-run -t branches.mainbb-run --branch feature/my-workbb-run --mode hostbb-run -v ENVIRONMENT=staging -v API_KEY=secretbb-run --list-targetsbb-run --list-targets --jsonbb-run --dry-run
bb-run --target branches.feature/my-work --branch feature/my-work --dry-run
bb-run --dry-run --jsonbb-run uses the same target naming as Bitbucket Pipelines:
defaultbranches.<branch-name>tags.<tag-name>custom.<name>for pipelines underpipelines: custom:pull-requests.<pattern>for pipelines underpipelines: pull-requests:
For branches.*, tags.*, and pull-requests.*, bb-run first tries an exact key match and then falls back to Bitbucket-style wildcard keys like feature/*, release/**, v*, or **.
Runs steps in Docker containers matching Bitbucket's build environment.
bb-run --mode dockerPros: Faithful reproduction of Bitbucket's environment
Cons: Requires Docker, images may take time to download
Runs steps directly on your local machine.
bb-run --mode hostPros: Fast, no image downloads
Cons: May differ from Bitbucket's environment (Python vs Python3, etc.)
Bitbucket-style parallel blocks are supported in Docker and host mode. Child steps run at the same time. While a parallel group runs, each container / shell receives BITBUCKET_PARALLEL_STEP (0-based index) and BITBUCKET_PARALLEL_STEP_COUNT, matching Bitbucket’s parallel variables.
pipelines:
default:
- parallel:
fail-fast: true
steps:
- step:
name: Integration A
script:
- ./integration.sh --batch 1
- step:
name: Integration B
script:
- ./integration.sh --batch 2You can set fail-fast: false on an individual step inside the group so its failure does not stop the others (when the group uses fail-fast).
bb-run models Bitbucket pipeline artifacts so later steps can rely on captured files even if you delete them mid-pipeline:
- List form —
artifacts: [dist/**, reports/*.txt] - Object form —
artifacts: { paths: [...], download: false }plus optionalupload:entries withname,type(shared/scoped/test-reports),paths,ignore-paths, andcapture-on(success/failed/always) download— default is to restore all prior shared layers before a step;download: falseskips that restore; a list of names restores only those shared artifacts (plus unnamed list-style captures as a fallback when nothing matches)
Captured trees are stored under .bb-run/artifacts/ in the repo (ignored by git). Shared layers are replayed onto the clone directory before each step that downloads them. Scoped and test-reports uploads are saved for inspection but are not injected into later steps.
Caveats: With --mode host or a bind-mounted Docker workspace, files left on disk by an earlier step are still visible even when download: false; bb-run only controls replay from its cache, not deleting your working tree. Parallel groups capture each child after the whole group finishes, reading the final workspace (Bitbucket isolates children more strictly).
cd my-python-project
bb-runcd my-node-project
bb-run --target branches.mainbb-run --verbose--verbose currently prints -v / --variables values before the run; more detail may be added later.
bb-run automatically looks for bitbucket-pipelines.yml in your current directory. Use --repo to specify a different path:
bb-run --repo /path/to/repoSupported (today):
default,branches.<name>,tags.<name>,custom.<name>, andpull-requests.<pattern>targets- Step
scriptexecution (sequential) - Basic environment variables (Bitbucket-style values)
- Docker images per step (Docker mode)
Not yet supported / simplified:
- Pipes (listed but not executed)
- Parallel steps or step conditions
- Services, caches, and artifacts
- Deployment environments, manual triggers, or step size
- Python 3.12+ (
requires-pythoninpyproject.toml) - PyYAML 6.x (installed automatically with
bb-run) - Docker CLI (optional; only for
--mode docker, the default)
Use Python 3.12 for the project venv so python --version matches requires-python in pyproject.toml:
# macOS (Homebrew)
brew install python@3.12
"$(brew --prefix python@3.12)/bin/python3.12" -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# or tests + coverage only: pip install -e ".[test]"
python -m pytest
python -m pytest --cov=bbrun --cov-report=xml tests/
ruff check bbrunbb-run sets these Bitbucket-specific environment variables:
| Variable | Description |
|---|---|
BITBUCKET_BUILD_NUMBER |
Build number (set to "1") |
BITBUCKET_CLONE_DIR |
Repo root on the host; in Docker mode the path inside the container (/opt/atlassian/pipelines/agent/build) |
BITBUCKET_COMMIT |
Git commit SHA (or local if unavailable) |
BITBUCKET_BRANCH |
Branch name (from --branch or default) |
BITBUCKET_REPO_SLUG |
Repository directory name |
BITBUCKET_REPO_UUID |
Unique run ID for this process |
BITBUCKET_WORKSPACE |
Set to "local" |
BITBUCKET_PARALLEL_STEP |
Zero-based index inside a parallel: group (parallel steps only) |
BITBUCKET_PARALLEL_STEP_COUNT |
Number of steps in that parallel group (parallel steps only) |
You are not in the repo root, or the file name does not match exactly. cd into the project that contains the YAML, or use --repo.
The --target name does not match your file. List names with:
bb-run --list-targetsUse --mode host to run on your local machine instead of in Docker:
bb-run --mode hostbb-run automatically translates pip to pip3 and adds --break-system-packages for PEP 668 environments.
Coverage flags come from the pytest-cov plugin. Install the test or dev extra, then use the same interpreter for pytest:
pip install -e ".[dev]"
# or: pip install -e ".[test]"
python -m pytest --cov=bbrun --cov-report=xml tests/Docker Hub rate limits may cause image downloads to fail. Try:
- Waiting and retrying later
- Using
--mode hosttemporarily - Configuring a Docker mirror
MIT License - see LICENSE for details.
See CONTRIBUTING.md. User-facing changes should be noted in CHANGELOG.md. Security reports: SECURITY.md.