From 286ceface812c4971d2326bb749d69c2c7f27096 Mon Sep 17 00:00:00 2001 From: Jessica Janiuk Date: Sun, 2 Aug 2026 10:21:34 -0700 Subject: [PATCH] Add code coverage checks to CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instruments the native env with --coverage (gcc/clang gcov flags). PlatformIO's build_flags only reach the compile step, not the link step, so a small extra_scripts hook appends --coverage to LINKFLAGS too — otherwise the gcov runtime symbols are undefined at link time. CI now runs gcovr against src/ (excluding main.cpp, which is Arduino-only and can't run on native) after the unit tests, prints a summary to the job summary, and fails the job if line coverage drops below 90%. No external service/account needed. Also documents the coverage bar in CLAUDE.md so future changes keep it in mind rather than lowering the threshold to unblock a PR. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 15 ++++++++++++++- CLAUDE.md | 1 + platformio.ini | 2 ++ scripts/native_coverage_linkflags.py | 5 +++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 scripts/native_coverage_linkflags.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d45167d..c7a47eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,11 +25,24 @@ jobs: key: ${{ runner.os }}-platformio-native-${{ hashFiles('platformio.ini') }} - name: Install PlatformIO - run: pip install --upgrade platformio + run: pip install --upgrade platformio gcovr - name: Run native unit tests run: pio test -e native + - name: Coverage report + run: | + output=$(gcovr --root . --filter 'src/' --exclude 'src/main\.cpp' --print-summary --fail-under-line 90) + status=$? + { + echo '### Coverage (src/, excluding main.cpp)' + echo '```' + echo "$output" + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + echo "$output" + exit $status + kb2040-build: runs-on: ubuntu-latest steps: diff --git a/CLAUDE.md b/CLAUDE.md index abc7d07..30a786b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,6 +6,7 @@ - All new logic should have unit tests in `test/` to prevent regressions. - Tests run on the native PlatformIO environment (no hardware required) — keep them that way. Do not introduce test dependencies that require Arduino or physical hardware. - When fixing a bug, add a test that would have caught it. +- CI enforces a minimum line-coverage threshold (via `gcovr`, currently 90%) on `src/`, excluding `main.cpp` (Arduino-only, can't run on native). Keep new logic covered well enough to not drop below that bar — don't lower the threshold in `.github/workflows/ci.yml` just to unblock a PR; that's a deliberate call for a human to make. **Bug fixes and regression test** - Any time you fix a bug, that bugfix should be covered by a new regression test. diff --git a/platformio.ini b/platformio.ini index df15e20..9cc2b93 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,3 +29,5 @@ platform = native test_build_src = yes build_src_filter = +<*> - test_framework = unity +build_flags = --coverage +extra_scripts = pre:scripts/native_coverage_linkflags.py diff --git a/scripts/native_coverage_linkflags.py b/scripts/native_coverage_linkflags.py new file mode 100644 index 0000000..13f4326 --- /dev/null +++ b/scripts/native_coverage_linkflags.py @@ -0,0 +1,5 @@ +Import("env") + +# PlatformIO's `build_flags` only reach the compile step for --coverage; the +# link step needs it too so the gcov/profiling runtime gets linked in. +env.Append(LINKFLAGS=["--coverage"])