diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 715520b..3830694 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,10 @@ jobs: - run: pnpm install --frozen-lockfile - run: pnpm test:unit:coverage + - name: Coverage summary + if: always() + run: bash scripts/coverage-summary.sh "Unit Test Coverage" coverage/unit/coverage-summary.json + - uses: actions/upload-artifact@v4 if: always() with: @@ -103,6 +107,10 @@ jobs: if: always() run: npx nyc report + - name: Coverage summary + if: always() + run: bash scripts/coverage-summary.sh "E2E Test Coverage" coverage/e2e/coverage-summary.json + - uses: actions/upload-artifact@v4 if: always() with: diff --git a/scripts/coverage-summary.sh b/scripts/coverage-summary.sh new file mode 100755 index 0000000..779d2e3 --- /dev/null +++ b/scripts/coverage-summary.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Writes a coverage summary table to $GITHUB_STEP_SUMMARY (or stdout if not in CI). +# Usage: scripts/coverage-summary.sh <json-summary-path> +set -euo pipefail + +TITLE="${1:?Usage: coverage-summary.sh <title> <json-summary-path>}" +JSON="${2:?Usage: coverage-summary.sh <title> <json-summary-path>}" + +if [ ! -f "$JSON" ]; then + echo "Coverage summary not found: $JSON" >&2 + exit 0 +fi + +# Resolve to absolute path for require() +ABS_JSON="$(cd "$(dirname "$JSON")" && pwd)/$(basename "$JSON")" + +# Extract totals with node (available in CI, no jq dependency) +read -r stmts branches funcs lines < <(node -e " + const s = require('$ABS_JSON').total; + console.log(s.statements.pct, s.branches.pct, s.functions.pct, s.lines.pct); +") + +TABLE="## $TITLE + +| Metric | Coverage | +|--------|----------| +| Statements | ${stmts}% | +| Branches | ${branches}% | +| Functions | ${funcs}% | +| Lines | ${lines}% | +" + +if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then + echo "$TABLE" >> "$GITHUB_STEP_SUMMARY" +else + echo "$TABLE" +fi