@@ -303,31 +303,84 @@ jobs:
303303 title : ' ## PR Code Coverage Report'
304304 update-comment : false
305305
306- - name : Coverage summary
307- run : |
308- echo "Base Overall Coverage: ${{ steps.jacoco-base.outputs.coverage-overall }}"
309- echo "PR Overall Coverage: ${{ steps.jacoco-pr.outputs.coverage-overall }}"
310- echo "PR Changed Files Coverage: ${{ steps.jacoco-pr.outputs.coverage-changed-files }}"
311-
312306 - name : Enforce coverage gates
313307 run : |
308+ set -euo pipefail
309+
310+ MIN_CHANGED=60
311+ MAX_DROP=-0.02
312+
314313 sanitize() {
315314 echo "$1" | tr -d ' %'
316315 }
316+ is_number() {
317+ [[ "$1" =~ ^-?[0-9]+([.][0-9]+)?$ ]]
318+ }
319+ compare_float() {
320+ # Usage: compare_float "<expr>"
321+ # Example: compare_float "1.2 >= -0.02"
322+ awk "BEGIN { if ($1) print 1; else print 0 }"
323+ }
317324
325+ # 1) Parse metrics from jacoco-report outputs
318326 BASE_OVERALL="$(sanitize "${{ steps.jacoco-base.outputs.coverage-overall }}")"
319327 PR_OVERALL="$(sanitize "${{ steps.jacoco-pr.outputs.coverage-overall }}")"
320328 PR_CHANGED="$(sanitize "${{ steps.jacoco-pr.outputs.coverage-changed-files }}")"
321329
322- if [ -z "$BASE_OVERALL" ] || [ -z "$PR_OVERALL" ] ; then
323- echo "Failed to parse overall coverage values."
330+ if ! is_number "$BASE_OVERALL" || ! is_number "$PR_OVERALL"; then
331+ echo "Failed to parse coverage values: base='${BASE_OVERALL}', pr='${PR_OVERALL}' ."
324332 exit 1
325333 fi
326334
335+ # 2) Compare metrics against thresholds
327336 DELTA=$(awk -v pr="$PR_OVERALL" -v base="$BASE_OVERALL" 'BEGIN { printf "%.4f", pr - base }')
328- echo "Coverage delta (PR - base): ${DELTA}%"
337+ DELTA_OK=$(compare_float "${DELTA} >= ${MAX_DROP}")
338+
339+ CHANGED_STATUS="SKIPPED (no changed coverage value)"
340+ CHANGED_OK=1
341+ if [ -n "$PR_CHANGED" ] && [ "$PR_CHANGED" != "NaN" ]; then
342+ if ! is_number "$PR_CHANGED"; then
343+ echo "Failed to parse changed-files coverage: changed='${PR_CHANGED}'."
344+ exit 1
345+ fi
346+ CHANGED_OK=$(compare_float "${PR_CHANGED} > ${MIN_CHANGED}")
347+ if [ "$CHANGED_OK" -eq 1 ]; then
348+ CHANGED_STATUS="PASS (> ${MIN_CHANGED}%)"
349+ else
350+ CHANGED_STATUS="FAIL (<= ${MIN_CHANGED}%)"
351+ fi
352+ fi
353+
354+ # 3) Output base metrics (always visible in logs + step summary)
355+ OVERALL_STATUS="PASS (>= ${MAX_DROP}%)"
356+ if [ "$DELTA_OK" -ne 1 ]; then
357+ OVERALL_STATUS="FAIL (< ${MAX_DROP}%)"
358+ fi
329359
330- DELTA_OK=$(awk -v d="$DELTA" 'BEGIN { if (d >= -0.02) print 1; else print 0 }')
360+ METRICS_TEXT=$(cat <<EOF
361+ Changed Files Coverage: ${PR_CHANGED}%
362+ PR Overall Coverage: ${PR_OVERALL}%
363+ Base Overall Coverage: ${BASE_OVERALL}%
364+ Delta (PR - Base): ${DELTA}%
365+ Changed Files Gate: ${CHANGED_STATUS}
366+ Overall Delta Gate: ${OVERALL_STATUS}
367+ EOF
368+ )
369+
370+ echo "$METRICS_TEXT"
371+
372+ {
373+ echo "### Coverage Gate Metrics"
374+ echo ""
375+ echo "- Changed Files Coverage: ${PR_CHANGED}%"
376+ echo "- PR Overall Coverage: ${PR_OVERALL}%"
377+ echo "- Base Overall Coverage: ${BASE_OVERALL}%"
378+ echo "- Delta (PR - Base): ${DELTA}%"
379+ echo "- Changed Files Gate: ${CHANGED_STATUS}"
380+ echo "- Overall Delta Gate: ${OVERALL_STATUS}"
381+ } >> "$GITHUB_STEP_SUMMARY"
382+
383+ # 4) Decide CI pass/fail
331384 if [ "$DELTA_OK" -ne 1 ]; then
332385 echo "Coverage gate failed: overall coverage dropped more than 0.02%."
333386 echo "base=${BASE_OVERALL}% pr=${PR_OVERALL}% delta=${DELTA}%"
@@ -339,7 +392,6 @@ jobs:
339392 exit 0
340393 fi
341394
342- CHANGED_OK=$(awk -v c="$PR_CHANGED" 'BEGIN { if (c > 60) print 1; else print 0 }')
343395 if [ "$CHANGED_OK" -ne 1 ]; then
344396 echo "Coverage gate failed: changed files coverage must be > 60%."
345397 echo "changed=${PR_CHANGED}%"
0 commit comments