From 72eb68364813677e3b0f92365471fb4c0bc2956d Mon Sep 17 00:00:00 2001 From: 24_OskinEA <24_OskinEA@iux.local> Date: Tue, 26 May 2026 20:56:15 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20git=5Fanalyzer.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- git_analyzer.py | 76 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/git_analyzer.py b/git_analyzer.py index 0bc9d31..96ae44b 100644 --- a/git_analyzer.py +++ b/git_analyzer.py @@ -4,37 +4,55 @@ import subprocess import tempfile from pathlib import Path from datetime import datetime -from dataclasses import dataclass, field - -@dataclass class CommitInfo: - hash: str - short: str - author: str - date: str - timestamp: int - message: str + def __init__(self, hash, short, author, date, timestamp, message): + self.hash = hash + self.short = short + self.author = author + self.date = date + self.timestamp = timestamp + self.message = message + + def __repr__(self): + return ( + f"CommitInfo(hash={self.hash!r}, short={self.short!r}, author={self.author!r}, " + f"date={self.date!r}, timestamp={self.timestamp!r}, message={self.message!r})" + ) -@dataclass class BranchInfo: - name: str - ref: str - total_files: int = 0 - total_lines: int = 0 + def __init__(self, name, ref, total_files=0, total_lines=0): + self.name = name + self.ref = ref + self.total_files = total_files + self.total_lines = total_lines + + def __repr__(self): + return ( + f"BranchInfo(name={self.name!r}, ref={self.ref!r}, " + f"total_files={self.total_files!r}, total_lines={self.total_lines!r})" + ) -@dataclass class RepositoryInfo: - link: str - repo_name: str - default_branch: str - branches: list = field(default_factory=list) - commits: list = field(default_factory=list) - total_files: int = 0 - total_lines: int = 0 + def __init__(self, link, repo_name, default_branch, branches=None, commits=None, total_files=0, total_lines=0): + self.link = link + self.repo_name = repo_name + self.default_branch = default_branch + self.branches = branches if branches is not None else [] + self.commits = commits if commits is not None else [] + self.total_files = total_files + self.total_lines = total_lines + + def __repr__(self): + return ( + f"RepositoryInfo(link={self.link!r}, repo_name={self.repo_name!r}, " + f"default_branch={self.default_branch!r}, branches={self.branches!r}, " + f"commits={self.commits!r}, total_files={self.total_files!r}, " + f"total_lines={self.total_lines!r})" + ) LANG_EXTENSIONS = { @@ -317,6 +335,9 @@ def read_file_at_ref(repo_dir, ref, path): def get_branch_commits(repo_dir, branch_ref): + """Коммиты конкретной ветки от старых к новым, с timestamp. + Это нужно, чтобы на старой версии не показывать ветку, которой тогда ещё не было. + """ fmt = "%H%x1f%h%x1f%an%x1f%ad%x1f%at%x1f%s" try: out = run_git(["log", branch_ref, "--reverse", "--date=iso", f"--pretty=format:{fmt}"], cwd=repo_dir) @@ -338,6 +359,10 @@ def get_branch_commits(repo_dir, branch_ref): def branch_first_unique_timestamp(repo_dir, branch_ref, default_ref): + """Когда ветка реально стала отдельной. + Git не хранит дату создания ветки, поэтому берём первый коммит ветки, + которого нет в основной ветке. Если таких нет — ветка считается старой. + """ if branch_ref == default_ref: return None result = run_git_allow_fail(["log", "--reverse", "--format=%at", f"{default_ref}..{branch_ref}"], cwd=repo_dir) @@ -527,6 +552,13 @@ def format_analysis(data): class GitAnalyzer: + """Главный класс анализа Git-репозиториев. + + В старых версиях проекта логика была набором функций. + В OOP-версии интерфейс создаёт объект GitAnalyzer и вызывает его методы. + Так проще строить диаграмму классов и объяснять систему как набор объектов. + """ + def __init__(self): self.languages = LANG_EXTENSIONS self.ignore_dirs = IGNORE_DIRS