Skip to content

Commit 11506c5

Browse files
committed
fix cosmwasm flag; add auto-update mode
1 parent 9d4905e commit 11506c5

File tree

4 files changed

+207
-32
lines changed

4 files changed

+207
-32
lines changed

.coverage-baseline

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ github.com/certusone/wormhole/node/pkg/watchers/algorand 10.9
4444
# Node - Lower-priority packages (<10%)
4545
github.com/certusone/wormhole/node/pkg/watchers/sui 7.7
4646
github.com/certusone/wormhole/node/pkg/processor 6.1
47-
github.com/certusone/wormhole/node/pkg/watchers/cosmwasm 3.4
47+
github.com/certusone/wormhole/node/pkg/watchers/cosmwasm 0.0
4848

4949
# Node - Packages with no tests yet (0% - tracked to prevent future regression if tests are added)
5050
github.com/certusone/wormhole/node/pkg/random 0.0

Makefile

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,25 @@ $(BIN)/guardiand: dirs generate
5656
## Run tests with coverage for node and sdk
5757
test-coverage:
5858
@echo "Running tests with coverage for node and sdk..."
59-
@(cd node && go test -cover ./...) 2>&1 | tee coverage-node.tmp
60-
@(cd sdk && go test -cover ./...) 2>&1 | tee coverage-sdk.tmp
61-
@cat coverage-node.tmp coverage-sdk.tmp > coverage.txt
62-
@rm coverage-node.tmp coverage-sdk.tmp
59+
@(cd node && go test -cover ./...) 2>&1 | tee coverage.txt
60+
@(cd sdk && go test -cover ./...) 2>&1 | tee -a coverage.txt
6361

6462
.PHONY: check-coverage
6563
## Check coverage against baseline (run tests first)
6664
check-coverage: test-coverage
6765
@./coverage-check
6866

67+
.PHONY: check-coverage-verbose
68+
## Check coverage against baseline (run tests first)
69+
check-coverage-verbose: test-coverage
70+
@./coverage-check -v
71+
6972
.PHONY: build-coverage-check
7073
## Build the coverage checker tool
7174
build-coverage-check:
7275
@cd scripts/coverage-check && go build -o ../../coverage-check .
76+
77+
.PHONY: update-coverage-baseline
78+
## Update coverage baseline with current coverage
79+
update-coverage-baseline: test-coverage
80+
@./coverage-check -u

scripts/coverage-check/README.md

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,13 @@ The tool runs automatically in GitHub Actions (`.github/workflows/build.yml`):
8787

8888
## Common Scenarios
8989

90-
### Scenario 1: Adding tests to an existing package
90+
### 💡 Scenario 1: Adding tests to an existing package
9191

