clang-format changed under you: ubuntu-latest is now Ubuntu 26.04
If your clang-format CI check started failing on lines nobody touched, and your workflow says
runs-on: ubuntu-latest, the code probably didn't change. The formatter did.
Guides to running clang-format and clang-tidy with cpp-linter.
If your clang-format CI check started failing on lines nobody touched, and your workflow says
runs-on: ubuntu-latest, the code probably didn't change. The formatter did.
Running clang-tidy once on a laptop is easy. Running it on every pull request is where projects get stuck: clang-tidy needs the real compile flags or it reports missing headers, the first run on an existing code base produces thousands of findings nobody asked for, and the output ends up in a CI log that contributors do not open.
With the GitHub Actions job below, clang-tidy findings appear as review comments on the lines a pull request changed, and the check turns red when something is left unfixed.
Formatting comments are the cheapest part of a code review to get rid of. A pre-commit hook runs clang-format on the files in each commit, so badly formatted code rarely reaches a pull request, and CI stops failing for a missing space.
With the pre-commit framework, nobody on the team has to install LLVM, and everyone gets the same clang-format version.
A common C++ workflow on GitHub has two lint jobs that grew up separately: a format check that fails the build, and a clang-tidy job that posts review comments. They pin different clang versions, they run on different triggers, and when one of them starts flaking nobody remembers why it was configured that way. Both jobs can be one cpp-linter-action step.
A pull request fails the format check. The author runs clang-format -i locally, pushes, and it
fails again with a different diff. Nothing is wrong with the code. The laptop has clang-format 18,
CI installed 21 from a package repository last week, and the reviewer's editor plugin ships 19.
Every major LLVM release changes clang-format's output in small ways: new style options, changed
defaults, fixed bugs. clang-tidy is worse, because new checks appear and old ones move between
categories. Pinning the project version of a linter wrapper does not help if the wrapper pulls
whatever clang happens to be around.