import os import shutil import subprocess import tempfile from datetime import datetime CODE_EXTENSIONS = { '.py', '.js', '.ts', '.java', '.c', '.cpp', '.h', '.hpp', '.cs', '.php', '.rb', '.go', '.rs', '.kt', '.swift', '.html', '.css', '.scss', '.json', '.xml', '.yaml', '.yml', '.sh', '.bat', '.sql', '.md' } SKIP_DIRS = {'.git', 'node_modules', '__pycache__', 'venv', '.venv', 'dist', 'build'} def run_cmd(cmd, cwd=None): result = subprocess.run( cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=60, ) if result.returncode != 0: raise Exception(result.stderr.strip() or result.stdout.strip()) return result.stdout.strip() def repo_name_from_url(url): name = url.rstrip('/').split('/')[-1] if name.endswith('.git'): name = name[:-4] return name or 'repository' def count_code_lines(repo_path): total = 0 files_count = 0 for root, dirs, files in os.walk(repo_path): dirs[:] = [d for d in dirs if d not in SKIP_DIRS] for filename in files: ext = os.path.splitext(filename)[1].lower() if ext not in CODE_EXTENSIONS: continue path = os.path.join(root, filename) try: with open(path, 'r', encoding='utf-8', errors='ignore') as f: total += len(f.readlines()) files_count += 1 except Exception: pass return total, files_count def analyze_repository(repo_url): temp_dir = tempfile.mkdtemp(prefix='git_analyzer_') repo_dir = os.path.join(temp_dir, repo_name_from_url(repo_url)) try: run_cmd(['git', 'clone', '--depth', '100', repo_url, repo_dir]) repo_name = repo_name_from_url(repo_url) authors_raw = run_cmd(['git', 'log', '--format=%an'], cwd=repo_dir) authors = [] for name in authors_raw.splitlines(): name = name.strip() if name and name not in authors: authors.append(name) created = run_cmd(['git', 'log', '--reverse', '--format=%ci', '-1'], cwd=repo_dir) updated = run_cmd(['git', 'log', '-1', '--format=%ci'], cwd=repo_dir) commits_count = run_cmd(['git', 'rev-list', '--count', 'HEAD'], cwd=repo_dir) branch = run_cmd(['git', 'branch', '--show-current'], cwd=repo_dir) lines, files_count = count_code_lines(repo_dir) main_author = authors[0] if authors else 'нет данных' coauthors = authors[1:] text = [] text.append(f'Ссылка: {repo_url}') text.append(f'Название репозитория: {repo_name}') text.append(f'Ветка: {branch or "не определена"}') text.append('') text.append(f'Автор по первому коммиту: {main_author}') text.append('Соавторы по коммитам:') if coauthors: for a in coauthors: text.append(f'- {a}') else: text.append('- нет соавторов') text.append('') text.append(f'Дата создания по первому коммиту: {created or "нет данных"}') text.append(f'Дата последнего изменения: {updated or "нет данных"}') text.append(f'Количество коммитов: {commits_count or "0"}') text.append(f'Файлов с кодом/текстом: {files_count}') text.append(f'Строк кода/текста: {lines}') return '\n'.join(text) finally: shutil.rmtree(temp_dir, ignore_errors=True)