From bcfe4daecc2e4003b6084114c6113c3262fc2655 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 22 May 2026 07:59:40 +0530 Subject: [PATCH] ci(coverage): gate PRs on 100% patch coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds diff-cover patch-coverage enforcement: every changed line in a PR must be covered by a test (--fail-under=100 vs origin/master). The node test runner is re-run with --enable-source-maps so the built-in lcov reporter maps coverage back to the src/*.ts sources (paths + line numbers) via the emitted .js.map files — otherwise lcov reports dist-test/*.js and the gate no-ops. Node 22 kept. New org mandate. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/coverage.yml | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ad25771..03939a2 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -15,6 +15,9 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 + with: + # Full history so diff-cover can resolve origin/. + fetch-depth: 0 - uses: actions/setup-node@v4 with: # >=22 for --test-coverage-exclude support (added 22.5.0). @@ -26,3 +29,46 @@ jobs: if: always() with: fail_ci_if_error: false + + # ------------------------------------------------------------------ + # Org patch-coverage mandate: every changed line in a PR diff must be + # covered by a test (100%). Tool: diff-cover + # (https://github.com/Bachmann1234/diff-cover). + # + # The node test runner reports coverage on the COMPILED JS in dist-test/. + # `--enable-source-maps` makes the built-in lcov reporter rewrite both + # the file paths and the line numbers back to the original TypeScript + # sources (src/*.ts) via the emitted .js.map files, so diff-cover lines + # up with the PR diff. Without it, lcov emits dist-test/src/*.js with + # JS line numbers and the gate silently no-ops. + # ------------------------------------------------------------------ + - name: Generate lcov mapped to TS sources + if: github.event_name == 'pull_request' + run: | + npm run pretest + mkdir -p coverage + node --enable-source-maps --test --experimental-test-coverage \ + --test-coverage-exclude='dist-test/test/**' \ + --test-coverage-exclude='dist/**' \ + --test-coverage-exclude='node_modules/**' \ + --test-reporter=lcov --test-reporter-destination=coverage/lcov.info \ + --test-reporter=spec --test-reporter-destination=stdout \ + dist-test/test/integration.test.js \ + dist-test/test/live-smoke.test.js \ + dist-test/test/client-unit.test.js \ + dist-test/test/index-unit.test.js \ + dist-test/test/tools-unit.test.js + - uses: actions/setup-python@v5 + if: github.event_name == 'pull_request' + with: + python-version: '3.12' + - name: Install diff-cover + if: github.event_name == 'pull_request' + run: pip install diff-cover + - name: Patch coverage gate (100% of changed lines) + if: github.event_name == 'pull_request' + run: | + git fetch origin "${{ github.base_ref }}" --depth=1 || true + diff-cover coverage/lcov.info \ + --compare-branch="origin/${{ github.base_ref }}" \ + --fail-under=100