diff --git a/ai_commit_msg/cli/conventional_commit_handler.py b/ai_commit_msg/cli/conventional_commit_handler.py index 3f5d094..18e2501 100644 --- a/ai_commit_msg/cli/conventional_commit_handler.py +++ b/ai_commit_msg/cli/conventional_commit_handler.py @@ -164,4 +164,4 @@ def conventional_commit_handler(args): execute_cli_command(["git", "commit", "-m", f'"{formatted_commit}"'], output=True) - handle_git_push() \ No newline at end of file + handle_git_push() diff --git a/ai_commit_msg/cli/doctor_handler.py b/ai_commit_msg/cli/doctor_handler.py new file mode 100644 index 0000000..5e3cda5 --- /dev/null +++ b/ai_commit_msg/cli/doctor_handler.py @@ -0,0 +1,30 @@ +import os +from rich.console import Console +from rich.panel import Panel +from rich.text import Text +from rich import box + +from ai_commit_msg.services.git_service import GitService +from ai_commit_msg.utils.logger import Logger +from ai_commit_msg.utils.utils import execute_cli_command + +console = Console() + + +def check_git_hooks_directory(): + """Check if we can determine the correct git hooks directory""" + try: + # Get the hooks directory using git's built-in command + hooks_dir = execute_cli_command( + ["git", "rev-parse", "--git-path", "hooks"] + ).stdout.strip() + git_dir = execute_cli_command(["git", "rev-parse", "--git-dir"]).stdout.strip() + + return { + "status": "ok", + "hooks_dir": hooks_dir, + "git_dir": git_dir, + "is_worktree": "worktrees" in git_dir, + } + except Exception as e: + return {"status": "error", "error": str(e)} diff --git a/ai_commit_msg/cli/hook_handler.py b/ai_commit_msg/cli/hook_handler.py index eb3babc..3404153 100644 --- a/ai_commit_msg/cli/hook_handler.py +++ b/ai_commit_msg/cli/hook_handler.py @@ -32,6 +32,11 @@ def get_bash_script(): def handle_setup_hook(hook_directory_path: str): + # Ensure the hooks directory exists + hooks_dir = os.path.dirname(hook_directory_path) + if not os.path.exists(hooks_dir): + os.makedirs(hooks_dir, exist_ok=True) + existing_hook_content = "" if os.path.exists(hook_directory_path): with open(hook_directory_path, "r") as file: diff --git a/ai_commit_msg/services/git_service.py b/ai_commit_msg/services/git_service.py index 7d81630..984a084 100644 --- a/ai_commit_msg/services/git_service.py +++ b/ai_commit_msg/services/git_service.py @@ -127,8 +127,12 @@ def get_git_config_value(key: GitConfigKeysEnum): @staticmethod def get_git_prepare_commit_msg_hook_path(): - git_repo_path = GitService.get_git_directory() - return git_repo_path + "/hooks/prepare-commit-msg" + # Use git's built-in command to get the correct hooks directory + # This properly handles worktrees and other git configurations + hooks_dir = execute_cli_command( + ["git", "rev-parse", "--git-path", "hooks"] + ).stdout.strip() + return hooks_dir + "/prepare-commit-msg" @staticmethod def get_last_n_commit_msg(n): diff --git a/ai_commit_msg/services/llm_service.py b/ai_commit_msg/services/llm_service.py index 8fece7f..eae9a22 100644 --- a/ai_commit_msg/services/llm_service.py +++ b/ai_commit_msg/services/llm_service.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod + class LLMService(ABC): @abstractmethod def chat_completion(self, messages): - pass \ No newline at end of file + pass diff --git a/test_hook_setup.py b/test_hook_setup.py new file mode 100644 index 0000000..0a06515 --- /dev/null +++ b/test_hook_setup.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +import os +import tempfile +import shutil +from ai_commit_msg.cli.hook_handler import handle_setup_hook + + +def test_hook_setup_with_missing_directory(): + """Test that handle_setup_hook creates the hooks directory if it doesn't exist""" + + # Create a temporary directory for testing + with tempfile.TemporaryDirectory() as temp_dir: + # Create a fake hooks path that doesn't exist + hooks_dir = os.path.join(temp_dir, "hooks") + hook_file_path = os.path.join(hooks_dir, "prepare-commit-msg") + + print(f"Testing hook setup with path: {hook_file_path}") + print(f"Hooks directory exists before: {os.path.exists(hooks_dir)}") + + # This should create the directory and the hook file + handle_setup_hook(hook_file_path) + + print(f"Hooks directory exists after: {os.path.exists(hooks_dir)}") + print(f"Hook file exists: {os.path.exists(hook_file_path)}") + print(f"Hook file is executable: {os.access(hook_file_path, os.X_OK)}") + + # Verify the content + if os.path.exists(hook_file_path): + with open(hook_file_path, "r") as f: + content = f.read() + print(f"Hook file contains git-ai-commit: {'git-ai-commit' in content}") + + print("āœ… Test completed successfully!") + + +def test_local_git_hooks(): + """Test the actual local .git/hooks directory""" + + # Check if we're in a git repository + git_dir = ".git" + if not os.path.exists(git_dir): + print("āŒ Not in a git repository - .git directory not found") + return + + hooks_dir = os.path.join(git_dir, "hooks") + hook_file_path = os.path.join(hooks_dir, "prepare-commit-msg") + + print(f"šŸ” Checking local git hooks in: {os.path.abspath(hooks_dir)}") + print(f"Hooks directory exists: {os.path.exists(hooks_dir)}") + + if os.path.exists(hooks_dir): + print(f"Files in hooks directory:") + for file in os.listdir(hooks_dir): + file_path = os.path.join(hooks_dir, file) + is_executable = os.access(file_path, os.X_OK) + print( + f" - {file} {'(executable)' if is_executable else '(not executable)'}" + ) + + print(f"\nšŸ“‹ prepare-commit-msg hook status:") + print(f"Hook file exists: {os.path.exists(hook_file_path)}") + + if os.path.exists(hook_file_path): + print(f"Hook file is executable: {os.access(hook_file_path, os.X_OK)}") + + # Check content + with open(hook_file_path, "r") as f: + content = f.read() + has_git_ai_commit = "git-ai-commit" in content + print(f"Hook file contains 'git-ai-commit': {has_git_ai_commit}") + + if has_git_ai_commit: + print("āœ… git-ai-commit hook is installed!") + else: + print("āŒ git-ai-commit not found in hook file") + print("Hook content preview:") + print("-" * 40) + print(content[:200] + "..." if len(content) > 200 else content) + print("-" * 40) + else: + print("āŒ prepare-commit-msg hook not found") + print("\nšŸ”§ To install the hook, you can run:") + print(f"handle_setup_hook('{hook_file_path}')") + + +if __name__ == "__main__": + print("=== Testing Local Git Hooks ===") + test_local_git_hooks() + + print("\n" + "=" * 50) + print("=== Testing with Temporary Directory ===") + test_hook_setup_with_missing_directory()