fix(husky): pre-commit cd recursion + lint-grep false positive

Two bugs in .husky/pre-commit made lint+typecheck+tests silently no-op:

1. cd recursion: `cd apps/web && ...` repeated 4× sequentially.
   After the 1st cd the CWD is apps/web, so `cd apps/web` again tries
   to enter apps/web/apps/web and errors out. Fix: wrap each step in
   a subshell `(cd apps/web && ...)` so the cd is scoped.

2. Lint grep false positive: `grep -q "error"` matched the ESLint
   summary line "(0 errors, K warnings)" — blocking commits even
   when lint was clean. Fix: `grep -qE "\([1-9][0-9]* error"` —
   matches only the summary with N>=1 errors.

With (1) alone, the hook would block any commit because of bug (2).
Both fixes land together to keep the hook usable.

Before: 3/4 steps no-op'd, and the 4th (lint) would have always
blocked if anything had ever triggered it.
After: all 4 steps run, and only actual errors block.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
senke 2026-04-20 20:20:40 +02:00
parent 68d946172f
commit 12f873bdb8

View file

@ -1,20 +1,24 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Each step runs in a subshell so the cd does not leak across steps.
# Pre-commit runs from the repo root; every cd below is relative to that.
# Generate TypeScript types from OpenAPI spec before commit # Generate TypeScript types from OpenAPI spec before commit
# This ensures types are always up-to-date with the backend API # This ensures types are always up-to-date with the backend API
cd apps/web && bash scripts/generate-types.sh (cd apps/web && bash scripts/generate-types.sh)
# Implicit 10.1: Type checking # Implicit 10.1: Type checking
# Prevent commits with TypeScript errors (warnings are allowed) # Prevent commits with TypeScript errors (warnings are allowed)
cd apps/web && npm run typecheck 2>&1 | grep -q "error TS" && { (cd apps/web && npm run typecheck 2>&1 | grep -q "error TS") && {
echo "❌ Type checking failed. Please fix TypeScript errors before committing." echo "❌ Type checking failed. Please fix TypeScript errors before committing."
echo "💡 Run 'npm run typecheck' to see all errors." echo "💡 Run 'npm run typecheck' to see all errors."
exit 1 exit 1
} || true } || true
# Implicit 10.2: Linting # Implicit 10.2: Linting
# Prevent commits with linting errors (warnings are allowed) # Prevent commits with linting errors (warnings are allowed).
cd apps/web && npm run lint 2>&1 | grep -q "error" && { # Pattern matches "(N error" with N>=1 in ESLint's summary line —
# avoids false positive on "(0 errors, K warnings)".
(cd apps/web && npm run lint 2>&1 | grep -qE "\([1-9][0-9]* error") && {
echo "❌ Linting failed. Please fix linting errors before committing." echo "❌ Linting failed. Please fix linting errors before committing."
echo "💡 Tip: Run 'npm run lint:fix' to automatically fix some issues." echo "💡 Tip: Run 'npm run lint:fix' to automatically fix some issues."
exit 1 exit 1
@ -24,7 +28,7 @@ cd apps/web && npm run lint 2>&1 | grep -q "error" && {
# Skip if SKIP_TESTS environment variable is set (for quick commits) # Skip if SKIP_TESTS environment variable is set (for quick commits)
# Only runs unit tests (not E2E) to keep it fast # Only runs unit tests (not E2E) to keep it fast
if [ -z "$SKIP_TESTS" ]; then if [ -z "$SKIP_TESTS" ]; then
cd apps/web && npm test -- --run 2>&1 | grep -q "FAIL" && { (cd apps/web && npm test -- --run 2>&1 | grep -q "FAIL") && {
echo "❌ Tests failed. Please fix failing tests before committing." echo "❌ Tests failed. Please fix failing tests before committing."
echo "💡 Tip: Run 'npm test' to see all test failures." echo "💡 Tip: Run 'npm test' to see all test failures."
echo "💡 Tip: Set SKIP_TESTS=1 to skip tests for this commit (not recommended)." echo "💡 Tip: Set SKIP_TESTS=1 to skip tests for this commit (not recommended)."