From 89da5c37d2ae95a399575f0203f2c43314a9423e Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sun, 1 Feb 2026 07:57:57 +0000 Subject: [PATCH] Add models, analyzers, and formatters --- src/models/data_structures.py | 148 +++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 45 deletions(-) diff --git a/src/models/data_structures.py b/src/models/data_structures.py index 5203b62..30f1f82 100644 --- a/src/models/data_structures.py +++ b/src/models/data_structures.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field from datetime import datetime -from typing import List, Optional +from typing import Any, Dict, List, Optional from dataclasses_json import dataclass_json @@ -8,7 +8,7 @@ from dataclasses_json import dataclass_json @dataclass_json @dataclass class Author: - """Represents a git author.""" + """Author information.""" name: str email: str commit_count: int = 0 @@ -19,77 +19,134 @@ class Author: @dataclass_json @dataclass class Commit: - """Represents a git commit.""" + """Git commit information.""" sha: str message: str - author: str + author_name: str author_email: str - timestamp: datetime - lines_added: int = 0 - lines_deleted: int = 0 + committed_datetime: datetime + author_datetime: datetime + additions: int = 0 + deletions: int = 0 files_changed: List[str] = field(default_factory=list) + parents: List[str] = field(default_factory=list) is_merge: bool = False is_revert: bool = False + @property + def lines_changed_count(self) -> int: + """Get total lines changed.""" + return self.additions + self.deletions + @dataclass_json @dataclass class FileChange: - """Represents changes to a file in a commit.""" + """File change information.""" filepath: str - lines_added: int - lines_deleted: int - change_type: str + lines_added: int = 0 + lines_deleted: int = 0 + change_type: str = "M" @dataclass_json @dataclass class CommitAnalysis: - """Analysis of commit patterns.""" - total_commits: int - unique_authors: int - commits_by_hour: dict - commits_by_day: dict - commits_by_week: dict - top_authors: List[Author] - average_commits_per_day: float + """Commit pattern analysis results.""" + total_commits: int = 0 + unique_authors: int = 0 + commits_by_hour: Dict[str, int] = field(default_factory=dict) + commits_by_day: Dict[str, int] = field(default_factory=dict) + commits_by_week: Dict[str, int] = field(default_factory=dict) + commits_by_month: Dict[str, int] = field(default_factory=dict) + top_authors: List[Author] = field(default_factory=list) + average_commits_per_day: float = 0.0 + + def to_dict(self) -> Dict[str, Any]: + """Convert to dictionary.""" + return { + "total_commits": self.total_commits, + "unique_authors": self.unique_authors, + "commits_by_hour": self.commits_by_hour, + "commits_by_day": self.commits_by_day, + "commits_by_week": self.commits_by_week, + "commits_by_month": self.commits_by_month, + "top_authors": [a.to_dict() for a in self.top_authors], + "average_commits_per_day": self.average_commits_per_day, + } @dataclass_json @dataclass class CodeChurnAnalysis: - """Analysis of code churn.""" - total_lines_added: int - total_lines_deleted: int - net_change: int - churn_by_file: dict - churn_by_author: dict - high_churn_commits: List[Commit] - average_churn_per_commit: float + """Code churn analysis results.""" + total_lines_added: int = 0 + total_lines_deleted: int = 0 + net_change: int = 0 + churn_by_file: Dict[str, int] = field(default_factory=dict) + churn_by_author: Dict[str, int] = field(default_factory=dict) + high_churn_files: List[FileChange] = field(default_factory=list) + high_churn_commits: List[Commit] = field(default_factory=list) + average_churn_per_commit: float = 0.0 + + def to_dict(self) -> Dict[str, Any]: + """Convert to dictionary.""" + return { + "total_lines_added": self.total_lines_added, + "total_lines_deleted": self.total_lines_deleted, + "net_change": self.net_change, + "churn_by_file": self.churn_by_file, + "churn_by_author": self.churn_by_author, + "high_churn_files": [f.to_dict() for f in self.high_churn_files], + "high_churn_commits": [c.to_dict() for c in self.high_churn_commits], + "average_churn_per_commit": self.average_churn_per_commit, + } @dataclass_json @dataclass class RiskyCommitAnalysis: - """Analysis of risky commits.""" - total_risky_commits: int - large_change_commits: List[Commit] - merge_commits: List[Commit] - revert_commits: List[Commit] - risk_score: float + """Risky commit detection results.""" + large_commits: List[Commit] = field(default_factory=list) + merge_commits: List[Commit] = field(default_factory=list) + revert_commits: List[Commit] = field(default_factory=list) + total_risky: int = 0 + + def to_dict(self) -> Dict[str, Any]: + """Convert to dictionary.""" + return { + "large_commits": [c.to_dict() for c in self.large_commits], + "merge_commits": [c.to_dict() for c in self.merge_commits], + "revert_commits": [c.to_dict() for c in self.revert_commits], + "total_risky": self.total_risky, + } @dataclass_json @dataclass class VelocityAnalysis: - """Analysis of team velocity.""" - commits_per_day: float - commits_per_week: float - commits_per_month: float - velocity_trend: str - top_contributors: List[Author] - most_active_day: str - most_active_hour: str + """Velocity analysis results.""" + total_commits: int = 0 + commits_per_day: float = 0.0 + commits_per_week: float = 0.0 + velocity_trend: str = "stable" + most_active_day: str = "" + most_active_hour: str = "" + weekly_totals: Dict[str, int] = field(default_factory=dict) + daily_totals: Dict[str, int] = field(default_factory=dict) + + def to_dict(self) -> Dict[str, Any]: + """Convert to dictionary.""" + return { + "total_commits": self.total_commits, + "commits_per_day": self.commits_per_day, + "commits_per_week": self.commits_per_week, + "velocity_trend": self.velocity_trend, + "most_active_day": self.most_active_day, + "most_active_hour": self.most_active_hour, + "weekly_totals": self.weekly_totals, + "daily_totals": self.daily_totals, + } @dataclass_json @@ -98,7 +155,8 @@ class ProductivityReport: """Comprehensive productivity report.""" repository_path: str analysis_days: int - commit_analysis: Optional[CommitAnalysis] - code_churn_analysis: Optional[CodeChurnAnalysis] - risky_commit_analysis: Optional[RiskyCommitAnalysis] - velocity_analysis: Optional[VelocityAnalysis] + commit_analysis: Optional[CommitAnalysis] = None + code_churn_analysis: Optional[CodeChurnAnalysis] = None + risky_commit_analysis: Optional[RiskyCommitAnalysis] = None + velocity_analysis: Optional[VelocityAnalysis] = None + generated_at: datetime = field(default_factory=datetime.now)