chore(pre-commit): run lint, typecheck and coverage as one parallel gate
The hook ran `pnpm test`, the whole coverage suite, and the agent flow in AGENTS.md ran that same suite again before committing: one commit verified identical content twice, about 45s of it. `pnpm run check` (scripts/check.sh) runs lint, typecheck and coverage concurrently, prints each tool's complete output (also kept in .tmp/check-logs) and fails when any of them does. A green run fingerprints the worktree into .tmp/check.stamp, so the hook skips the suite for content that just passed; any tracked or untracked edit, or a stamp older than an hour (gitignored inputs like lib/ and node_modules can drift unseen), re-runs it, and `--full` always does. The hook gains lint and typecheck at no extra wall time: 3.2s and 1.4s hide inside the 23s test run. .gitignore now lists the local tool state (.codegraph, .idea, .zcode): it is not a gate input, and its churn would otherwise invalidate every stamp. Verified: green gate on 146 files / 2305 tests, hook skip in 0.1s, full re-run after any edit, and a stubbed failing tool exits 1 without stamping.
This commit is contained in:
1 parent
d9d3868dc4
commit
e0b42ee6a7
5 files changed
+94
-5
No files matched your search
@@ -33,6 +33,12 @@ yarn-error.log*
|
||||
.pnpm-store/
|
||||
.tmp/
|
||||
|
||||
# Local tool state: CodeGraph index, IDE, agent tooling. They are not gate
|
||||
# inputs, and their churn would otherwise invalidate the pre-commit stamp.
|
||||
.codegraph/
|
||||
.idea/
|
||||
.zcode/
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
pnpm test
|
||||
pnpm run check
|
||||
@@ -42,10 +42,8 @@ Complete ALL of these before ANY commit:
|
||||
- Review the full diff independently: every change necessary, correct, and not over-engineered.
|
||||
- Clean up generated temporary files and temporary or unhelpful comments.
|
||||
- Load the [code-review](https://github.com/mattpocock/skills/tree/main/skills/engineering/code-review) skill if available, run it to review all the changes, and independently verify or follow each of its suggestions when its multi-axis analysis done.
|
||||
- Run the following commands concurrently for maximum efficiency
|
||||
- First, run `pnpm run lint` to fix all lint errors.
|
||||
- Second, run `pnpm run typecheck` to fix all type errors.
|
||||
- Third, run `pnpm run coverage` to run and ensure 100% per-file coverage. Please capture the ALL content of the full output without truncation or tailing.
|
||||
- Run `pnpm run check`: it runs `pnpm run lint`, `pnpm run typecheck` and `pnpm run coverage` concurrently, prints each tool's COMPLETE output, and fails when any of them does (the same logs stay in `.tmp/check-logs/`).
|
||||
- Fix every lint and type error, and ensure 100% per-file coverage. Please capture the ALL content of the full output without truncation or tailing.
|
||||
- Example for per-file 100% coverage output:
|
||||
```
|
||||
% Coverage report from v8
|
||||
@@ -54,6 +52,7 @@ Complete ALL of these before ANY commit:
|
||||
-------------------------|---------|----------|---------|---------|-------------------
|
||||
-------------------------|---------|----------|---------|---------|-------------------
|
||||
```
|
||||
- The `pre-commit` hook runs this same gate, and a green run stamps the worktree into `.tmp/check.stamp`, so a commit of unchanged content skips it; `pnpm run check --full` forces a full re-run.
|
||||
|
||||
## Layout & responsive
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"build": "tsdown",
|
||||
"lint": "oxlint",
|
||||
"lint:fix": "oxlint --fix",
|
||||
"check": "bash scripts/check.sh",
|
||||
"watch": "bash scripts/watch.sh",
|
||||
"web": "bash scripts/web.sh",
|
||||
"register": "bash scripts/register.sh",
|
||||
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# The pre-commit gate: lint, typecheck and the full coverage suite, run
|
||||
# concurrently, each tool's complete output kept in .tmp/check-logs.
|
||||
#
|
||||
# A green run fingerprints the worktree into .tmp/check.stamp, so the husky
|
||||
# hook skips the full suite for content that just passed. Any tracked or
|
||||
# untracked edit invalidates the stamp, and so does a stamp older than an hour:
|
||||
# gitignored inputs (lib/, node_modules, staged dsh baselines) can drift without
|
||||
# changing the fingerprint. `--full` always re-runs.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
STAMP=".tmp/check.stamp"
|
||||
LOGS=".tmp/check-logs"
|
||||
INDEX=".tmp/check-index"
|
||||
STAMP_TTL_MIN=60
|
||||
|
||||
# The fingerprint is the worktree's tree object, built through a THROWAWAY
|
||||
# index: staged and unstaged edits plus untracked files all count, while
|
||||
# gitignored outputs (.tmp, coverage, lib, node_modules, IDE/tool state) do not.
|
||||
fingerprint() {
|
||||
local tree
|
||||
mkdir -p .tmp
|
||||
rm -f "$INDEX"
|
||||
if ! GIT_INDEX_FILE="$INDEX" git add -A -- . >/dev/null; then
|
||||
rm -f "$INDEX"
|
||||
return 1
|
||||
fi
|
||||
tree="$(GIT_INDEX_FILE="$INDEX" git write-tree)" || tree=""
|
||||
rm -f "$INDEX"
|
||||
[[ -n "$tree" ]] || return 1
|
||||
printf '%s\n' "$tree"
|
||||
}
|
||||
|
||||
FULL=0
|
||||
[[ "${1:-}" == "--full" ]] && FULL=1
|
||||
|
||||
# Command substitutions do not inherit errexit on bash 3.2 (macOS), so both
|
||||
# fingerprint calls check their status explicitly.
|
||||
BEFORE="$(fingerprint)" || { echo "==> check: cannot fingerprint the worktree" >&2; exit 1; }
|
||||
if (( FULL == 0 )) && [[ -f "$STAMP" ]] && [[ "$(cat "$STAMP")" == "$BEFORE" ]] \
|
||||
&& [[ -n "$(find "$STAMP" -mmin "-$STAMP_TTL_MIN" 2>/dev/null)" ]]; then
|
||||
echo "==> check: worktree unchanged since the last green gate — skipping. Run 'pnpm run check --full' to force a full run."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -rf "$LOGS"
|
||||
mkdir -p "$LOGS"
|
||||
|
||||
echo "==> check: lint, typecheck and coverage in parallel"
|
||||
pnpm run lint >"$LOGS/lint.log" 2>&1 & LINT=$!
|
||||
pnpm run typecheck >"$LOGS/typecheck.log" 2>&1 & TYPECHECK=$!
|
||||
pnpm run coverage >"$LOGS/coverage.log" 2>&1 & COVERAGE=$!
|
||||
|
||||
FAILED=""
|
||||
wait "$LINT" || FAILED="$FAILED lint"
|
||||
wait "$TYPECHECK" || FAILED="$FAILED typecheck"
|
||||
wait "$COVERAGE" || FAILED="$FAILED coverage"
|
||||
|
||||
for name in lint typecheck coverage; do
|
||||
echo
|
||||
echo "===== $name ====="
|
||||
cat "$LOGS/$name.log"
|
||||
done
|
||||
|
||||
echo
|
||||
if [[ -n "$FAILED" ]]; then
|
||||
echo "==> check FAILED:$FAILED" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# A gate run over a moving worktree proves nothing, so an edit during the run
|
||||
# must not be stamped as verified.
|
||||
AFTER="$(fingerprint)" || { echo "==> check: cannot fingerprint the worktree" >&2; exit 1; }
|
||||
if [[ "$BEFORE" != "$AFTER" ]]; then
|
||||
echo "==> check: the worktree changed while the gate ran — re-run before committing." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '%s\n' "$BEFORE" > "$STAMP"
|
||||
echo "==> check passed: lint, typecheck and 100% per-file coverage (lint/typecheck/coverage output above; logs in $LOGS)"
|
||||
Reference in new issue
Block a user