Bitbucket Pipelines runs CodeCharter as a regular shell step inside the Docker-based runner. The setup below downloads the CLI, analyzes the solution, and stores the SARIF report as a pipeline artifact.
If your repository is hosted on GitHub and only the build runs in Bitbucket Pipelines, you can additionally publish a branded CodeCharter check run and PR comment from this pipeline — see Publish checks from any CI.
bitbucket-pipelines.yml:
image: mcr.microsoft.com/dotnet/sdk:9.0
pipelines:
default:
- step:
name: CodeCharter
caches:
- codecharter
script:
- curl -sSL -H "Authorization: Bearer $CODECHARTER_API_KEY" \
-o codecharter.tar.gz \
https://codecharter.tools/api/v1/cli/linux-x64/1.0.12
- mkdir -p /opt/codecharter && tar -xzf codecharter.tar.gz -C /opt/codecharter
- chmod +x /opt/codecharter/codecharter
- export PATH="/opt/codecharter:$PATH"
- codecharter analyze MySolution.sln --fail-on error --output sarif:codecharter.sarif
artifacts:
- codecharter.sarif
definitions:
caches:
codecharter: .codecharter/cache
Replace MySolution.sln with the path to your solution or project file —
analyze expects a .sln, .slnx, or .csproj file, not a directory.
API key
In Bitbucket: Repository settings → Repository variables, create the variable
CODECHARTER_API_KEY and enable "Secured".
The variable does double duty: the curl step uses it to download the CLI, and
the analyze step uses it to automatically mint a short-lived license when
none is cached. Bitbucket exposes repository variables to every step's
environment, so no extra configuration is needed.
PR annotations via Bitbucket Reports API
Optionally you can post findings as Bitbucket Code Insights. CodeCharter has no direct converter for this, but the JSON format is easy to work with:
- codecharter analyze MySolution.sln --output json --output-file findings.json
- # Convert findings.json into Code Insights API calls
- python3 ./scripts/publish-to-bitbucket-insights.py findings.json
Pull request pipelines: only changed lines
In pull request pipelines you can restrict both the reported findings and the
--fail-on gate to lines changed by the PR with --git-ref:
pipelines:
pull-requests:
'**':
- step:
name: CodeCharter (changed lines only)
clone:
depth: full
script:
# ... download the CLI as above ...
- git fetch origin $BITBUCKET_PR_DESTINATION_BRANCH
- codecharter analyze MySolution.sln --fail-on error --git-ref "origin/$BITBUCKET_PR_DESTINATION_BRANCH..HEAD"
--git-ref runs git diff <range> --unified=0 internally, so the destination
branch must be present in the clone (hence clone: depth: full and the
git fetch).
For legacy codebases there is also baseline support: --write-baseline records
the current findings once, and --baseline then makes output and --fail-on
apply only to new findings.
Caching
CodeCharter has no analysis-result cache, so there is no speedup to be had from
caching analysis output. The one thing worth caching is the rule-bundle cache:
when your project uses portal rule profiles (a .codecharter/codecharter.lock.json
in the .codecharter/ directory), downloaded bundles are stored in
.codecharter/cache. The caches: codecharter block above together with the custom
cache definition persists that directory, which skips re-downloading the
bundles on warm runs.
If your solution file is not at the repo root, adjust the path in the cache definition accordingly. Without portal profiles there is nothing to cache and you can drop the cache blocks.
Version pinning
As always recommended: pin a specific CLI version, see Versioning.
Every download response carries an X-CodeCharter-Sha256 header. Compare it
against the checksum of the downloaded archive if you want to verify download
integrity in the step.
Exit codes
Bitbucket marks the step failed on any non-zero exit. codecharter analyze uses
these exit codes:
| Code | Meaning |
|---|---|
| 0 | No gating findings |
| 1 | Findings at or above the --fail-on level; without --fail-on, any finding at all |
| 2 | Usage error (invalid options, corrupt baseline, ...) |
| 3 | Solution or project could not be loaded |
| 6 | License error |
If the pipeline suddenly fails at the download or analyze step with HTTP 402,
the subscription has expired — both the CLI download and the license minting
return 402 in that case.