mirror of
https://github.com/renorris/openfsd
synced 2026-08-13 13:05:41 +08:00
Move pure file-shaped types and ParseAPT/ParseAIR into stdlib-only pkg/twrfiles. sweatbox keeps type aliases and thin wrappers so callers need minimal renames. Export IsWordName for taxi validation.
95 lines
2.9 KiB
Bash
Executable File
95 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Fail if overall statement coverage (excluding cmd/) is below the floor.
|
|
# Also enforces pure-package hard floors (see AGENTS.md §8).
|
|
#
|
|
# Usage: scripts/check-coverage.sh [overall_floor_percent]
|
|
# Default overall floor: 80
|
|
#
|
|
# Hard floors (fail CI):
|
|
# pkg/protocol ≥98, pkg/twrfiles ≥98, internal/geo ≥98, internal/auth ≥95,
|
|
# internal/postoffice ≥90, internal/sweatbox ≥95
|
|
# Soft / reported only:
|
|
# internal/web ≥80, overall aspirational 90
|
|
set -euo pipefail
|
|
|
|
FLOOR="${1:-80}"
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
COVER_OUT="$(mktemp)"
|
|
trap 'rm -f "$COVER_OUT"' EXIT
|
|
|
|
# shellcheck disable=SC2046
|
|
go test -coverprofile="$COVER_OUT" $(go list ./... | grep -v '/cmd/')
|
|
|
|
TOTAL_LINE="$(go tool cover -func="$COVER_OUT" | tail -1)"
|
|
echo "coverage total line: $TOTAL_LINE"
|
|
|
|
# Statement-weighted package + overall floors from cover.out
|
|
python3 - "$COVER_OUT" "$FLOOR" <<'PY'
|
|
import re, sys
|
|
from collections import defaultdict
|
|
|
|
cover_out, overall_floor = sys.argv[1], float(sys.argv[2])
|
|
stmts = defaultdict(lambda: [0, 0]) # pkg -> [total, covered]
|
|
with open(cover_out) as f:
|
|
next(f)
|
|
for line in f:
|
|
line = line.strip()
|
|
m = re.match(r"(.+):(\d+)\.(\d+),(\d+)\.(\d+) (\d+) (\d+)", line)
|
|
if not m:
|
|
continue
|
|
path = m.group(1)
|
|
nstmt, count = int(m.group(6)), int(m.group(7))
|
|
if "/openfsd/" in path:
|
|
rel = path.split("/openfsd/", 1)[1]
|
|
else:
|
|
rel = path
|
|
pkg = "/".join(rel.split("/")[:-1]) # drop filename
|
|
stmts[pkg][0] += nstmt
|
|
if count > 0:
|
|
stmts[pkg][1] += nstmt
|
|
|
|
hard = {
|
|
"pkg/protocol": 98.0,
|
|
"pkg/twrfiles": 98.0,
|
|
"internal/geo": 98.0,
|
|
"internal/auth": 95.0,
|
|
"internal/postoffice": 90.0,
|
|
"internal/sweatbox": 95.0,
|
|
}
|
|
soft = {
|
|
"internal/web": 80.0, # aspirational PE-era floor; report only
|
|
}
|
|
|
|
failed = False
|
|
print("--- package floors ---")
|
|
for pkg, floor in sorted(hard.items()):
|
|
t, c = stmts.get(pkg, [0, 0])
|
|
pct = 100.0 * c / t if t else 0.0
|
|
status = "OK" if pct + 1e-9 >= floor else "FAIL"
|
|
print(f"{status}: {pkg} {pct:.1f}% (floor {floor:.0f}%, {c}/{t})")
|
|
if status == "FAIL":
|
|
failed = True
|
|
|
|
for pkg, floor in sorted(soft.items()):
|
|
t, c = stmts.get(pkg, [0, 0])
|
|
pct = 100.0 * c / t if t else 0.0
|
|
note = "meets" if pct + 1e-9 >= floor else "below (soft)"
|
|
print(f"SOFT: {pkg} {pct:.1f}% (aspirational {floor:.0f}%, {note}, {c}/{t})")
|
|
|
|
total_t = sum(v[0] for v in stmts.values())
|
|
total_c = sum(v[1] for v in stmts.values())
|
|
overall = 100.0 * total_c / total_t if total_t else 0.0
|
|
print("--- overall ---")
|
|
print(f"overall {overall:.1f}% (floor {overall_floor:.0f}%, aspirational 90%)")
|
|
if overall + 1e-9 < overall_floor:
|
|
print(f"FAIL: coverage {overall:.1f}% < floor {overall_floor:.0f}%", file=sys.stderr)
|
|
failed = True
|
|
else:
|
|
print(f"OK: coverage {overall:.1f}% >= floor {overall_floor:.0f}%")
|
|
|
|
if failed:
|
|
sys.exit(1)
|
|
PY
|