22
33This project uses automated coverage checks to prevent test coverage from decreasing.
44
5- ## How It Works: Two-Phase Automated Protection
5+ ## How It Works: Dual Validation
66
7- This system uses two GitHub Actions workflows that work together to enforce coverage without manual maintenance:
7+ Developers run coverage locally and commit the baseline file. CI validates both that the developer ran coverage correctly AND that coverage didn't decrease.
88
9- ### Phase 1: PR Check (` .github/workflows/coverage.yml ` )
9+ ### Coverage Workflow (` .github/workflows/coverage.yml ` )
1010** Triggers:** Every pull request to main
1111
1212** What it does:**
13- 1 . Fetches ` coverage- baseline.json ` from ** main branch** (not PR branch)
14- 2 . Runs ` npm run coverage ` on PR code to generate fresh coverage
15- 3 . Compares PR coverage against main's baseline
16- 4 . ** Result :**
17- - ❌ Blocks merge if coverage drops below baseline
18- - ✅ Passes if coverage maintained or improved
19- - Shows detailed comparison in CI output
20-
21- ** Security: ** Developers cannot cheat by modifying the baseline file in their PR because CI always fetches the baseline from the main branch.
22-
23- ### Phase 2: Auto-Update ( ` .github/workflows/update- baseline.yml ` )
24- ** Triggers: ** Every push to main (after PR merge )
25-
26- ** What it does :**
27- 1 . Runs ` npm run coverage` on the new main branch code
28- 2 . Updates ` coverage-baseline.json ` with the new coverage values
29- 3 . Commits the updated baseline automatically (only if coverage changed)
30- 4 . Uses ` github-actions[bot] ` for the commit
31-
32- ** Result: ** The baseline automatically tracks the current coverage on main, requiring zero manual maintenance.
13+ 1 . ** Fetches baseline from main branch** - the current production baseline
14+ 2 . ** Reads baseline from PR branch ** - the baseline you committed
15+ 3 . ** Runs coverage fresh in CI ** - generates actual coverage from your code
16+ 4 . ** Performs two validations :**
17+
18+ ** Validation 1: Did you run coverage locally? **
19+ - ✅ ** PASS ** if ` CI coverage === PR baseline ` (you ran coverage correctly)
20+ - ❌ ** FAIL ** if ` CI coverage !== PR baseline ` (you forgot to run coverage or tampered with file)
21+
22+ ** Validation 2: Did coverage decrease? **
23+ - ✅ ** PASS ** if ` CI coverage >= main baseline` (coverage maintained or improved )
24+ - ❌ ** FAIL ** if ` CI coverage < main baseline ` (coverage decreased )
25+
26+ ** Security Model :**
27+ - ✅ ** Can't skip running coverage** - CI checks if your committed baseline matches actual coverage
28+ - ✅ ** Can't decrease coverage** - CI checks if your coverage is below main's baseline
29+ - ✅ ** Can't cheat ** - CI regenerates coverage fresh and validates against both baselines
30+ - ✅ ** Can't commit invalid baseline ** - CI validates JSON format before processing
31+ - ✅ ** Can't skip baseline file ** - CI fails immediately if baseline file is missing
32+ - ✅ ** Visible in PR ** - Baseline changes are visible in the PR diff
3333
3434---
3535
36- ** Combined Effect:** Coverage can only go up or stay the same, never down! This creates a "ratchet effect" where quality continuously improves. ✅
36+ ** Effect:** Coverage can only go up or stay the same, never down! This creates a "ratchet effect" where quality continuously improves. ✅
3737
3838## Commands
3939
@@ -52,25 +52,40 @@ npm run coverage:update-baseline
5252
5353### For Developers
5454
55- When working on a PR:
56- 1 . Run ` npm run coverage ` to generate coverage report
57- 2 . Run ` npm run coverage:check ` to verify you maintained coverage
58- 3 . If check fails, add more tests until it passes
55+ ** IMPORTANT:** You must run coverage locally and commit the baseline file with your PR.
56+
57+ ** Step-by-step:**
58+ 1 . Make your code changes
59+ 2 . Run coverage locally:
60+ ``` bash
61+ npm run coverage
62+ ```
63+ 3 . Update the baseline file:
64+ ``` bash
65+ npm run coverage:update-baseline
66+ ```
67+ 4 . Commit the baseline file:
68+ ``` bash
69+ git add coverage-baseline.json
70+ git commit -m " chore: update coverage baseline"
71+ ```
72+ 5 . Push your PR
73+
74+ ** What CI validates:**
75+ - ✅ ** Check 1:** Your committed baseline matches CI coverage (proves you ran coverage)
76+ - ✅ ** Check 2:** Your coverage is >= main's baseline (proves coverage didn't drop)
77+
78+ ** If CI fails:**
79+ - ** "No coverage-baseline.json found in PR"** → You forgot to commit the baseline file. Run steps 2-4 above and push.
80+ - ** "coverage-baseline.json is not valid JSON"** → The baseline file is corrupted. Run ` npm run coverage:update-baseline ` and commit.
81+ - ** "CI coverage doesn't match PR baseline"** → You forgot to update the baseline. Run steps 2-3 above and push.
82+ - ** "Coverage decreased"** → Add more tests to maintain or improve coverage.
5983
6084### For Maintainers
6185
62- ** No manual work needed!** Phase 2 automatically:
63- - Runs coverage after each merge to main
64- - Updates ` coverage-baseline.json `
65- - Commits the new baseline
86+ ** No special maintenance needed!** Developers commit their own baseline files.
6687
67- You can manually update baseline if needed:
68- ``` bash
69- npm run coverage:update-baseline
70- git add coverage-baseline.json
71- git commit -m " chore: update coverage baseline"
72- git push
73- ```
88+ The workflow only validates - it doesn't modify anything. When a PR merges, the updated baseline goes to main automatically.
7489
7590## Current Coverage
7691
@@ -86,10 +101,12 @@ Current baseline (as of initial setup):
86101- Uses Hardhat's built-in coverage tool (generates ` coverage/lcov.info ` )
87102- Parses LCOV format to extract: lines, functions, branches, statements
88103- Stores baseline in ` coverage-baseline.json ` at repository root
89- - Script: ` scripts/check-coverage.ts `
104+ - Scripts:
105+ - ` scripts/check-coverage.ts ` - Local validation (compares coverage against baseline)
106+ - ` scripts/get-coverage-percentage.ts ` - Extracts coverage percentage from lcov.info (used by CI)
90107
91108### Environment Setup for CI
92- Both workflows copy ` .env.example ` to ` .env ` to enable fork tests with public RPC endpoints during coverage runs.
109+ The workflow copies ` .env.example ` to ` .env ` to enable fork tests with public RPC endpoints during coverage runs.
93110
94111### Branch Protection
95112To enforce coverage checks, enable branch protection on main:
0 commit comments