Skip to content

ci(coverage): disable jacoco PR comments, relax overall delta threshold to 0.4%#22

Merged
bladehan1 merged 1 commit intodevelopfrom
fix/ci_coverage
Apr 23, 2026
Merged

ci(coverage): disable jacoco PR comments, relax overall delta threshold to 0.4%#22
bladehan1 merged 1 commit intodevelopfrom
fix/ci_coverage

Conversation

@bladehan1
Copy link
Copy Markdown
Owner

@bladehan1 bladehan1 commented Apr 20, 2026

What

Three targeted fixes to the coverage-gate CI job in pr-build.yml:

  1. Add comment-type: summary to both jacoco-report steps — routes output to the workflow step summary instead of PR comments.
  2. Relax MAX_DROP from -0.1% to -0.4%.

Why

Issue 1 — 403 errors on PR comment posting

The coverage-gate job declares only permissions: contents: read. The madrapps/jacoco-report action defaults to comment-type: pr_comment, which calls the GitHub PR comment API and requires pull-requests: write. Every CI run was producing a 403 error in the logs, though it did not block the gate because the action's own continue-on-error default is true.

Setting comment-type: summary makes the action write to $GITHUB_STEP_SUMMARY (a local file write, no API call), so the 403 disappears entirely without needing to grant broader token permissions.

Issue 2 — coverage-changed-files reports INSTRUCTION coverage, not LINE coverage

The value shown as Changed Files Coverage is bytecode instruction coverage, not source-line coverage. This is a fixed behavior of madrapps/jacoco-report@v1.7.2 — the action has no coverage-type parameter and internally reads only the INSTRUCTION counter from JaCoCo XML.

Why INSTRUCTION ≠ LINE and why it matters:

  • JaCoCo XML records six counter types per source file: INSTRUCTION, BRANCH, LINE, COMPLEXITY, METHOD, CLASS.
  • A single source line compiles to multiple bytecode instructions. For example, a null-check if (x != null) may emit 3–5 instructions; a fluent chain on one line may emit 10+.
  • INSTRUCTION coverage is therefore sensitive to compiler expansion: generated code (constructors, getters/setters, toString, enum boilerplate) inflates the instruction count without adding meaningful semantic coverage.
  • When a PR touches one method in a class that also has many generated accessors, the changed-file INSTRUCTION coverage can read significantly lower than the LINE coverage a reviewer would intuitively expect.
  • Concretely: the 93.3% figure visible in recent CI runs is INSTRUCTION coverage of the diff files, not line coverage.

To switch to LINE coverage the action would need to be replaced with a custom script that reads the LINE counter (<counter type="LINE" covered="N" missed="M"/>) from each matching <sourcefile> node. The action itself does not expose this as a configuration option in any released version through v1.7.2.

Issue 3 — -0.1% delta threshold causes false failures

Normal variance in test execution timing, minor refactoring (renaming, extracting constants), or adding tests to previously uncovered edge-case paths can shift overall INSTRUCTION coverage by ±0.2%. A threshold of -0.1% triggered spurious gate failures in these scenarios. -0.4% still catches real coverage regressions while eliminating the noise.

Summary by CodeRabbit

  • Chores
    • Coverage report comments in pull requests now use summary-style formatting.
    • Coverage enforcement updated to use a changed-line coverage metric (computed per-PR); pull requests will fail if changed-line coverage falls below the configured threshold.
    • Removed the previous "changed files" coverage gate and related messaging.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

The workflow now computes "changed-line coverage" using diff-cover (Python 3.11), replaces the previous "changed files" coverage metric with this single changed-line metric for the coverage gate, updates base and PR aggregation to comment-type: summary, and enforces the gate by validating and comparing CHANGED_LINE to MIN_CHANGED.

Changes

Cohort / File(s) Summary
Workflow Configuration
​.github/workflows/pr-build.yml
Added Python 3.11 + diff-cover run to compute diff-cover.json; replaced the prior "changed files" coverage input with total_percent_covered (CHANGED_LINE) as the sole changed-coverage metric; removed parsing, skip logic, and messaging for "changed files" gate; updated enforcement to validate numeric CHANGED_LINE vs MIN_CHANGED and fail with a changed-line-specific message; set comment-type: summary on both base and PR JaCoCo aggregation steps.

