87 lines
2.9 KiB
Python
Executable File
87 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
PostToolUse hook: Auto-format Python files with ruff and block on errors
|
|
Inspired by onuralpszr's pre-commit hook: https://github.com/onuralpszr/onuralpszr/blob/main/configs/git-hooks/pre-commit-line-120
|
|
"""
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def main():
|
|
try:
|
|
data = json.load(sys.stdin)
|
|
|
|
# Get file path from tool input
|
|
file_path = data.get("tool_input", {}).get("file_path", "")
|
|
|
|
# Only process Python files
|
|
if not file_path.endswith('.py'):
|
|
sys.exit(0)
|
|
|
|
# Check if ruff is available - silent exit if not (no blocking)
|
|
if not shutil.which('ruff'):
|
|
sys.exit(0)
|
|
|
|
# Get directory containing the Python file
|
|
py_file = Path(file_path)
|
|
if not py_file.exists():
|
|
sys.exit(0)
|
|
|
|
work_dir = py_file.parent
|
|
|
|
# Run ruff check with fixes - capture output to check for errors
|
|
check_result = subprocess.run([
|
|
'ruff', 'check',
|
|
'--fix',
|
|
'--extend-select', 'F,I,D,UP,RUF,FA',
|
|
'--target-version', 'py39',
|
|
'--ignore', 'D100,D104,D203,D205,D212,D213,D401,D406,D407,D413,RUF001,RUF002,RUF012',
|
|
str(py_file)
|
|
], capture_output=True, text=True, cwd=work_dir)
|
|
|
|
# Block only if ruff check finds unfixable errors
|
|
if check_result.returncode != 0:
|
|
error_output = check_result.stdout.strip() or check_result.stderr.strip()
|
|
error_msg = f'ERROR running ruff check ❌ {error_output}'
|
|
print(error_msg, file=sys.stderr)
|
|
output = {
|
|
'systemMessage': f'Ruff errors detected in {py_file.name}',
|
|
'hookSpecificOutput': {'hookEventName': 'PostToolUse', 'decision': 'block', 'reason': error_msg},
|
|
}
|
|
print(json.dumps(output))
|
|
sys.exit(2)
|
|
|
|
# Run ruff format
|
|
format_result = subprocess.run([
|
|
'ruff', 'format',
|
|
'--line-length', '120',
|
|
str(py_file)
|
|
], capture_output=True, text=True, cwd=work_dir)
|
|
|
|
# Block only if ruff format fails (unlikely but possible)
|
|
if format_result.returncode != 0:
|
|
error_msg = f'ERROR running ruff format ❌ {format_result.stderr.strip()}'
|
|
print(error_msg, file=sys.stderr)
|
|
output = {
|
|
'systemMessage': f'Ruff format failed for {py_file.name}',
|
|
'hookSpecificOutput': {'hookEventName': 'PostToolUse', 'decision': 'block', 'reason': error_msg},
|
|
}
|
|
print(json.dumps(output))
|
|
sys.exit(2)
|
|
|
|
except Exception as e:
|
|
# Block on unexpected errors
|
|
error_msg = f'Python code quality hook error: {e}'
|
|
print(error_msg, file=sys.stderr)
|
|
sys.exit(2)
|
|
|
|
# Success - no errors
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main() |