Skip to content

Commit 468d1cf

Browse files
imeoerbergwolf
authored andcommitted
fix(ci): collect correct changed lines coverage
Fixed the issue where changed lines coverage could not be obtained. Signed-off-by: imeoer <yansong.ys@antgroup.com>
1 parent 32d6d08 commit 468d1cf

File tree

3 files changed

+73
-20
lines changed

3 files changed

+73
-20
lines changed

.github/workflows/coverage-comment.yml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ on:
1313
types: [completed]
1414

1515
permissions:
16+
actions: read
1617
contents: read
1718
pull-requests: write # needed to create / update the comment
1819

@@ -26,22 +27,41 @@ jobs:
2627
github.event.workflow_run.conclusion == 'failure')
2728
steps:
2829
- name: Download coverage artifacts
30+
id: download
31+
continue-on-error: true
2932
uses: actions/download-artifact@v4
3033
with:
3134
name: coverage-report
35+
path: coverage-artifact
3236
github-token: ${{ secrets.GITHUB_TOKEN }}
3337
# Download from the triggering workflow run, not the current one.
3438
run-id: ${{ github.event.workflow_run.id }}
3539

3640
- name: Read PR number
3741
id: pr
3842
run: |
39-
if [ -f pr-number.txt ]; then
40-
echo "number=$(cat pr-number.txt)" >> "$GITHUB_OUTPUT"
43+
if [ -f coverage-artifact/pr-number.txt ]; then
44+
echo "number=$(cat coverage-artifact/pr-number.txt)" >> "$GITHUB_OUTPUT"
45+
elif [ -n "${{ github.event.workflow_run.pull_requests[0].number }}" ]; then
46+
echo "number=${{ github.event.workflow_run.pull_requests[0].number }}" >> "$GITHUB_OUTPUT"
4147
else
4248
echo "number=" >> "$GITHUB_OUTPUT"
4349
fi
4450
51+
- name: Prepare coverage comment body
52+
run: |
53+
if [ -f coverage-artifact/coverage-report.md ]; then
54+
cp coverage-artifact/coverage-report.md coverage-report.md
55+
else
56+
printf '%s\n' \
57+
'## 📊 Code Coverage Report' \
58+
'' \
59+
'Coverage workflow concluded with **${{ github.event.workflow_run.conclusion }}**, but no coverage report artifact was available.' \
60+
'' \
61+
'Triggering workflow run: ${{ github.event.workflow_run.html_url }}' \
62+
> coverage-report.md
63+
fi
64+
4565
- name: Post coverage comment on PR
4666
if: steps.pr.outputs.number != ''
4767
uses: marocchino/sticky-pull-request-comment@v2

.github/workflows/coverage.yml

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ jobs:
5454
- name: Convert to Cobertura XML
5555
run: gocover-cobertura < coverage.out > coverage.xml
5656

57+
- name: Normalize Cobertura paths for diff-cover
58+
run: |
59+
MODULE_PATH=$(go list -m)
60+
python3 -c "from pathlib import Path; import sys; module = sys.argv[1].rstrip('/') + '/'; path = Path('coverage.xml'); path.write_text(path.read_text(encoding='utf-8').replace(f'filename=\"{module}', 'filename=\"'), encoding='utf-8')" "$MODULE_PATH"
61+
5762
- name: Install diff-cover
5863
run: pip install diff-cover
5964