Sequence Diagram(s)

sequenceDiagram
  participant PR as Pull Request
  participant GH as GitHub Actions
  participant Py as Python/Runner
  participant JC as JaCoCo
  participant DC as diff-cover
  participant Gate as Coverage Gate
  participant Commenter as Commenter

  PR->>GH: Trigger workflow
  GH->>Py: Setup Python 3.11
  GH->>JC: Aggregate JaCoCo XMLs (base & PR)
  JC-->>GH: Produce JaCoCo XMLs
  GH->>DC: Run diff-cover against JaCoCo XMLs
  DC-->>GH: Emit diff-cover.json (total_percent_covered)
  GH->>Gate: Provide CHANGED_LINE, MIN_CHANGED
  Gate->>Gate: Validate numeric & compare thresholds
  alt meets threshold
    Gate-->>Commenter: Post summary comment (comment-type: summary)
  else fails threshold
    Gate-->>GH: Fail job with changed-line-specific message
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through XMLs, counted every line,
diff-cover gave a number, neat and fine.
One metric now, no files to chase,
A summary comment finds its place.
The rabbit cheers—coverage wins the race!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: disabling jacoco PR comments and relaxing the coverage delta threshold.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ci_coverage

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
.github/workflows/pr-build.yml (2)

391-391: Keep the threshold message in sync with MAX_DROP.

The hardcoded 0.4% in the failure message will drift if MAX_DROP is tuned again. Consider interpolating the variable.

Proposed fix
-            echo "Coverage gate failed: overall coverage dropped more than 0.4%."
+            echo "Coverage gate failed: overall coverage dropped more than ${MAX_DROP#-}%."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr-build.yml at line 391, The failure message currently
hardcodes "0.4%" which can go out of sync with the MAX_DROP setting; update the
echo that prints the coverage gate failure so it interpolates the MAX_DROP
variable (referencing MAX_DROP and the echo command) instead of a literal "0.4%"
so the message always reflects the configured threshold.

361-364: Minor: status string reads awkwardly with a negative threshold.

With MAX_DROP=-0.4, the summary renders as PASS (>= -0.4%) / FAIL (< -0.4%), which conflates the delta with the threshold. Consider phrasing in terms of the delta for clarity.

Proposed wording
-          OVERALL_STATUS="PASS (>= ${MAX_DROP}%)"
+          OVERALL_STATUS="PASS (delta ${DELTA}% >= ${MAX_DROP}%)"
           if [ "$DELTA_OK" -ne 1 ]; then
-            OVERALL_STATUS="FAIL (< ${MAX_DROP}%)"
+            OVERALL_STATUS="FAIL (delta ${DELTA}% < ${MAX_DROP}%)"
           fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr-build.yml around lines 361 - 364, The status message
uses the threshold variable MAX_DROP in a way that reads awkwardly when it's
negative; update the strings set to OVERALL_STATUS to phrase them in terms of
the observed delta instead of the threshold. Replace "PASS (>= ${MAX_DROP}%)"
and "FAIL (< ${MAX_DROP}%)" with clearer wording such as "PASS (delta >=
${MAX_DROP}%)" and "FAIL (delta < ${MAX_DROP}%)" (or "delta >=/ <" whatever
style you prefer), ensuring the branch that checks DELTA_OK continues to set
OVERALL_STATUS accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/pr-build.yml:
- Line 391: The failure message currently hardcodes "0.4%" which can go out of
sync with the MAX_DROP setting; update the echo that prints the coverage gate
failure so it interpolates the MAX_DROP variable (referencing MAX_DROP and the
echo command) instead of a literal "0.4%" so the message always reflects the
configured threshold.
- Around line 361-364: The status message uses the threshold variable MAX_DROP
in a way that reads awkwardly when it's negative; update the strings set to
OVERALL_STATUS to phrase them in terms of the observed delta instead of the
threshold. Replace "PASS (>= ${MAX_DROP}%)" and "FAIL (< ${MAX_DROP}%)" with
clearer wording such as "PASS (delta >= ${MAX_DROP}%)" and "FAIL (delta <
${MAX_DROP}%)" (or "delta >=/ <" whatever style you prefer), ensuring the branch
that checks DELTA_OK continues to set OVERALL_STATUS accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3ff2d486-cf3d-476b-b392-960144f1732f

