Other CI systems¶
cpp-linter-action is for GitHub Actions. On any other
CI system, run the cpp-linter command: it reads git diff, checks the C and C++ files your
branch changes with the LLVM version you pin, and writes a report.
What you get outside GitHub:
- The findings in the job log, and a Markdown report in
cpp-linter.mdthat the job keeps. - A failed job when there are findings.
- No comments or reviews on the merge request or pull request. cpp-linter posts those on GitHub only.
The script¶
Save this as ci/cpp-linter.sh. It is the same for every CI system; only the job definition
around it differs.
#!/usr/bin/env bash
# Checks the files this branch changes with clang-format and clang-tidy.
# Usage: ci/cpp-linter.sh <target branch>
set -euo pipefail
target="$1"
llvm=21
python3 -m venv .venv
. .venv/bin/activate
pip install --quiet 'cpp-linter<2' clang-tools
clang-tools install clang-format clang-tidy --version "$llvm" --directory .venv/bin --no-progress-bar
git fetch --quiet origin "+refs/heads/$target:refs/remotes/origin/$target"
base="$(git merge-base "origin/$target" HEAD)"
cpp-linter --version="$llvm" --style=file --tidy-checks='' \
--files-changed-only=true --diff-base="$base" \
--summary-output-file=cpp-linter.md 2>&1 | tee cpp-linter.log
# cpp-linter exits with 0 when it finds problems, so fail the job here.
grep -q ':0 checks-failed$' cpp-linter.log
- The script needs Python 3.11 or later, git and a full clone:
git merge-basecannot find the point where your branch started in a shallow clone. Each job below turns shallow cloning off. clang-toolsdownloads static clang-format and clang-tidy binaries into the virtual environment, with clang's builtin headers. Nothing is installed outside.venv.--style=fileand--tidy-checks=''use your.clang-formatand.clang-tidy.--files-changed-only=truechecks every line of the files the branch changes. Add--lines-changed-only=trueto report only on the changed lines.- clang-tidy needs a
compile_commands.jsonto find your include paths and flags. Build it before the script runs and add--database=build(the directory that holds it). 'cpp-linter<2'keeps the Python package. Version 2, a rewrite in Rust, is in release candidates and changes some options.
Run it on your machine first, from a branch of your repository:
bash ci/cpp-linter.sh main
GitLab CI¶
cpp-linter:
image: python:3.13
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
GIT_DEPTH: 0
script:
- bash ci/cpp-linter.sh "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
artifacts:
when: always
paths:
- cpp-linter.md
Jenkins¶
For a multibranch pipeline, where Jenkins sets CHANGE_TARGET on pull request builds:
pipeline {
agent { docker { image 'python:3.13' } }
stages {
stage('cpp-linter') {
when { changeRequest() }
steps {
sh 'bash ci/cpp-linter.sh "$CHANGE_TARGET"'
}
}
}
post {
always {
archiveArtifacts artifacts: 'cpp-linter.md', allowEmptyArchive: true
}
}
}
Azure Pipelines¶
pr:
- main
pool:
vmImage: ubuntu-latest
steps:
- checkout: self
fetchDepth: 0
- task: UsePythonVersion@0
inputs:
versionSpec: '3.13'
- script: bash ci/cpp-linter.sh "$(System.PullRequest.targetBranchName)"
displayName: cpp-linter
condition: eq(variables['Build.Reason'], 'PullRequest')
- publish: cpp-linter.md
artifact: cpp-linter
condition: and(always(), eq(variables['Build.Reason'], 'PullRequest'))
The pr trigger works for repositories on GitHub and Bitbucket Cloud. For a repository in Azure
Repos, start the pipeline from a branch policy's build validation instead.
Bitbucket Pipelines¶
image: python:3.13
clone:
depth: full
pipelines:
pull-requests:
'**':
- step:
name: cpp-linter
script:
- bash ci/cpp-linter.sh "$BITBUCKET_PR_DESTINATION_BRANCH"
artifacts:
- cpp-linter.md
What was tested¶
The script was run as written, on Linux, with cpp-linter 1.16.0 and LLVM 21: it fails on a branch with findings and passes on a clean one. The four job definitions use each system's documented variables for the target branch, but were not run on those systems. If one does not work for you, open an issue.
Only clang-format, without Python¶
The Docker images hold the clang tools and
nothing else to install. This GitLab job checks the formatting of every source file under src:
clang-format:
image: ghcr.io/cpp-linter/clang-tools:21
script:
- find src -name '*.cpp' -o -name '*.h' | xargs -r clang-format --dry-run --Werror