diff --git a/src/analyzers/commit_pattern.py b/src/analyzers/commit_pattern.py index 22e625a..7d1d891 100644 --- a/src/analyzers/commit_pattern.py +++ b/src/analyzers/commit_pattern.py @@ -1,63 +1,79 @@ from collections import defaultdict -from dataclasses import dataclass -from typing import Dict, List, Optional +from datetime import datetime +from typing import Dict, List from src.analyzers.git_repository import GitRepository -from src.models.data_structures import CommitAnalysis +from src.models import Author, CommitAnalysis -@dataclass class CommitPatternAnalyzer: - """Analyzes commit patterns.""" + """Analyze commit patterns and statistics.""" - repo: GitRepository - days: int + def __init__( + self, + repo: GitRepository, + days: int = 30, + ) -> None: + """Initialize CommitPatternAnalyzer.""" + self.repo = repo + self.days = days - def analyze(self) -> Optional[CommitAnalysis]: + def analyze(self) -> CommitAnalysis: """Analyze commit patterns.""" - commits = self.repo.get_commits() + commits = self.repo.get_commits(since_days=self.days) if not commits: - return None + return CommitAnalysis() - commits_by_hour: Dict[str, int] = defaultdict(int) - commits_by_day: Dict[str, int] = defaultdict(int) - commits_by_week: Dict[str, int] = defaultdict(int) + authors = defaultdict(lambda: {"count": 0, "lines_added": 0, "lines_deleted": 0}) - author_commits: Dict[str, List[str]] = defaultdict(list) + commits_by_hour = defaultdict(int) + commits_by_day = defaultdict(int) + commits_by_week = defaultdict(int) + commits_by_month = defaultdict(int) for commit in commits: - hour_key = commit.timestamp.strftime("%H:00") - day_key = commit.timestamp.strftime("%A") - week_key = commit.timestamp.strftime("%Y-W%U") + hour = commit.author_datetime.strftime("%H:00") + day = commit.author_datetime.strftime("%A") + week = commit.author_datetime.strftime("%Y-W%W") + month = commit.author_datetime.strftime("%Y-%m") - commits_by_hour[hour_key] += 1 - commits_by_day[day_key] += 1 - commits_by_week[week_key] += 1 + commits_by_hour[hour] += 1 + commits_by_day[day] += 1 + commits_by_week[week] += 1 + commits_by_month[month] += 1 - author_commits[commit.author_email].append(commit.sha) + author_key = f"{commit.author_name} <{commit.author_email}>" + authors[author_key]["count"] += 1 + authors[author_key]["lines_added"] += commit.additions + authors[author_key]["lines_deleted"] += commit.deletions - authors = [] - for email, commit_shas in author_commits.items(): - author = self.repo.get_authors() - for a in author: - if a.email == email: - a.commit_count = len(commit_shas) - authors.append(a) - break + top_authors = [ + Author( + name=name.split(" <")[0], + email=name.split("<")[1].rstrip(">") if "<" in name else "", + commit_count=data["count"], + lines_added=data["lines_added"], + lines_deleted=data["lines_deleted"], + ) + for name, data in sorted( + authors.items(), + key=lambda x: x[1]["count"], + reverse=True, + )[:10] + ] - authors.sort(key=lambda a: a.commit_count, reverse=True) - top_authors = authors[:10] - - total_days = max(1, self.days) - avg_commits_per_day = len(commits) / total_days + unique_authors = len(authors) + total_commits = len(commits) + average_commits_per_day = total_commits / max(self.days, 1) return CommitAnalysis( - total_commits=len(commits), - unique_authors=len(authors), + total_commits=total_commits, + unique_authors=unique_authors, commits_by_hour=dict(commits_by_hour), commits_by_day=dict(commits_by_day), commits_by_week=dict(commits_by_week), + commits_by_month=dict(commits_by_month), top_authors=top_authors, - average_commits_per_day=avg_commits_per_day, + average_commits_per_day=average_commits_per_day, )