Skip to content

fix(ci): align coverage scope between the gate and SonarCloud - #32

Merged
santidev21 merged 2 commits into
mainfrom
chore/align-coverage-scope
Oct 1, 2026
Merged

santidev21 merged 2 commits into
mainfrom
chore/align-coverage-scope

Conversation

@santidev21

Copy link
Copy Markdown
Owner

Problem

The CI coverage gate and SonarCloud reported very different numbers for the same repository (gate 97.4% / Sonar 36.9% on SplitIt). Investigation showed the two tools were measuring different things.

Root cause 1 — the gate was measuring generated code

coverlet included the EF Core migration scaffolding (.Designer.cs and *ModelSnapshot.cs). Those files are auto-generated and applied verbatim by the integration-test fixture, so coverlet reports them as ~100% covered, while they dominate the denominator:

Repo Gate before Scaffolding lines Gate after excluding scaffolding
SplitIt 97.4% ~17,970 / 20,190 (~89%) 76.5%
Bikontrol 88.8% ~5,450 / 6,765 (~81%) 92.7%

The gate was not above Sonar because of good coverage; it was above because of generated code. ExcludeByFile now drops only the generated Designer/snapshot files — migration Up/Down logic stays in scope, so this is a scope fix, not a threshold change.

Root cause 2 — SonarCloud counted the frontend as 0% covered

This job only runs backend .NET tests and only supplies coverage.opencover.xml. SonarCloud still analyzed the Angular frontend and the repo scripts, so every TS/JS line was counted as uncovered (SplitIt: ~1,096 lines; Bikontrol: ~989). That diluted project coverage and would have failed the new-code coverage gate on any frontend PR. sonar.coverage.exclusions now excludes the languages this job cannot measure, plus the same generated scaffolding.

What changed

  • coverlet.runsettings: exclude generated migration scaffolding from line coverage.
  • .github/workflows/sonarcloud.yml: sonar.coverage.exclusions for frontend/scripts and generated scaffolding.

No threshold was modified (SplitIt 70, Bikontrol 80).

Residual difference (documented in the master plan)

Even with both scopes aligned, the two numbers are not identical: SonarCloud measures every executable line across every backend project, while coverlet only measures sequence points in assemblies the test host actually loads (e.g. SplitIt's Application layer is not instrumented today). This is a real coverage gap that Sonar surfaces and coverlet hides; it is documented rather than papered over.

Verification

  • Ran the full suite locally with the new settings; all tests pass and the gate passes (SplitIt 76.5% ≥ 70; Bikontrol 92.7% ≥ 80).
  • No production code touched.

The coverlet gate reported 97.4% but ~89% of its denominator was EF Core migration scaffolding (.Designer.cs / ModelSnapshot), which the integration fixture applies verbatim and therefore counts as ~100% covered: the gate was effectively measuring generated code. Exclude that scaffolding (keeping migration Up/Down logic) so the line gate reflects hand-written code (now ~76.5%).

SonarCloud only receives backend opencover coverage in this job, yet it analyzed the Angular frontend and repo scripts too, counting every TS/JS line as 0% covered. That diluted the project coverage to 36.9% and would fail the new-code coverage gate on any frontend PR. Add sonar.coverage.exclusions for the languages this job cannot measure plus the same generated scaffolding.

The residual difference between the two numbers is documented in the master plan.
@sonarqubecloud

sonarqubecloud Bot commented Oct 1, 2026

Copy link
Copy Markdown

@santidev21
santidev21 merged commit 25fbe94 into main Oct 1, 2026
12 checks passed
@santidev21
santidev21 deleted the chore/align-coverage-scope branch October 1, 2026 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant