Files
gh-withzombies-hyperpowers/hooks/post-tool-use/04-block-pre-existing-checks.py
2025-11-30 09:06:38 +08:00

114 lines
3.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
PostToolUse hook to block git checkout when checking for pre-existing errors.
When projects use pre-commit hooks that enforce passing tests, checking if
errors are "pre-existing" is unnecessary and wastes time. All test failures
and lint errors must be from current changes because pre-commit hooks prevent
commits with failures.
Blocked patterns:
- git checkout <sha> (or git stash && git checkout)
- Combined with test/lint commands (ruff, pytest, mypy, cargo test, npm test, etc.)
"""
import json
import sys
import re
# Test and lint command patterns that might be run on previous commits
VERIFICATION_COMMANDS = [
r'\bruff\b',
r'\bpytest\b',
r'\bmypy\b',
r'\bflake8\b',
r'\bblack\b',
r'\bisort\b',
r'\bcargo\s+test\b',
r'\bcargo\s+clippy\b',
r'\bnpm\s+test\b',
r'\bnpm\s+run\s+test\b',
r'\byarn\s+test\b',
r'\bgo\s+test\b',
r'\bmvn\s+test\b',
r'\bgradle\s+test\b',
r'\bpylint\b',
r'\beslint\b',
r'\btsc\b', # TypeScript compiler
r'\bpre-commit\s+run\b',
]
def is_checking_previous_commit(command):
"""
Detect if command is checking out previous commits to run tests/lints.
Patterns:
- git checkout <sha>
- git stash && git checkout
- git diff <sha>..<sha>
"""
# Check for git checkout patterns
if re.search(r'git\s+checkout\s+[a-f0-9]{6,40}', command):
return True
if re.search(r'git\s+stash.*?&&.*?git\s+checkout', command):
return True
# Check if command contains verification commands
# (only flag if combined with git checkout)
has_verification = any(re.search(pattern, command) for pattern in VERIFICATION_COMMANDS)
has_git_checkout = re.search(r'git\s+checkout', command)
return has_verification and has_git_checkout
def main():
# Read tool use event from stdin
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError:
# If we can't parse JSON, allow the operation
sys.exit(0)
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
# Only check Bash tool calls
if tool_name != "Bash":
sys.exit(0)
command = tool_input.get("command", "")
if not command:
sys.exit(0)
# Check if this looks like checking previous commits for errors
if is_checking_previous_commit(command):
# Block the command and provide helpful feedback
output = {
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": (
"⚠️ CHECKING FOR PRE-EXISTING ERRORS IS UNNECESSARY\n\n"
"Your project uses pre-commit hooks that enforce all tests pass before commits.\n"
"Therefore, ALL test failures and errors are from your current changes.\n\n"
"Do not check if errors were pre-existing. Pre-commit hooks guarantee they weren't.\n\n"
"What you should do instead:\n"
"1. Read the error messages from the current test run\n"
"2. Fix the errors directly\n"
"3. Run tests again to verify the fix\n\n"
"Checking git history for errors is wasting time when pre-commit hooks enforce quality.\n\n"
"Blocked command:\n"
f"{command[:200]}" # Show first 200 chars of command
)
}
}
print(json.dumps(output))
sys.exit(0)
# Allow command if not checking for pre-existing errors
sys.exit(0)
if __name__ == "__main__":
main()