📥 Commits

Reviewing files that changed from the base of the PR and between 2de63bb and a4fffea.

📒 Files selected for processing (1)
  • .github/workflows/pr-build.yml

Use diff-cover changed-line coverage as the changed-code gate, keep the overall coverage delta gate at -0.1%, and keep Jacoco reports as summary-only snapshots.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/pr-build.yml (1)

370-371: ⚠️ Potential issue | 🟠 Major

Apply the intended MAX_DROP=-0.4 relaxation.

The workflow still uses MAX_DROP=-0.1 and the failure message still says 0.1%, so the PR objective is not actually implemented.

Proposed fix
           MIN_CHANGED=60
-          MAX_DROP=-0.1
+          MAX_DROP=-0.4
           if [ "$DELTA_OK" -ne 1 ]; then
-            echo "Coverage gate failed: overall coverage dropped more than 0.1%."
+            echo "Coverage gate failed: overall coverage dropped more than 0.4%."
             echo "base=${BASE_OVERALL}% pr=${PR_OVERALL}% delta=${DELTA}%"
             exit 1
           fi

Also applies to: 441-443

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr-build.yml around lines 370 - 371, Update the workflow
to apply the intended relaxation by changing the MAX_DROP value from -0.1 to
-0.4 wherever it appears (e.g., the MIN_CHANGED/MAX_DROP assignment block and
the later occurrence around the other check), and update any corresponding
failure messages that currently say "0.1%" to "0.4%" so they reflect the new
threshold; look for the MAX_DROP identifier and the literal "0.1%" in the file
and adjust them consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/pr-build.yml:
- Around line 404-408: The comparison currently uses a strict greater-than,
causing values exactly equal to MIN_CHANGED to fail; change the compare_float
invocation(s) to use ">=" instead of ">" where CHANGED_LINE_OK is computed (and
similarly at the other occurrence around CHANGED_LINE_STATUS) so that
CHANGED_LINE == MIN_CHANGED yields PASS; update the calls that produce
CHANGED_LINE_OK (the compare_float expression involving CHANGED_LINE and
MIN_CHANGED) in both places mentioned and keep the CHANGED_LINE_STATUS logic
unchanged.
- Around line 307-321: The workflow captures diff-cover's exit code into DIFF_RC
but continues to parse diff-cover.json; change the logic after running
diff-cover (the diff-cover invocation that sets DIFF_RC) to check if DIFF_RC is
non-zero and immediately fail (exit with DIFF_RC and an error message) before
attempting to read diff-cover.json/CHANGED_LINE_COVERAGE; apply the same fix to
the other diff-cover invocation block (the second diff-cover run that also sets
DIFF_RC) so the job stops on tool/report-generation failures instead of parsing
partial/stale JSON.

---

Outside diff comments:
In @.github/workflows/pr-build.yml:
- Around line 370-371: Update the workflow to apply the intended relaxation by
changing the MAX_DROP value from -0.1 to -0.4 wherever it appears (e.g., the
MIN_CHANGED/MAX_DROP assignment block and the later occurrence around the other
check), and update any corresponding failure messages that currently say "0.1%"
to "0.4%" so they reflect the new threshold; look for the MAX_DROP identifier
and the literal "0.1%" in the file and adjust them consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 335d2e00-737e-4998-99c5-c93a3c048c1e

📥 Commits

Reviewing files that changed from the base of the PR and between a4fffea and 28f1819.

📒 Files selected for processing (1)
  • .github/workflows/pr-build.yml

