Обновить git_analyzer.py

This commit is contained in:
2026-05-26 20:56:15 +03:00
parent bb429c38c6
commit 72eb683648

View File

@@ -4,37 +4,55 @@ import subprocess
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
from dataclasses import dataclass, field
@dataclass
class CommitInfo: class CommitInfo:
hash: str def __init__(self, hash, short, author, date, timestamp, message):
short: str self.hash = hash
author: str self.short = short
date: str self.author = author
timestamp: int self.date = date
message: str 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: class BranchInfo:
name: str def __init__(self, name, ref, total_files=0, total_lines=0):
ref: str self.name = name
total_files: int = 0 self.ref = ref
total_lines: int = 0 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: class RepositoryInfo:
link: str def __init__(self, link, repo_name, default_branch, branches=None, commits=None, total_files=0, total_lines=0):
repo_name: str self.link = link
default_branch: str self.repo_name = repo_name
branches: list = field(default_factory=list) self.default_branch = default_branch
commits: list = field(default_factory=list) self.branches = branches if branches is not None else []
total_files: int = 0 self.commits = commits if commits is not None else []
total_lines: int = 0 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 = { LANG_EXTENSIONS = {
@@ -317,6 +335,9 @@ def read_file_at_ref(repo_dir, ref, path):
def get_branch_commits(repo_dir, branch_ref): def get_branch_commits(repo_dir, branch_ref):
"""Коммиты конкретной ветки от старых к новым, с timestamp.
Это нужно, чтобы на старой версии не показывать ветку, которой тогда ещё не было.
"""
fmt = "%H%x1f%h%x1f%an%x1f%ad%x1f%at%x1f%s" fmt = "%H%x1f%h%x1f%an%x1f%ad%x1f%at%x1f%s"
try: try:
out = run_git(["log", branch_ref, "--reverse", "--date=iso", f"--pretty=format:{fmt}"], cwd=repo_dir) 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): def branch_first_unique_timestamp(repo_dir, branch_ref, default_ref):
"""Когда ветка реально стала отдельной.
Git не хранит дату создания ветки, поэтому берём первый коммит ветки,
которого нет в основной ветке. Если таких нет — ветка считается старой.
"""
if branch_ref == default_ref: if branch_ref == default_ref:
return None return None
result = run_git_allow_fail(["log", "--reverse", "--format=%at", f"{default_ref}..{branch_ref}"], cwd=repo_dir) 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: class GitAnalyzer:
"""Главный класс анализа Git-репозиториев.
В старых версиях проекта логика была набором функций.
В OOP-версии интерфейс создаёт объект GitAnalyzer и вызывает его методы.
Так проще строить диаграмму классов и объяснять систему как набор объектов.
"""
def __init__(self): def __init__(self):
self.languages = LANG_EXTENSIONS self.languages = LANG_EXTENSIONS
self.ignore_dirs = IGNORE_DIRS self.ignore_dirs = IGNORE_DIRS