Add backpressure stack for agentic coding quality gates
PostToolUse hooks run after every file edit: - Backend: ./mvnw compile (Checkstyle Google Style + javac) - Frontend: vue-tsc --noEmit + oxlint + ESLint Stop hook runs test suites when source files changed, blocks the agent on failure and re-engages it to fix the issue. Output is filtered to [ERROR] lines only for context efficiency. Static analysis: Checkstyle (validate phase), SpotBugs (verify phase), ArchUnit (9 hexagonal architecture rules as JUnit tests). Fail-fast: Surefire skipAfterFailureCount=1, Vitest bail=1. Test log noise suppressed via logback-test.xml (WARN level), redirectTestOutputToFile, and trimStackTrace. Existing Java sources reformatted to Google Style (2-space indent, import order, Javadoc on public types). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
54
.claude/hooks/run-tests.sh
Executable file
54
.claude/hooks/run-tests.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$CLAUDE_PROJECT_DIR"
|
||||
|
||||
# Read hook input from stdin
|
||||
INPUT=$(cat)
|
||||
|
||||
# Prevent infinite loops: if already re-engaged by a previous Stop hook, let it stop
|
||||
STOP_HOOK_ACTIVE=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('stop_hook_active', False))" 2>/dev/null || echo "False")
|
||||
if [[ "$STOP_HOOK_ACTIVE" == "True" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for uncommitted changes in backend/frontend source
|
||||
HAS_BACKEND=$(git status --porcelain backend/src/ 2>/dev/null | head -1)
|
||||
HAS_FRONTEND=$(git status --porcelain frontend/src/ 2>/dev/null | head -1)
|
||||
|
||||
# Nothing changed -- skip
|
||||
if [[ -z "$HAS_BACKEND" && -z "$HAS_FRONTEND" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ERRORS=""
|
||||
PASSED=""
|
||||
|
||||
# Run backend tests if Java sources changed
|
||||
if [[ -n "$HAS_BACKEND" ]]; then
|
||||
if OUTPUT=$(cd backend && ./mvnw test -q 2>&1); then
|
||||
PASSED+="✓ Backend tests passed. "
|
||||
else
|
||||
# Filter: only [ERROR] lines, skip Maven boilerplate
|
||||
FILTERED=$(echo "$OUTPUT" | grep -E "^\[ERROR\]" | grep -v -E "Re-run Maven|See |Help 1|full stack trace|Failed to execute goal|For more information|^\[ERROR\] *$" || true)
|
||||
ERRORS+="Backend tests failed:\n$FILTERED\n\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run frontend tests if TS/Vue sources changed
|
||||
if [[ -n "$HAS_FRONTEND" ]]; then
|
||||
if OUTPUT=$(cd frontend && npm run test:unit -- --run 2>&1); then
|
||||
PASSED+="✓ Frontend tests passed. "
|
||||
else
|
||||
ERRORS+="Frontend tests failed:\n$OUTPUT\n\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$ERRORS" ]]; then
|
||||
# Block stopping — re-engage the agent to fix failures
|
||||
ESCAPED=$(printf '%s' "$ERRORS" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))")
|
||||
echo "{\"decision\":\"block\",\"reason\":$ESCAPED}"
|
||||
else
|
||||
# Success — allow stopping, report via stopReason
|
||||
echo "{\"decision\":\"approve\",\"reason\":\"$PASSED\"}"
|
||||
fi
|
||||
Reference in New Issue
Block a user