kyorlin2001/code-analysis-tool
0
1from __future__ import annotations2 3from dataclasses import dataclass4from pathlib import Path5from tempfile import TemporaryDirectory6from zipfile import ZipFile, BadZipFile7 8import requests9 10from tools.repo_loader import RepositoryData, build_file_tree, list_repository_files11 12 13@dataclass14class ExtractedGitHubRepository:15 data: RepositoryData16 temp_dir: TemporaryDirectory17 18 19def load_repository_from_github(20 owner: str,21 repo: str,22 branch: str = "main",23 token: str | None = None,24) -> ExtractedGitHubRepository:25 """26 Download a GitHub repository archive and normalize it into RepositoryData.27 """28 archive_url = f"https://api.github.com/repos/{owner}/{repo}/zipball/{branch}"29 30 headers = {31 "Accept": "application/vnd.github+json",32 }33 if token:34 headers["Authorization"] = f"Bearer {token}"35 36 response = requests.get(archive_url, headers=headers, timeout=60)37 response.raise_for_status()38 39 temp_dir = TemporaryDirectory(prefix="agentic_code_analysis_github_")40 temp_root = Path(temp_dir.name)41 zip_path = temp_root / f"{repo}.zip"42 zip_path.write_bytes(response.content)43 44 try:45 with ZipFile(zip_path, "r") as zip_ref:46 zip_ref.extractall(temp_root)47 except BadZipFile as exc:48 temp_dir.cleanup()49 raise ValueError("GitHub archive could not be extracted.") from exc50 51 extracted_root = _find_extracted_root(temp_root)52 53 repo_data = RepositoryData(54 repo_name=repo,55 file_tree=build_file_tree(extracted_root),56 files=list_repository_files(extracted_root),57 root_dir=str(extracted_root),58 )59 60 return ExtractedGitHubRepository(data=repo_data, temp_dir=temp_dir)61 62 63def _find_extracted_root(temp_root: Path) -> Path:64 entries = [p for p in temp_root.iterdir() if p.name != "__MACOSX"]65 66 dirs = [p for p in entries if p.is_dir()]67 files = [p for p in entries if p.is_file()]68 69 if len(dirs) == 1 and not files:70 return dirs[0]71 72 return temp_root