Introduce clang-tidy and Lizard via PR-delta ratchet strategy

Table of Contents

This page is a capture in the inbox bucket of the product backlog — a pre-sprint idea, not yet pulled into a sprint as a story.

What

Introduce Clang-Tidy and Lizard into the CI pipeline using a ratchet strategy: both tools enforce standards only on lines or files that are new or changed in the current PR, leaving the existing codebase untouched. Technical debt is frozen in place and decreases naturally every time a developer touches a file.

The implementation has two parts:

  • Lizard (complexity: CCN, length, arguments, nesting) — use dorny/paths-filter to build the list of modified .cpp=/.hpp files and pass it to lizard --warnings_only. Nothing runs if no C++ files changed. Note: dorny/paths-filter with list-files: shell produces a space-separated list suitable for shell expansion; without that option the output is newline-separated and requires tr '\n' ' ' before passing to Lizard as arguments.
  • Clang-Tidy — use cpp-linter/cpp-linter-action with lines-changed-only: true and files-changed-only: true. The action compiles every modified file against compile_commands.json but only fails the build and posts PR comments for lines actually added or changed. A legacy file with 500 pre-existing warnings on unmodified lines passes clean.

Rollout happens in three phases:

  1. Observation (week 1–2): run both jobs with continue-on-error: true. Developers see inline PR comments without build breakage.
  2. Soft enforcement (week 3–4): remove continue-on-error; enable Lizard and Clang-Tidy readability/modernize checks as hard failures for new lines.
  3. Hard enforcement (month 2+): add bugprone-* and cppcoreguidelines-* checks.

The story task list would be: add Lizard job (with paths-filter delta guard), add Clang-Tidy job (cpp-linter-action, lines-changed-only), wire both into the pr-gate check, write the .clang-tidy config (include per-file suppressions for generated code — OreStudio generates C++ and generated files touching a PR must not trigger ratchet failures), tune thresholds, run the observation phase, flip to hard enforcement.

Why

OreStudio has a large, accumulated C++ codebase. Turning on Clang-Tidy or Lizard against the whole tree today would produce hundreds of failures, forcing a multi-week freeze to fix them before CI is green again — unacceptable while features are shipping. The ratchet approach avoids that entirely: the debt is frozen, not ignored, and shrinks with every PR. The existing clang_tidy_static_analysis capture describes the general setup; this capture records the specific safe rollout strategy needed to act on it without disrupting the team.

References

  • cpp-linter/cpp-linter-action — GitHub Action with built-in lines-changed-only support (key parameter for legacy repos).
  • dorny/paths-filter — GitHub Action; use list-files: shell to get a space-separated list directly usable as Lizard arguments.
  • Suggested Lizard thresholds: --length 150 --CCN 15 --arguments 8 --nested_level 4.

See also

  • Set up clang-tidy static analysis — general clang-tidy setup capture (CMake targets, compile_commands, nightly workflow); this capture is the how-to-introduce-it-safely companion.

Emacs 29.1 (Org mode 9.6.6)