Skip to content

Commit 066ae70

Browse files
committed
chore: expand pre-commit/pre-push hooks and document them
Pre-commit: - Trailing newline check (exactly one at EOF; skip binaries) - Conditional Rust (fmt/clippy/test only when Rust files staged) - Web: lint + tsc + npm test when web/ staged - Shellcheck when scripts/ or .githooks/ change Pre-push: - Version sync (Cargo.toml vs git tags) - cargo audit when installed - Full web: npm ci && build && test Docs: CLAUDE.md Development section; README Local Development Checks expanded. Made-with: Cursor
1 parent a60fc02 commit 066ae70

File tree

4 files changed

+68
-12
lines changed

4 files changed

+68
-12
lines changed

.githooks/pre-commit

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ cd "$repo_root"
77
staged="$(git diff --cached --name-only)"
88

99
# Reject merge conflict markers in staged files
10-
conflicts_file=""
1110
if [ -n "$staged" ]; then
1211
conflicts_file="$(mktemp)"
1312
echo "$staged" | while IFS= read -r f; do
@@ -22,19 +21,51 @@ if [ -n "$staged" ]; then
2221
rm -f "$conflicts_file"
2322
fi
2423

24+
# Require text files to end with exactly one newline (skip binaries and fixtures)
25+
if [ -n "$staged" ]; then
26+
noeol_file="$(mktemp)"
27+
skip_ext='\.(png|jpg|jpeg|gif|ico|pdf|bin|wasm|woff2?|ttf|eot|otf|zip|gz|sqlite|db)$'
28+
echo "$staged" | while IFS= read -r f; do
29+
[ ! -f "$f" ] && continue
30+
[ -d "$f" ] && continue
31+
[ ! -s "$f" ] && continue
32+
echo "$f" | grep -qE "$skip_ext" && continue
33+
# Must end with newline (0a)
34+
last="$(tail -c 1 "$f" 2>/dev/null | od -An -tx1 | tr -d ' \n')" || last=""
35+
[ "$last" = "0a" ] && continue
36+
# Reject double newline at EOF
37+
last2="$(tail -c 2 "$f" 2>/dev/null | od -An -tx1 | tr -d ' \n')" || last2=""
38+
[ "$last2" = "0a0a" ] && echo "$f" >> "$noeol_file" && continue
39+
[ "$last" != "0a" ] && echo "$f" >> "$noeol_file"
40+
done
41+
if [ -s "$noeol_file" ] 2>/dev/null; then
42+
echo "ERROR: These files must end with exactly one newline (no missing or double newline at EOF):"
43+
cat "$noeol_file"
44+
rm -f "$noeol_file"
45+
exit 1
46+
fi
47+
rm -f "$noeol_file"
48+
fi
49+
2550
echo "==> Validating GitHub workflows..."
2651
bash "./scripts/check-workflows.sh"
2752

28-
echo "==> Running cargo fmt --check..."
29-
cargo fmt --check
53+
# Only run Rust checks when Rust-relevant files are staged
54+
rust_relevant() { echo "$staged" | grep -qE '^Cargo\.(toml|lock)$|\.rs$|^src/|^\.cargo/'; }
3055

31-
echo "==> Running cargo clippy --all-targets..."
32-
cargo clippy --all-targets -- -D warnings
56+
if rust_relevant; then
57+
echo "==> Running cargo fmt --check..."
58+
cargo fmt --check
59+
60+
echo "==> Running cargo clippy --all-targets..."
61+
cargo clippy --all-targets -- -D warnings
62+
fi
3363

3464
if echo "$staged" | grep -q '^web/'; then
35-
echo "==> Web files changed: running npm lint and tsc in web/..."
65+
echo "==> Web files changed: running npm lint, tsc, and test in web/..."
3666
(cd web && npm run lint)
3767
(cd web && npx tsc -b --noEmit)
68+
(cd web && npm run test)
3869
fi
3970

4071
if command -v shellcheck >/dev/null 2>&1; then
@@ -46,11 +77,13 @@ if command -v shellcheck >/dev/null 2>&1; then
4677
fi
4778
fi
4879

49-
if [ "${SKIP_TESTS:-0}" = "1" ]; then
50-
echo "==> Skipping cargo test (SKIP_TESTS=1). Pre-push still enforces the full Rust gate."
51-
else
52-
echo "==> Running cargo test..."
53-
cargo test
80+
if rust_relevant; then
81+
if [ "${SKIP_TESTS:-0}" = "1" ]; then
82+
echo "==> Skipping cargo test (SKIP_TESTS=1). Pre-push still enforces the full Rust gate."
83+
else
84+
echo "==> Running cargo test..."
85+
cargo test
86+
fi
5487
fi
5588

5689
echo "==> Pre-commit checks passed."

.githooks/pre-push

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,25 @@ cd "$repo_root"
77
echo "==> Validating GitHub workflows..."
88
bash "./scripts/check-workflows.sh"
99

10+
echo "==> Verifying Cargo version vs git tags..."
11+
python3 .github/scripts/check_version_sync.py
12+
1013
echo "==> Running cargo fmt --check..."
1114
cargo fmt --check
1215

1316
echo "==> Running cargo clippy --all-targets..."
1417
cargo clippy --all-targets -- -D warnings
1518

19+
if command -v cargo-audit >/dev/null 2>&1; then
20+
echo "==> Running cargo audit..."
21+
cargo audit
22+
else
23+
echo "==> Skipping cargo audit (cargo-audit not installed; run: cargo install cargo-audit)."
24+
fi
25+
26+
echo "==> Building and testing web..."
27+
(cd web && npm ci && npm run build && npm run test)
28+
1629
echo "==> Running cargo test..."
1730
cargo test
1831

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ cargo run -- --help # CLI usage
2121
- `eval/` — Evaluation and benchmarking
2222
- `examples/` — Usage examples
2323

24+
## Development
25+
- Run `bash scripts/install-hooks.sh` once to install pre-commit and pre-push hooks (merge conflict check, trailing newline, conditional Rust/web checks, shellcheck; pre-push adds version sync, cargo audit, full web build+test).
26+
2427
## Conventions
2528
- Use frontier models for reviews — never default to smaller models
2629
- Vault integration for secrets management (HashiCorp Vault)

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,14 @@ Enable the repository-managed git hooks after cloning:
10101010
bash scripts/install-hooks.sh
10111011
```
10121012

1013-
The hooks validate GitHub Actions workflows and run `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` before code leaves your machine. Install `actionlint` if you want full local workflow linting; otherwise the fallback check still blocks invalid `secrets.*` usage inside workflow `if:` expressions.
1013+
**Pre-commit** runs only when relevant files are staged:
1014+
- Rejects merge conflict markers and requires text files to end with exactly one newline
1015+
- Validates GitHub Actions workflows (install `actionlint` for full workflow linting)
1016+
- When Rust files are staged: `cargo fmt --check`, `cargo clippy --all-targets`, `cargo test`
1017+
- When `web/` is staged: `npm run lint`, `tsc -b`, and `npm run test` in `web/`
1018+
- When `scripts/` or `.githooks/` change: `shellcheck` (if installed)
1019+
1020+
**Pre-push** runs the full gate: workflow check, version sync (`Cargo.toml` vs git tags), `cargo fmt`, `cargo clippy`, `cargo audit` (if installed), `npm ci && npm run build && npm run test` in `web/`, and `cargo test`. The first push after clone may take longer due to `npm ci`.
10141021

10151022
## Supported Platforms
10161023

0 commit comments

Comments
 (0)