ci-pipeline-cleanup Phase 10: coverage PR-comment action

Bundle: ci-pipeline-cleanup, Phase 10 / frozen decision 0.9.

Self-hosted alternative to Codecov / Coveralls. Posts a per-package
coverage delta as a PR comment on every PR; updates the same comment
in place on subsequent pushes (avoids duplicate noise).

scripts/ci-guards/coverage-pr-comment.sh:
- Reads coverage.out from the prior Go Test step
- Builds per-package coverage table (mirrors check-coverage-thresholds
  averaging logic)
- Searches existing PR comments for the '**Coverage report' marker
  and PATCHes the existing one if found, else POSTs a new one
- No-op on non-PR builds (push to master, scheduled, etc.)

Wired into go-build-and-test job after 'Upload Coverage Report' step
with if: github.event_name == 'pull_request' guard.

Operator can swap to Codecov/Coveralls later by replacing this script
+ step with a third-party action — the YAML manifest at
.github/coverage-thresholds.yml stays unchanged either way.
This commit is contained in:
shankar0123
2026-04-30 20:51:48 +00:00
parent 19a5e438f2
commit 3a69600c2c
2 changed files with 101 additions and 0 deletions
+11
View File
@@ -124,6 +124,17 @@ jobs:
path: coverage.out
retention-days: 30
- name: Coverage PR comment
# ci-pipeline-cleanup Phase 10 / frozen decision 0.9: self-hosted
# alternative to Codecov / Coveralls. Posts a per-package coverage
# delta as a PR comment; updates in place on subsequent pushes.
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.number }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: bash scripts/ci-guards/coverage-pr-comment.sh
# Bundle P / Strengthening #6 — QA-doc drift guards. Forces every PR
# that adds a Part to docs/testing-guide.md OR a seed row to
# migrations/seed_demo.sql to keep docs/qa-test-guide.md in sync. This
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
# scripts/ci-guards/coverage-pr-comment.sh
#
# Post a per-package coverage table as a PR comment on every PR.
# Self-hosted alternative to Codecov / Coveralls (per ci-pipeline-cleanup
# bundle Phase 10 / frozen decision 0.9).
#
# Reads coverage.out from the Go Test step. Updates an existing comment
# in place if one already exists (avoids duplicate noise on subsequent
# pushes to the same PR).
#
# Required env:
# GH_TOKEN — secrets.GITHUB_TOKEN
# PR_NUMBER — github.event.number
# GITHUB_REPOSITORY — github.repository (owner/name)
set -e
if [ -z "$PR_NUMBER" ]; then
echo "PR_NUMBER not set — not a PR build, skipping coverage comment."
exit 0
fi
if [ -z "$GH_TOKEN" ]; then
echo "::warning::GH_TOKEN not set — cannot post coverage comment"
exit 0
fi
if [ ! -f coverage.out ]; then
echo "::warning::coverage.out not found — skipping coverage comment"
exit 0
fi
# Build per-package summary table (mirrors check-coverage-thresholds.sh logic).
table=$(go tool cover -func=coverage.out | awk '
/internal\// {
pkg = $1
sub(/\/[^\/]+\.go:.*$/, "", pkg)
cov = $NF
sub(/%/, "", cov)
sum[pkg] += cov + 0
n[pkg]++
}
END {
for (pkg in sum) printf "| `%s` | %.1f%% |\n", pkg, sum[pkg] / n[pkg]
}
' | sort)
total=$(go tool cover -func=coverage.out | tail -1 | awk '{print $NF}')
body="**Coverage report (HEAD)**
| package | coverage |
|---|---:|
| **TOTAL** | **${total}** |
${table}
_Per-package floors enforced by \`scripts/check-coverage-thresholds.sh\`._
_Generated by \`scripts/ci-guards/coverage-pr-comment.sh\` (ci-pipeline-cleanup Phase 10)._"
# Find existing comment created by this script (starts with the marker).
api="https://api.github.com/repos/${GITHUB_REPOSITORY}"
existing_id=$(curl -sS \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"$api/issues/$PR_NUMBER/comments?per_page=100" \
| python3 -c "
import sys, json
comments = json.load(sys.stdin)
for c in comments:
if c['body'].startswith('**Coverage report'):
print(c['id'])
break
")
if [ -n "$existing_id" ]; then
curl -sS -X PATCH \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"$api/issues/comments/$existing_id" \
-d "$(python3 -c "import json,sys; print(json.dumps({'body': open('/dev/stdin').read()}))" <<< "$body")" \
> /dev/null
echo "Updated existing coverage comment #$existing_id on PR #$PR_NUMBER"
else
curl -sS -X POST \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"$api/issues/$PR_NUMBER/comments" \
-d "$(python3 -c "import json,sys; print(json.dumps({'body': open('/dev/stdin').read()}))" <<< "$body")" \
> /dev/null
echo "Created new coverage comment on PR #$PR_NUMBER"
fi