The repo configured four frontend gates and enforced one of them. eslint
and prettier ran in no workflow and no hook; `bun run check` ran only in
build-release.yml, so a type error could sit on master until somebody cut
a tag; and `bun run test:coverage` had been dead for months.
CI (build-and-test.yml) now runs format:check, lint, check and coverage
alongside the existing boundary and doc-link tripwires.
The coverage script failure was a version mismatch, not a config problem:
@vitest/coverage-v8 resolved to 4.1.10, whose peer range pins vitest
exactly, while package.json asked for ">=1.0.0 <5.0.0" and got 4.0.16 --
every run died on a missing BaseCoverageProvider export. The loose range
is what allowed the pair to drift, so it is now ^4.1.10.
Two ratchets, same policy as MIN_THRESHOLD in traceability-check.yml:
eslint --max-warnings=159 (0 errors; 159 is today's backlog, only
ever lower it)
vitest thresholds (statements 51 / branches 45 /
functions 46 / lines 52, measured at
54.6 / 48.7 / 49.6 / 55.1)
no-console is promoted from "off" to "error": the logger-facade
migration it was waiting on is finished -- 8 calls remained, 2 of them
real stragglers in the settings page, now on the facade the file already
imported. The sink itself, tests, and scripts/ are exempted; a CLI whose
stdout is the product is not a stray debug statement.
The threshold was verified to bite by raising it to 99 and watching the
run go red, not by assuming an unfailed gate works.
DR-205 moves to Done; the coverage gate is DR-215.
94 lines
3.2 KiB
Bash
Executable File
94 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# JellyTau pre-commit hook — the fast half of CLAUDE.md's "Before Committing"
|
|
# list, enforced instead of remembered.
|
|
#
|
|
# TRACES: | DR-207
|
|
#
|
|
# Install with: bun run hooks:install (sets core.hooksPath=scripts/hooks)
|
|
# Skip once with: git commit --no-verify
|
|
#
|
|
# What runs here is deliberately limited to gates that finish in seconds:
|
|
#
|
|
# bun run check svelte-check (types)
|
|
# bun run test vitest, single pass
|
|
# scripts/check-frontend-boundary.sh domain-taxonomy tripwire (DR-094)
|
|
# bun run format:check prettier
|
|
# bun run lint --max-warnings=N eslint, warning-count ratchet
|
|
# cargo fmt --all -- --check only when src-tauri/ is staged
|
|
#
|
|
# NOT here, on purpose: `cargo clippy` and `cargo test`. Both take minutes on a
|
|
# cold target dir, which turns every commit into a coffee break and trains
|
|
# people to reach for --no-verify. CI (.gitea/workflows/build-and-test.yml) is
|
|
# where those run; `bun run test:all` is the local equivalent.
|
|
|
|
set -uo pipefail
|
|
|
|
# Merge and rebase commits carry someone else's changes, and conflict resolution
|
|
# is exactly when a slow gate is least welcome. Let them through — CI still
|
|
# gates the merge result.
|
|
GIT_DIR_PATH="$(git rev-parse --git-dir 2>/dev/null)" || exit 0
|
|
if [ -e "$GIT_DIR_PATH/MERGE_HEAD" ] ||
|
|
[ -d "$GIT_DIR_PATH/rebase-merge" ] ||
|
|
[ -d "$GIT_DIR_PATH/rebase-apply" ] ||
|
|
[ -e "$GIT_DIR_PATH/CHERRY_PICK_HEAD" ]; then
|
|
echo "pre-commit: merge/rebase in progress — skipping checks (CI still gates the result)."
|
|
exit 0
|
|
fi
|
|
|
|
# Nothing staged (e.g. `git commit --amend` that only edits the message): nothing
|
|
# to check.
|
|
STAGED="$(git diff --cached --name-only --diff-filter=ACMR)"
|
|
if [ -z "$STAGED" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
cd "$REPO_ROOT" || exit 1
|
|
|
|
FAILED=0
|
|
|
|
run_gate() {
|
|
label="$1"
|
|
shift
|
|
echo ""
|
|
echo "🔎 pre-commit: $label"
|
|
if ! "$@"; then
|
|
echo "❌ pre-commit: $label failed"
|
|
FAILED=1
|
|
fi
|
|
}
|
|
|
|
run_gate "svelte-check (bun run check)" bun run check
|
|
run_gate "frontend tests (bun run test)" bun run test
|
|
run_gate "frontend/backend boundary" bash scripts/check-frontend-boundary.sh
|
|
run_gate "formatting (bun run format:check)" bun run format:check
|
|
# Same ratchet as the CI step in build-and-test.yml — keep the two numbers equal,
|
|
# or a commit passes here and fails there.
|
|
run_gate "lint (bun run lint)" bun run lint --max-warnings=159
|
|
|
|
# rustfmt only matters when Rust actually changed, and `cargo fmt --check` is
|
|
# cheap (no compilation) whenever it does.
|
|
if printf '%s\n' "$STAGED" | grep -q '^src-tauri/'; then
|
|
if command -v cargo >/dev/null 2>&1; then
|
|
echo ""
|
|
echo "🔎 pre-commit: rustfmt (src-tauri/ is staged)"
|
|
if ! (cd src-tauri && cargo fmt --all -- --check); then
|
|
echo "❌ pre-commit: cargo fmt --all -- --check failed"
|
|
echo " fix with: cd src-tauri && cargo fmt"
|
|
FAILED=1
|
|
fi
|
|
else
|
|
echo "⚠️ pre-commit: src-tauri/ staged but cargo is not on PATH — skipping rustfmt."
|
|
fi
|
|
fi
|
|
|
|
if [ "$FAILED" -ne 0 ]; then
|
|
echo ""
|
|
echo "🛑 pre-commit checks failed. Fix them, or bypass deliberately with:"
|
|
echo " git commit --no-verify"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo "✅ pre-commit checks passed."
|