From d64249a43d485c9ff8b02d88887cfd53e787d8b6 Mon Sep 17 00:00:00 2001 From: Juan Sugg Date: Thu, 2 Jul 2026 19:48:23 -0300 Subject: [PATCH] ci: summarize coverage gate --- .github/workflows/quality.yml | 24 ++++++++++++++++++- .../quality-node-compat.contract.spec.ts | 20 +++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 26ad1f6..ee8a5cd 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -209,7 +209,29 @@ jobs: cache-version: v1 - name: Enforce critical and global coverage thresholds - run: npm run test:coverage + run: | + set -o pipefail + mkdir -p coverage + npm run test:coverage 2>&1 | tee coverage/coverage-gate.log + + - name: Summarize coverage gate + if: always() + run: | + { + echo "### Coverage gate" + echo + echo "Command: \`npm run test:coverage\`" + echo + echo "Critical-module and global coverage thresholds are enforced by this required job." + echo + echo "\`\`\`text" + if [ -f coverage/coverage-gate.log ]; then + tail -n 120 coverage/coverage-gate.log + else + echo "coverage/coverage-gate.log was not created." + fi + echo "\`\`\`" + } >> "$GITHUB_STEP_SUMMARY" mutation-baseline: name: Mutation Baseline (Advisory) diff --git a/tests/suites/contracts/workflows/quality-node-compat.contract.spec.ts b/tests/suites/contracts/workflows/quality-node-compat.contract.spec.ts index cc2d9e0..e6f469d 100644 --- a/tests/suites/contracts/workflows/quality-node-compat.contract.spec.ts +++ b/tests/suites/contracts/workflows/quality-node-compat.contract.spec.ts @@ -97,9 +97,23 @@ describe('quality workflow Node compatibility contract', () => { expect(setupNodeStep.uses).toBe(lockedInstallActionPath); expect(setupNodeStep.with.get('node-version')).toBe('22'); expect(setupNodeStep.with.get('cache-namespace')).toBe('coverage'); - expect( - getWorkflowStep(coverageJob, 'Enforce critical and global coverage thresholds').run, - ).toBe('npm run test:coverage'); + expectTextIncludes( + getWorkflowStep(coverageJob, 'Enforce critical and global coverage thresholds').run ?? '', + { + text: 'npm run test:coverage 2>&1 | tee coverage/coverage-gate.log', + rationale: 'Coverage gate must preserve threshold output for actionable job summaries.', + }, + ); + const summaryStep = getWorkflowStep(coverageJob, 'Summarize coverage gate'); + expect(summaryStep.if).toBe('always()'); + expectTextIncludes(summaryStep.run ?? '', { + text: 'GITHUB_STEP_SUMMARY', + rationale: 'Coverage gate must publish a summary even after threshold failures.', + }); + expectTextIncludes(summaryStep.run ?? '', { + text: 'coverage/coverage-gate.log', + rationale: 'Coverage summary must identify the module/floor output that failed.', + }); }); it('makes Redis integration and guarded self-heal proof mandatory in quality gates', () => {