@@ -84,15 +89,32 @@ jobs:
8489
BASE=origin/${{ github.base_ref }}
8590
DIFF_OUTPUT=$(diff-cover coverage.xml \
8691
--compare-branch="${BASE}" \
92+
--format json:diff-cover.json \
8793
--fail-under=${{ env.THRESHOLD_DIFF }} \
8894
2>&1) && DIFF_EXIT=0 || DIFF_EXIT=$?
8995
90-
DIFF_PCT=$(echo "$DIFF_OUTPUT" | grep -oP 'Diff coverage is \K[0-9.]+' || echo "N/A")
96+
if [ -f diff-cover.json ]; then
97+
DIFF_PCT=$(python3 -c "import json; report=json.load(open('diff-cover.json', encoding='utf-8')); num_changed_lines=report.get('num_changed_lines', 0); total_num_lines=report.get('total_num_lines', 0); total_percent_covered=report.get('total_percent_covered', 'N/A'); print('N/A' if num_changed_lines > 0 and total_num_lines == 0 else total_percent_covered)")
98+
else
99+
DIFF_PCT="N/A"
100+
fi
101+
102+
if [ "$DIFF_PCT" = "N/A" ]; then
103+
DIFF_DISPLAY="N/A"
104+
else
105+
DIFF_DISPLAY="${DIFF_PCT}%"
106+
fi
107+
91108
echo "diff_pct=${DIFF_PCT}" >> "$GITHUB_OUTPUT"
109+
echo "diff_display=${DIFF_DISPLAY}" >> "$GITHUB_OUTPUT"
92110
echo "$DIFF_OUTPUT"
93111
94-
if [ "$DIFF_EXIT" -ne 0 ]; then
112+
if [ "$DIFF_EXIT" -ne 0 ] || [ "$DIFF_PCT" = "N/A" ]; then
95113
echo "diff_status=fail" >> "$GITHUB_OUTPUT"
114+
115+
if [ "$DIFF_PCT" = "N/A" ]; then
116+
echo "❌ Changed-line coverage could not be computed because diff-cover found changed lines without matching coverage information."
117+
fi
96118
else
97119
echo "diff_status=pass" >> "$GITHUB_OUTPUT"
98120
fi
@@ -106,31 +128,38 @@ jobs:
106128
107129
TOTAL="${{ steps.total_coverage.outputs.total }}"
108130
STATUS="${{ steps.total_coverage.outputs.status }}"
131+
[ -n "$TOTAL" ] || TOTAL="N/A"
109132
[ "$STATUS" = "pass" ] && ICON="✅" || ICON="❌"
110133
111134
echo "| Metric | Coverage | Threshold | Status |"
112135
echo "|--------|----------|-----------|--------|"
113136
echo "| Overall | **${TOTAL}%** | ${{ env.THRESHOLD_TOTAL }}% | ${ICON} |"
114137
115138
if [ "${{ github.event_name }}" = "pull_request" ]; then
116-
DIFF_PCT="${{ steps.diff_coverage.outputs.diff_pct }}"
139+
DIFF_DISPLAY="${{ steps.diff_coverage.outputs.diff_display }}"
117140
DIFF_STATUS="${{ steps.diff_coverage.outputs.diff_status }}"
141+
[ -n "$DIFF_DISPLAY" ] || DIFF_DISPLAY="N/A"
118142
[ "$DIFF_STATUS" = "pass" ] && DIFF_ICON="✅" || DIFF_ICON="❌"
119-
echo "| Changed lines | **${DIFF_PCT}%** | ${{ env.THRESHOLD_DIFF }}% | ${DIFF_ICON} |"
143+
echo "| Changed lines | **${DIFF_DISPLAY}** | ${{ env.THRESHOLD_DIFF }}% | ${DIFF_ICON} |"
120144
fi
121145
122-
echo ""
123-
echo "<details>"
124-
echo "<summary>📦 Per-package breakdown</summary>"
125-
echo ""
126-
echo '```'
127-
go tool cover -func=coverage.out | grep -v "^total:" | \
128-
awk '{printf "%-80s %s\n", $1, $3}' | sort
129-
echo ""
130-
go tool cover -func=coverage.out | grep "^total:"
131-
echo '```'
132-
echo ""
133-
echo "</details>"
146+
if [ -f coverage.out ]; then
147+
echo ""
148+
echo "<details>"
149+
echo "<summary>📦 Per-package breakdown</summary>"
150+
echo ""
151+
echo '```'
152+
go tool cover -func=coverage.out | grep -v "^total:" | \
153+
awk '{printf "%-80s %s\n", $1, $3}' | sort
154+
echo ""
155+
go tool cover -func=coverage.out | grep "^total:"
156+
echo '```'
157+
echo ""
158+
echo "</details>"
159+
else
160+
echo ""
161+
echo "Coverage artifacts were not generated because the workflow failed before coverage collection completed."
162+
fi
134163
} > coverage-report.md
135164
136165
# ── Write step summary ────────────────────────────────────────────────
@@ -150,8 +179,10 @@ jobs:
150179
path: |
151180
coverage.out
152181
coverage.xml
182+
diff-cover.json
153183
coverage-report.md
154184
pr-number.txt
185+
if-no-files-found: warn
155186
retention-days: 14
156187

157188
- name: Upload coverage to Codecov
@@ -176,6 +207,6 @@ jobs:
176207
github.event_name == 'pull_request' &&
177208
steps.diff_coverage.outputs.diff_status == 'fail'
178209
run: |
179-
echo "❌ Changed-line coverage ${{ steps.diff_coverage.outputs.diff_pct }}% is below the required ${{ env.THRESHOLD_DIFF }}%"
210+
echo "❌ Changed-line coverage ${{ steps.diff_coverage.outputs.diff_display }} is below the required ${{ env.THRESHOLD_DIFF }}%"
180211
exit 1
181212

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ test-coverage-ci:
5656
$(eval PKGS := $(shell go list -tags disable_libgit2 ./pkg/... | grep -v pkg/server))
5757
$(eval COVERPKG := $(shell go list -tags disable_libgit2 ./pkg/... | grep -v pkg/server | tr '\n' ',' | sed 's/,$$//'))
5858
@go test -tags disable_libgit2 -race \
59-
-coverprofile=coverage.out \
59+
-coverprofile=coverage.raw.out \
6060
-coverpkg=$(COVERPKG) \
6161
-covermode=atomic \
6262
-timeout 10m \
6363
$(PKGS)
64+
@awk 'NR == 1 { print; next } { key = $$1 " " $$2; count[key] += $$3; if (!(key in seen)) { seen[key] = 1; order[++n] = key } } END { for (i = 1; i <= n; i++) print order[i], count[order[i]] }' coverage.raw.out > coverage.out
65+
@rm -f coverage.raw.out
6466
@echo "Coverage report generated: coverage.out"

0 commit comments

Comments
 (0)