Comment on lines +307 to +321
set +e
diff-cover $PR_XMLS \
--compare-branch="origin/${BASE_REF}" \
--src-roots $SRC_ROOTS \
--fail-under=0 \
--json-report=diff-cover.json \
--markdown-report=diff-cover.md
DIFF_RC=$?
set -e

CHANGED_LINE_COVERAGE=$(jq -r '.total_percent_covered // empty' diff-cover.json)
if [ -z "$CHANGED_LINE_COVERAGE" ]; then
echo "Unable to parse changed-line coverage from diff-cover.json."
exit 1
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail when diff-cover exits nonzero.

DIFF_RC is captured but only logged. With --fail-under=0, a nonzero exit should represent a tool/report-generation problem, so the gate should stop instead of parsing potentially stale or partial diff-cover.json.

Proposed fix
           DIFF_RC=$?
           set -e
+
+          if [ "$DIFF_RC" -ne 0 ]; then
+            echo "diff-cover failed with exit code: ${DIFF_RC}"
+            exit "$DIFF_RC"
+          fi
 
           CHANGED_LINE_COVERAGE=$(jq -r '.total_percent_covered // empty' diff-cover.json)

Also applies to: 334-334

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr-build.yml around lines 307 - 321, The workflow captures
diff-cover's exit code into DIFF_RC but continues to parse diff-cover.json;
change the logic after running diff-cover (the diff-cover invocation that sets
DIFF_RC) to check if DIFF_RC is non-zero and immediately fail (exit with DIFF_RC
and an error message) before attempting to read
diff-cover.json/CHANGED_LINE_COVERAGE; apply the same fix to the other
diff-cover invocation block (the second diff-cover run that also sets DIFF_RC)
so the job stops on tool/report-generation failures instead of parsing
partial/stale JSON.

Comment on lines +404 to +408
CHANGED_LINE_OK=$(compare_float "${CHANGED_LINE} > ${MIN_CHANGED}")
if [ "$CHANGED_LINE_OK" -eq 1 ]; then
CHANGED_LINE_STATUS="PASS (> ${MIN_CHANGED}%)"
else
CHANGED_LINE_STATUS="FAIL (<= ${MIN_CHANGED}%)"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use inclusive comparison for the minimum changed-line threshold.

MIN_CHANGED=60 reads as “at least 60%,” but > makes exactly 60.0% fail. Use >= unless the strict boundary is intentional.

Proposed fix
-          CHANGED_LINE_OK=$(compare_float "${CHANGED_LINE} > ${MIN_CHANGED}")
+          CHANGED_LINE_OK=$(compare_float "${CHANGED_LINE} >= ${MIN_CHANGED}")
           if [ "$CHANGED_LINE_OK" -eq 1 ]; then
-            CHANGED_LINE_STATUS="PASS (> ${MIN_CHANGED}%)"
+            CHANGED_LINE_STATUS="PASS (>= ${MIN_CHANGED}%)"
           else
-            CHANGED_LINE_STATUS="FAIL (<= ${MIN_CHANGED}%)"
+            CHANGED_LINE_STATUS="FAIL (< ${MIN_CHANGED}%)"
           fi
           if [ "$CHANGED_LINE_OK" -ne 1 ]; then
-            echo "Coverage gate failed: changed-line coverage must be > 60%."
+            echo "Coverage gate failed: changed-line coverage must be >= 60%."
             echo "changed-line=${CHANGED_LINE}%"
             exit 1
           fi

Also applies to: 447-449

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr-build.yml around lines 404 - 408, The comparison
currently uses a strict greater-than, causing values exactly equal to
MIN_CHANGED to fail; change the compare_float invocation(s) to use ">=" instead
of ">" where CHANGED_LINE_OK is computed (and similarly at the other occurrence
around CHANGED_LINE_STATUS) so that CHANGED_LINE == MIN_CHANGED yields PASS;
update the calls that produce CHANGED_LINE_OK (the compare_float expression
involving CHANGED_LINE and MIN_CHANGED) in both places mentioned and keep the
CHANGED_LINE_STATUS logic unchanged.

@bladehan1 bladehan1 merged commit cbfc520 into develop Apr 23, 2026
27 of 29 checks passed
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