Files

107 lines
3.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# Pre-commit validation hook for godot-opencode (Phase 3.5).
# - Validates staged .json tables parse (blocks on bad JSON).
# - GDScript quick check: conflict markers + obvious type-consistency slips.
# - Optionally blocks on test failure (--run-tests or VALIDATE_COMMIT_RUN_TESTS=1).
# Gracefully degrades when optional tools (python3/bun/godot) are missing.
set -euo pipefail
RUN_TESTS=0
if [[ "${1:-}" == "--run-tests" ]]; then
RUN_TESTS=1
fi
if [[ "${VALIDATE_COMMIT_RUN_TESTS:-}" == "1" ]]; then
RUN_TESTS=1
fi
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$ROOT"
STAGED="$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true)"
if [[ -z "$STAGED" ]]; then
echo "validate-commit: no staged changes, ok"
exit 0
fi
fail() {
echo "validate-commit: $*" >&2
exit 1
}
json_ok() {
local file="$1"
if command -v python3 >/dev/null 2>&1; then
python3 -c 'import json,sys; json.load(open(sys.argv[1]))' "$file" 2>/dev/null
return $?
fi
if command -v bun >/dev/null 2>&1; then
bun -e 'const f=Bun.file(process.argv[2]); JSON.parse(await f.text())' -- "$file" 2>/dev/null
return $?
fi
if command -v node >/dev/null 2>&1; then
node -e 'require("fs"); JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))' "$file" 2>/dev/null
return $?
fi
echo "validate-commit: warning: no JSON parser available, skipping $file" >&2
return 0
}
JSON_FAILED=0
while IFS= read -r file; do
[[ -z "$file" ]] && continue
case "$file" in
*.json)
if [[ -f "$file" ]]; then
if ! json_ok "$file"; then
echo "validate-commit: invalid JSON: $file" >&2
JSON_FAILED=1
fi
fi
;;
esac
done <<<"$STAGED"
if [[ "$JSON_FAILED" == "1" ]]; then
fail "staged JSON validation failed"
fi
GD_FAILED=0
while IFS= read -r file; do
[[ -z "$file" ]] && continue
case "$file" in
*.gd)
if [[ -f "$file" ]]; then
if grep -qE '^(<<<<<<<|>>>>>>>|\|\|\|\|\|\|)' "$file"; then
echo "validate-commit: conflict markers in $file" >&2
GD_FAILED=1
fi
# Obvious type-consistency slips: int := quoted string, String := bare number.
if grep -qE 'var\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*int\s*=\s*"' "$file"; then
echo "validate-commit: type mismatch (int := string) in $file" >&2
GD_FAILED=1
fi
if grep -qE 'var\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*String\s*=\s*[0-9]' "$file"; then
echo "validate-commit: type mismatch (String := number) in $file" >&2
GD_FAILED=1
fi
fi
;;
esac
done <<<"$STAGED"
if [[ "$GD_FAILED" == "1" ]]; then
fail "staged GDScript check failed"
fi
if [[ "$RUN_TESTS" == "1" ]]; then
if command -v bun >/dev/null 2>&1; then
echo "validate-commit: running bun tests..."
if ! bun test ./packages/plugin/test/ ./companion/tests/; then
fail "tests failed, commit blocked"
fi
else
echo "validate-commit: warning: bun not found, skipping tests" >&2
fi
fi
echo "validate-commit: ok"
exit 0