9292
```
9393
# Before: pkg/foo has 50% coverage in baseline
9494
# You add tests and coverage goes to 55%
95-
Result: ✅ PASS (improvement is allowed)
95+
Result: 💡 Coverage improved! Update baseline with: make update-coverage-baseline
96+
Exit code: 1 (forces you to update)
9697
```
9798
9899
### ❌ Scenario 2: Coverage drops accidentally
@@ -109,8 +110,8 @@ Fix: Add tests to restore coverage to ≥50%
109110
```
110111
# Before: pkg/foo has 50% coverage in baseline
111112
# You remove dead code, coverage drops to 48%
112-
Result: ❌ FAIL initially
113-
Fix: Update baseline file to 48.0 and commit with explanation
113+
Result: ❌ FAIL - coverage regression
114+
Fix: Run `make update-coverage-baseline` and commit with explanation
114115
```
115116
116117
### ❌ Scenario 4: New package without tests
@@ -121,12 +122,13 @@ Result: ❌ FAIL - new package has 0% coverage (minimum: 10%)
121122
Fix: Add basic tests to reach ≥10% coverage
122123
```
123124
124-
### Scenario 5: New package with basic tests
125+
### 💡 Scenario 5: New package with basic tests
125126
126127
```
127128
# You add pkg/newfeature/ with 15% test coverage
128-
Result: ✅ PASS - meets 10% minimum
129-
Note: Once merged, 15% becomes the new baseline for this package
129+
Result: 💡 New package detected! Update baseline with: make update-coverage-baseline
130+
Exit code: 1 (forces you to add to baseline)
131+
Note: After update, 15% becomes the baseline for this package
130132
```
131133
132134
### ✅ Scenario 6: Adding cmd/ or hack/ code
@@ -140,14 +142,23 @@ Result: ✅ PASS - cmd/ packages are excluded from checks
140142
141143
### When to Update
142144
143-
Update the baseline when:
144-
1. You **intentionally** reduce coverage (e.g., removing dead code)
145-
2. You refactor and temporarily need lower coverage (with a plan to improve)
146-
3. A package is removed or renamed
145+
The tool will **require** you to update the baseline when:
146+
1. You **improve** coverage (tool exits with code 1, forces update to lock in gains)
147+
2. You add a new package with tests (tool exits with code 1, forces adding to baseline)
148+
3. You **intentionally** reduce coverage (e.g., removing dead code)
147149
148150
### How to Update
149151
150-
Edit `node/.coverage-baseline`:
152+
**Automatic way (recommended):**
153+
```bash
154+
make update-coverage-baseline
155+
# Or: ./coverage-check -u
156+
```
157+
158+
This updates the baseline file automatically while preserving comments and structure.
159+
160+
**Manual way (if needed):**
161+
Edit `.coverage-baseline` directly:
151162

152163
```bash
153164
# Lower the threshold for a specific package
@@ -194,11 +205,15 @@ const (
194205
### Command-line Flags
195206

196207
```bash
197-
./coverage-check # Quiet mode (only shows failures)
198-
./coverage-check -v # Verbose mode (shows all checks)
199-
./coverage-check --verbose # Same as -v
208+
./coverage-check # Quiet mode (only shows failures and improvements)
209+
./coverage-check -v # Verbose mode (shows all checks)
210+
./coverage-check --verbose # Same as -v
211+
./coverage-check -u # Update baseline with current coverage
212+
./coverage-check --update # Same as -u
200213
```
201214

215+
**Important**: The tool will exit with code 1 if coverage improved, prompting you to update the baseline. This is intentional - it forces you to lock in improvements!
216+
202217
**Note**: The tool expects `coverage.txt` at repo root. Generate it with:
203218
```bash
204219
make test-coverage

scripts/coverage-check/main.go

Lines changed: 164 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,22 @@ type packageCoverage struct {
3030
coverage float64
3131
}
3232

33-
var verbose bool
33+
type improvement struct {
34+
name string
35+
baseline float64
36+
current float64
37+
}
38+
39+
var (
40+
verbose bool
41+
updateBaseline bool
42+
)
3443

3544
func main() {
3645
flag.BoolVar(&verbose, "v", false, "verbose output (show all checks)")
3746
flag.BoolVar(&verbose, "verbose", false, "verbose output (show all checks)")
47+
flag.BoolVar(&updateBaseline, "u", false, "update baseline with current coverage")
48+
flag.BoolVar(&updateBaseline, "update", false, "update baseline with current coverage")
3849
flag.Parse()
3950

4051
if err := run(); err != nil {
@@ -69,11 +80,26 @@ func run() error {
6980
return fmt.Errorf("failed to load baseline: %w", err)
7081
}
7182

72-
// Check baseline packages for regression
73-
passed, regressions := checkBaseline(baseline, currentCoverage)
83+
// Check baseline packages for regression and track improvements
84+
passed, regressions, improvements, improvementList := checkBaseline(baseline, currentCoverage)
7485

7586
// Check new packages
76-
newPassed, newFailed := checkNewPackages(baseline, currentCoverage)
87+
newPassed, newFailed, newPackages := checkNewPackages(baseline, currentCoverage)
88+
89+
// Handle update flag
90+
if updateBaseline {
91+
if err := writeUpdatedBaseline(baseline, currentCoverage, newPackages); err != nil {
92+
return fmt.Errorf("failed to update baseline: %w", err)
93+
}
94+
fmt.Printf("%s✅ Baseline updated successfully%s\n", colorGreen, colorReset)
95+
if improvements > 0 {
96+
fmt.Printf(" %d package(s) improved\n", improvements)
97+
}
98+
if len(newPackages) > 0 {
99+
fmt.Printf(" %d new package(s) added\n", len(newPackages))
100+
}
101+
return nil
102+
}
77103

78104
// Summary
79105
if verbose {
@@ -84,6 +110,9 @@ func run() error {
84110
fmt.Printf("Baseline packages checked: %d\n", passed+regressions)
85111
fmt.Printf(" - Passed: %d\n", passed)
86112
fmt.Printf(" - Regressions: %d\n", regressions)
113+
if improvements > 0 {
114+
fmt.Printf(" - Improvements: %d\n", improvements)
115+
}
87116
fmt.Printf("New packages checked: %d\n", newPassed+newFailed)
88117
if newPassed+newFailed > 0 {
89118
fmt.Printf(" - Passed: %d\n", newPassed)
@@ -92,9 +121,9 @@ func run() error {
92121
fmt.Println()
93122
}
94123

124+
// Check for failures (regressions or new packages below threshold)
95125
if regressions > 0 || newFailed > 0 {
96126
if !verbose {
97-
// In quiet mode, print a brief summary of what failed
98127
fmt.Printf("%s❌ Coverage check FAILED%s\n", colorRed, colorReset)
99128
if regressions > 0 {
100129
fmt.Printf(" %d package(s) regressed below baseline\n", regressions)
@@ -110,12 +139,35 @@ func run() error {
110139
fmt.Println("To fix:")
111140
fmt.Println(" 1. Add tests to improve coverage for failing packages")
112141
fmt.Println(" 2. If coverage drop is intentional, update baseline:")
113-
fmt.Println(" - Edit node/.coverage-baseline")
114-
fmt.Println(" - Lower the threshold for the affected package")
142+
fmt.Println(" - Run: make update-coverage-baseline")
143+
fmt.Println(" - Or: ./coverage-check -u")
115144
}
116145
return fmt.Errorf("coverage check failed")
117146
}
118147

148+
// Check for improvements - exit with code 1 to force baseline update
149+
if improvements > 0 || len(newPackages) > 0 {
150+
fmt.Printf("%s💡 Coverage improved!%s\n", colorYellow, colorReset)
151+
if improvements > 0 {
152+
fmt.Printf(" %d package(s) have better coverage than baseline:\n", improvements)
153+
for _, pkg := range improvementList {
154+
fmt.Printf(" - %s: %.1f%% → %.1f%%\n", pkg.name, pkg.baseline, pkg.current)
155+
}
156+
}
157+
if len(newPackages) > 0 {
158+
fmt.Printf(" %d new package(s) with coverage:\n", len(newPackages))
159+
for _, pkg := range newPackages {
160+
fmt.Printf(" - %s: %.1f%%\n", pkg.name, pkg.coverage)
161+
}
162+
}
163+
fmt.Println()
164+
fmt.Printf("%sPlease update the baseline to lock in these improvements:%s\n", colorYellow, colorReset)
165+
fmt.Println(" Run: make update-coverage-baseline")
166+
fmt.Println(" Or: ./coverage-check -u")
167+
return fmt.Errorf("baseline update required")
168+
}
169+
170+
// All checks passed, no improvements
119171
if verbose {
120172
fmt.Printf("%s✅ All coverage checks PASSED%s\n", colorGreen, colorReset)
121173
}
@@ -202,7 +254,7 @@ func loadBaseline() (map[string]float64, error) {
202254
}
203255

204256
// checkBaseline compares current coverage against baseline
205-
func checkBaseline(baseline, current map[string]float64) (passed, regressions int) {
257+
func checkBaseline(baseline, current map[string]float64) (passed, regressions, improvements int, improvementList []improvement) {
206258
if verbose {
207259
fmt.Println("Checking baseline packages for regression...")
208260
fmt.Println("--------------------------------------------")
@@ -228,6 +280,19 @@ func checkBaseline(baseline, current map[string]float64) (passed, regressions in
228280
fmt.Printf("%s Coverage dropped from %.1f%% to %.1f%%%s\n",
229281
colorRed, baselineCov, currentCov, colorReset)
230282
regressions++
283+
} else if currentCov > baselineCov+coverageTolerance {
284+
// Coverage improved
285+
if verbose {
286+
fmt.Printf("%s📈 %s: %.1f%% (baseline: %.1f%%, +%.1f%%)%s\n",
287+
colorGreen, pkg, currentCov, baselineCov, currentCov-baselineCov, colorReset)
288+
}
289+
improvements++
290+
improvementList = append(improvementList, improvement{
291+
name: pkg,
292+
baseline: baselineCov,
293+
current: currentCov,
294+
})
295+
passed++
231296
} else {
232297
if verbose {
233298
fmt.Printf("%s✅ %s: %.1f%% (baseline: %.1f%%)%s\n",
@@ -239,15 +304,19 @@ func checkBaseline(baseline, current map[string]float64) (passed, regressions in
239304

240305
if verbose {
241306
fmt.Println()
242-
fmt.Printf("Baseline check: %d passed, %d regressions\n", passed, regressions)
307+
fmt.Printf("Baseline check: %d passed, %d regressions", passed, regressions)
308+
if improvements > 0 {
309+
fmt.Printf(", %d improvements", improvements)
310+
}
311+
fmt.Println()
243312
fmt.Println()
244313
}
245314

246-
return passed, regressions
315+
return passed, regressions, improvements, improvementList
247316
}
248317

249318
// checkNewPackages checks that new packages meet minimum coverage requirements
250-
func checkNewPackages(baseline, current map[string]float64) (passed, failed int) {
319+
func checkNewPackages(baseline, current map[string]float64) (passed, failed int, newPackages []packageCoverage) {
251320
if verbose {
252321
fmt.Println("Checking new packages for minimum coverage...")
253322
fmt.Println("----------------------------------------------")
@@ -279,6 +348,10 @@ func checkNewPackages(baseline, current map[string]float64) (passed, failed int)
279348
fmt.Printf("%s✅ NEW PACKAGE: %s has %.1f%% coverage (meets %.1f%% minimum)%s\n",
280349
colorGreen, pkg, cov, minNewPkgCoverage, colorReset)
281350
}
351+
newPackages = append(newPackages, packageCoverage{
352+
name: pkg,
353+
coverage: cov,
354+
})
282355
passed++
283356
}
284357
}
@@ -287,7 +360,7 @@ func checkNewPackages(baseline, current map[string]float64) (passed, failed int)
287360
fmt.Println("No new packages found")
288361
}
289362

290-
return passed, failed
363+
return passed, failed, newPackages
291364
}
292365

293366
// shouldExclude determines if a package should be excluded from new package checks
@@ -318,3 +391,82 @@ func shouldExclude(pkg string) bool {
318391

319392
return false
320393
}
394+
395+
// writeUpdatedBaseline writes an updated baseline file with current coverage
396+
func writeUpdatedBaseline(baseline, current map[string]float64, newPackages []packageCoverage) error {
397+
// Read the original baseline to preserve comments and structure
398+
originalFile, err := os.Open(baselineFile)
399+
if err != nil {
400+
return err
401+
}
402+
defer originalFile.Close()
403+
404+
// Create a temporary file in the same directory as the baseline to avoid cross-device link issues
405+
tempFile, err := os.CreateTemp(".", ".coverage-baseline-*.tmp")
406+
if err != nil {
407+
return err
408+
}
409+
defer os.Remove(tempFile.Name())
410+
411+
writer := bufio.NewWriter(tempFile)
412+
scanner := bufio.NewScanner(originalFile)
413+
414+
// Track which packages we've updated
415+
updated := make(map[string]bool)
416+
417+
// Process existing baseline file, updating coverage values
418+
for scanner.Scan() {
419+
line := scanner.Text()
420+
trimmed := strings.TrimSpace(line)
421+
422+
// Preserve comments and empty lines
423+
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
424+
fmt.Fprintln(writer, line)
425+
continue
426+
}
427+
428+
// Parse package line
429+
parts := strings.Fields(trimmed)
430+
if len(parts) != 2 {
431+
// Invalid format, keep as-is
432+
fmt.Fprintln(writer, line)
433+
continue
434+
}
435+
436+
pkg := parts[0]
437+
if currentCov, exists := current[pkg]; exists {
438+
// Update with current coverage
439+
fmt.Fprintf(writer, "%s %.1f\n", pkg, currentCov)
440+
updated[pkg] = true
441+
} else {
442+
// Package not found in current run, keep baseline value (might be removed/renamed)
443+
fmt.Fprintln(writer, line)
444+
}
445+
}
446+
447+
if err := scanner.Err(); err != nil {
448+
return err
449+
}
450+
451+
// Add new packages if any
452+
if len(newPackages) > 0 {
453+
fmt.Fprintln(writer, "")
454+
fmt.Fprintln(writer, "# Newly added packages")
455+
for _, pkg := range newPackages {
456+
fmt.Fprintf(writer, "%s %.1f\n", pkg.name, pkg.coverage)
457+
updated[pkg.name] = true
458+
}
459+
}
460+
461+
if err := writer.Flush(); err != nil {
462+
return err
463+
}
464+
tempFile.Close()
465+
466+
// Replace original file with updated file
467+
if err := os.Rename(tempFile.Name(), baselineFile); err != nil {
468+
return err
469+
}
470+
471+
return nil
472+
}

0 commit comments

Comments
 (0)