Files
clide/ci/coverage_gate.sh
T
jpmschweitzerandClaude 1151a0ce80 install ratcheting line-coverage gate at 34% floor (T-90)
First child of T-89. Codifies "don't make coverage worse" as a
durable pre-push contract before any test-writing children land.

- pubspec.yaml: new `coverage_floor: 34` key. Single source of
  truth for the floor; ratchets up only.
- ci/coverage_gate.sh: parses coverage/lcov.info (LH/LF), reads
  the floor from pubspec.yaml, exits non-zero if integer-truncated
  measured % drops below it. Self-contained awk parser — no `lcov`
  CLI dependency.
- ci/test.sh: flutter test now runs with --coverage, so the gate
  reads fresh data without an extra test invocation. Wall time
  delta is small and stays inside the < 90 s pre-push budget
  (D-29).
- Makefile: new `coverage-gate` target wires the script in;
  `push-check` adds it as a dependency. The .githooks/pre-push
  hook (already wired) picks this up automatically.
- .gitignore: ignore /coverage/ wholesale; the floor lives in
  pubspec.yaml, nothing under coverage/ is committed.

Decision recorded as D-66 (decisions/testing.md). End target is
95%; reaching it is tracked as the rest of T-89's children.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-06 22:44:43 +02:00

51 lines
1.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Coverage gate — fails if total line coverage drops below the
# `coverage_floor:` value in pubspec.yaml. Driven by D-66.
#
# Reads coverage/lcov.info (generated by `flutter test --coverage`,
# which `ci/test.sh` runs as part of the fast suite). Parses the
# total LF/LH counts and compares the integer percentage against
# the floor. The floor only ratchets up — bumping it requires an
# explicit edit to pubspec.yaml committed alongside the test
# additions that earned the bump.
#
# Self-contained parser (awk) — does not depend on `lcov` being
# installed on the dev machine.
set -euo pipefail
cd "$(dirname "$0")/.."
LCOV=coverage/lcov.info
if [[ ! -f "$LCOV" ]]; then
echo "==> coverage gate: $LCOV missing — run \`make test\` first (it writes lcov)" >&2
exit 2
fi
floor=$(awk -F: '/^coverage_floor:/ {gsub(/ /,"",$2); print $2; exit}' pubspec.yaml)
if [[ -z "$floor" ]]; then
echo "==> coverage gate: pubspec.yaml is missing coverage_floor: — see D-66" >&2
exit 2
fi
read measured measured_int < <(
awk -F: '
/^LF:/ { lf += $2 }
/^LH:/ { lh += $2 }
END {
pct = (lh / lf) * 100
printf "%.2f %d\n", pct, int(pct)
}
' "$LCOV"
)
if (( measured_int < floor )); then
echo "==> coverage gate FAIL: ${measured}% < floor ${floor}%"
echo " Add tests, or — if the drop is intentional — explain in the commit and lower the floor explicitly."
exit 1
fi
if (( measured_int > floor )); then
echo "==> coverage gate OK: ${measured}% (floor ${floor}%) — ${measured_int}% available; consider bumping coverage/floor.txt to ${measured_int}"
else
echo "==> coverage gate OK: ${measured}% (floor ${floor}%)"
fi