Skip to content

Commit

Permalink
feat: refactor GitCommitAssistant to AiCommit and enhance commit hand…
Browse files Browse the repository at this point in the history
…ling

This refactor changes the class name from GitCommitAssistant to AiCommit and adds new methods for handling changes and creating commits. It improves code organization and clarity.
  • Loading branch information
versun committed Dec 23, 2024
1 parent 7ea240c commit 22b38c6
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 50 deletions.
91 changes: 41 additions & 50 deletions aicmt/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
import sys
from typing import List
from .git_operations import GitOperations
from .ai_analyzer import AIAnalyzer
from .cli_interface import CLIInterface
Expand All @@ -9,59 +10,59 @@
console = Console()


class GitCommitAssistant:
class AiCommit:
def __init__(self):
self.git_ops = GitOperations()
self.ai_analyzer = AIAnalyzer()
self.cli = CLIInterface()

def _handle_changes(self) -> List[dict]:
"""Handle and return git changes"""
staged_changes = self.git_ops.get_staged_changes()
if staged_changes:
self.cli.display_info("Found staged changes, analyzing only those changes.")
return staged_changes
return self.git_ops.get_unstaged_changes()

def _create_new_commits(self, approved_groups: List[dict]) -> None:
"""Process approved commit groups"""
for group in approved_groups:
try:
self.git_ops.stage_files(group["files"])
self.git_ops.commit_changes(
f"{group['commit_message']}\n\n{group['description']}"
)
self.cli.display_success(f"Created commit: {group['commit_message']}")
except Exception as e:
self.cli.display_error(f"Failed to create commit: {str(e)}")

def _handle_push(self) -> None:
"""Handle pushing changes if confirmed"""
if self.cli.confirm_push():
try:
self.git_ops.push_changes()
self.cli.display_success("Successfully pushed all commits!")
except Exception as e:
self.cli.display_error(f"Failed to push commits: {str(e)}")

def run(self):
"""Main execution flow"""
try:
self.cli.display_welcome()
# Display repository info
self.cli.display_repo_info(self.git_ops.repo.working_dir, self.git_ops.get_current_branch())

# Get changes
changes = []
staged_changes = self.git_ops.get_staged_changes()
if staged_changes:
changes = staged_changes
self.cli.display_info("Found staged changes, analyzing only those changes.")
else:
changes = self.git_ops.get_unstaged_changes()
changes = self._handle_changes()

# Display current changes with detailed info
self.cli.display_changes(changes)

# Analyze changes with AI
self.cli.display_ai_analysis_start(self.ai_analyzer.base_url, self.ai_analyzer.model)

commit_groups = self.ai_analyzer.analyze_changes(changes)
approved_groups = self.cli.display_commit_groups(commit_groups)
self.cli.display_groups_approval_status(len(approved_groups), len(commit_groups))

# Create commits for approved groups
for group in approved_groups:
try:
# Stage files for this group
self.git_ops.stage_files(group["files"])

# Create commit
self.git_ops.commit_changes(group["commit_message"] + "\n\n" + group["description"])

self.cli.display_success(f"Created commit: {group['commit_message']}")
except Exception as e:
self.cli.display_error(f"Failed to create commit: {str(e)}")
continue
self.cli.display_groups_approval_status(len(approved_groups), len(commit_groups))

# Ask user if they want to push changes
if self.cli.confirm_push():
try:
self.git_ops.push_changes()
self.cli.display_success("Successfully pushed all commits!")
except Exception as e:
self.cli.display_error(f"Failed to push commits: {str(e)}")
self._create_new_commits(approved_groups)
self._handle_push()

except KeyboardInterrupt:
self.cli.exit_program("\nOperation cancelled by user.")
Expand All @@ -71,22 +72,12 @@ def run(self):


def cli():
# Create and run assistant
try:
# First parse command line arguments
parse_args()

# Create and run assistant
try:
assistant = GitCommitAssistant()
assistant.run()
except ValueError as ve:
# Configuration related errors
console.print(f"[bold red]Configuration Error:[/bold red] {str(ve)}")
sys.exit(1)
except Exception as e:
# Other runtime errors
console.print(f"[bold red]Runtime Error:[/bold red] {str(e)}")
sys.exit(1)
except KeyboardInterrupt:
console.print("\nProgram interrupted by user")
assistant = AiCommit()
assistant.run()
except Exception as e:
# Other runtime errors
console.print(f"[bold red]Error:[/bold red] {str(e)}")
sys.exit(1)
61 changes: 61 additions & 0 deletions aicmt/git_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,64 @@ def get_commit_history(self, max_count: int = 10) -> List[Dict]:
return commits
except git.GitCommandError as e:
raise git.GitCommandError(f"Failed to get commit history: {str(e)}", e.status, e.stderr)

def get_commit_changes(self, commit_hash: str) -> List[Change]:
"""Get changes from a specific commit
Args:
commit_hash: Hash of the commit to analyze
Returns:
List[Change]: List of changes in the commit
Raises:
git.GitCommandError: If there is an error getting the commit changes
"""
try:
commit = self.repo.commit(commit_hash)
parent = commit.parents[0] if commit.parents else self.repo.tree("4b825dc642cb6eb9a060e54bf8d69288fbee4904")

changes = []
diff_index = parent.diff(commit)

for diff in diff_index:
status = "error"
content = ""
insertions = diff.insertions if hasattr(diff, "insertions") else 0
deletions = diff.deletions if hasattr(diff, "deletions") else 0

try:
if diff.deleted_file:
status = "deleted"
content = "[File deleted]"
insertions, deletions = 0, diff.a_blob.size if diff.a_blob else 0
elif diff.new_file:
if diff.b_blob:
try:
content = diff.b_blob.data_stream.read().decode('utf-8')
status = "new file"
insertions = len(content.splitlines())
deletions = 0
except UnicodeDecodeError:
status = "new file (binary)"
content = "[Binary file]"
else:
status = "new file"
content = "[Empty file]"
else:
status = "modified"
content = self.repo.git.diff(f"{parent.hexsha}..{commit.hexsha}", diff.b_path)
stats = self.repo.git.diff(f"{parent.hexsha}..{commit.hexsha}", "--numstat", diff.b_path).split()
if len(stats) >= 2:
insertions = int(stats[0]) if stats[0] != "-" else 0
deletions = int(stats[1]) if stats[1] != "-" else 0

except Exception as e:
status = "error"
content = f"[Unexpected error: {str(e)}]"

changes.append(Change(file=diff.b_path or diff.a_path, status=status, diff=content, insertions=insertions, deletions=deletions))

return changes
except git.GitCommandError as e:
raise git.GitCommandError(f"Failed to get commit changes: {str(e)}", e.status, e.stderr)

0 comments on commit 22b38c6

Please sign in to comment.