Skip to main content

max / balanced_breakfast

Add a rustfmt pre-commit gate Blocks a commit whose staged Rust files are not formatted, checking only the crates that have staged .rs changes. Activate in a fresh clone with: git config core.hooksPath scripts/githooks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-21 23:55 UTC
Commit: db205df0774a0a44c84b31751999f2283438b106
Parent: 802b361
2 files changed, +66 insertions, -1 deletion
@@ -1,5 +1,6 @@
1 1 #!/bin/bash
2 - # Balanced Breakfast pre-commit gate: frontend design-system lint + JS tests.
2 + # Balanced Breakfast pre-commit gate: rustfmt + frontend design-system lint
3 + # + JS tests.
3 4 # Blocks the commit if either fails (per the no-PR workflow; run locally).
4 5 #
5 6 # Activate in a fresh clone (one-time):
@@ -11,6 +12,12 @@ set -euo pipefail
11 12 ROOT="$(git rev-parse --show-toplevel)"
12 13 cd "$ROOT"
13 14
15 + echo "pre-commit: rustfmt..."
16 + if ! bash scripts/githooks/rustfmt-gate.sh; then
17 + echo "pre-commit: rustfmt gate failed — commit aborted (use --no-verify to bypass)."
18 + exit 1
19 + fi
20 +
14 21 echo "pre-commit: frontend lint..."
15 22 if ! bash scripts/lint-frontend.sh; then
16 23 echo "pre-commit: lint failed — commit aborted (use --no-verify to bypass)."
@@ -0,0 +1,58 @@
1 + #!/bin/bash
2 + # rustfmt gate: blocks a commit whose staged Rust files are not formatted.
3 + #
4 + # Activate in a fresh clone (one-time):
5 + # git config core.hooksPath scripts/githooks
6 + #
7 + # Bypass for a work-in-progress commit: git commit --no-verify
8 + #
9 + # Only crates with staged .rs changes are checked, so the hook stays fast on a
10 + # large repo. Each file maps to the nearest enclosing Cargo.toml, and the check
11 + # runs as `cargo fmt` there, which picks up that crate's edition and any
12 + # rustfmt.toml rather than guessing.
13 + set -euo pipefail
14 +
15 + ROOT="$(git rev-parse --show-toplevel)"
16 + cd "$ROOT"
17 +
18 + # Paths the gate ignores (extended regex, matched against repo-relative paths).
19 + # Empty means check everything.
20 + SKIP_PATHS="${SKIP_PATHS:-}"
21 +
22 + staged="$(git diff --cached --name-only --diff-filter=ACMR -- '*.rs')"
23 + if [ -n "$SKIP_PATHS" ]; then
24 + staged="$(printf '%s\n' "$staged" | grep -Ev "$SKIP_PATHS" || true)"
25 + fi
26 + [ -n "$staged" ] || exit 0
27 +
28 + # Map each staged file to the directory of its nearest Cargo.toml.
29 + crates=""
30 + while IFS= read -r f; do
31 + [ -n "$f" ] || continue
32 + d="$(dirname "$f")"
33 + while [ "$d" != "." ] && [ ! -f "$d/Cargo.toml" ]; do
34 + d="$(dirname "$d")"
35 + done
36 + [ -f "$d/Cargo.toml" ] || continue
37 + crates="$crates$d"$'\n'
38 + done <<< "$staged"
39 +
40 + crates="$(printf '%s' "$crates" | sort -u)"
41 + [ -n "$crates" ] || exit 0
42 +
43 + failed=0
44 + while IFS= read -r c; do
45 + [ -n "$c" ] || continue
46 + if ! (cd "$c" && cargo fmt --check >/dev/null 2>&1); then
47 + echo "pre-commit: rustfmt gate failed in $c"
48 + failed=1
49 + fi
50 + done <<< "$crates"
51 +
52 + if [ "$failed" -ne 0 ]; then
53 + echo "pre-commit: run 'cargo fmt' in the crates above, then restage."
54 + echo "pre-commit: commit aborted (use --no-verify to bypass)."
55 + exit 1
56 + fi
57 +
58 + echo "pre-commit: rustfmt gate clean."