Files
gh-aojdevstudio-dev-utils-m…/hooks/scripts/auto_commit_on_changes.py
2025-11-29 17:57:39 +08:00

119 lines
3.5 KiB
Python
Executable File

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.8"
# dependencies = []
# ///
import subprocess
import sys
from datetime import datetime
from pathlib import Path
def run_git_command(command: list[str]) -> subprocess.CompletedProcess:
"""Run a git command and return the completed process."""
try:
return subprocess.run(
command, capture_output=True, text=True, check=True, cwd=Path.cwd()
)
except subprocess.CalledProcessError as e:
print(f"Git command failed: {' '.join(command)}")
print(f"Error: {e.stderr}")
sys.exit(1)
def count_changed_files(max_count: int = 6) -> int:
"""
Count all changed files (staged, unstaged, and untracked) with early exit.
Ignores files in .gitignore. Returns count up to max_count.
"""
changed_files = set()
try:
# 1. Get unstaged changes (working tree vs index)
result = subprocess.run(
["git", "diff-files", "--name-only"],
capture_output=True,
text=True,
check=True,
)
if result.stdout.strip():
changed_files.update(result.stdout.strip().split("\n"))
if len(changed_files) >= max_count:
return max_count
# 2. Get staged changes (index vs HEAD)
result = subprocess.run(
["git", "diff-index", "--cached", "--name-only", "HEAD"],
capture_output=True,
text=True,
check=True,
)
if result.stdout.strip():
changed_files.update(result.stdout.strip().split("\n"))
if len(changed_files) >= max_count:
return max_count
# 3. Get untracked files (respects .gitignore)
result = subprocess.run(
["git", "ls-files", "--others", "--exclude-standard"],
capture_output=True,
text=True,
check=True,
)
if result.stdout.strip():
changed_files.update(result.stdout.strip().split("\n"))
return min(len(changed_files), max_count)
except subprocess.CalledProcessError:
# If git command fails, assume no changes
return 0
def check_git_repository() -> bool:
"""Check if we're in a git repository."""
try:
subprocess.run(
["git", "rev-parse", "--git-dir"], capture_output=True, check=True
)
return True
except subprocess.CalledProcessError:
return False
def request_claude_commit():
"""Request Claude Code to make a commit by echoing the appropriate message."""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
commit_message = f"Auto-commit: 5+ file changes detected at {timestamp}"
# Echo a message that Claude Code can interpret as a commit request
print(f"CLAUDE_COMMIT_REQUEST: {commit_message}")
print("🔄 Requesting Claude Code to stage and commit changes...")
def main():
"""Main execution function."""
print("🔍 Checking for file changes...")
# Verify we're in a git repository
if not check_git_repository():
print("❌ Not in a git repository. Exiting.")
sys.exit(1)
# Count changed files with early exit at 6
changed_count = count_changed_files(max_count=6)
print(f"📊 Found {changed_count} changed file(s)")
# Check if we hit the threshold
if changed_count >= 5:
print("🚨 Threshold reached: 5+ files changed")
request_claude_commit()
else:
print(f"✅ Below threshold: {changed_count}/5 files changed")
if __name__ == "__main__":
main()