This commit is contained in:
140
.gitea/checker/git_utils.py
Normal file
140
.gitea/checker/git_utils.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
Git 操作工具模块。
|
||||
负责在 CI 环境中检出上一版本代码、获取变更文件列表及提交元信息。
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class CommitInfo:
|
||||
"""单次 Git 提交的元信息。"""
|
||||
|
||||
sha: str
|
||||
author: str
|
||||
commit_time: str
|
||||
message: str
|
||||
|
||||
|
||||
def run_git(args: List[str], cwd: Optional[Path] = None) -> str:
|
||||
"""
|
||||
执行 git 命令并返回标准输出。
|
||||
|
||||
:param args: git 子命令及参数,如 ["log", "-1", "--format=%H"]
|
||||
:param cwd: 工作目录,默认为当前目录
|
||||
:return: 命令 stdout 文本(已 strip)
|
||||
:raises RuntimeError: git 命令执行失败时抛出
|
||||
"""
|
||||
cmd = ["git"] + args
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"Git 命令失败: {' '.join(cmd)}\n{result.stderr}")
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def get_current_commit() -> CommitInfo:
|
||||
"""
|
||||
获取当前 HEAD 提交的元信息(推送人、时间等,用于通知模板)。
|
||||
|
||||
:return: CommitInfo 对象
|
||||
"""
|
||||
sha = run_git(["rev-parse", "HEAD"])
|
||||
author = run_git(["log", "-1", "--format=%an"])
|
||||
commit_time = run_git(["log", "-1", "--format=%ci"])
|
||||
message = run_git(["log", "-1", "--format=%s"])
|
||||
return CommitInfo(sha=sha, author=author, commit_time=commit_time, message=message)
|
||||
|
||||
|
||||
def get_previous_commit_sha() -> Optional[str]:
|
||||
"""
|
||||
获取上一次提交的 SHA(HEAD~1)。
|
||||
若是首次提交则返回 None。
|
||||
|
||||
:return: 上一 commit SHA,或 None
|
||||
"""
|
||||
try:
|
||||
return run_git(["rev-parse", "HEAD~1"])
|
||||
except RuntimeError:
|
||||
return None
|
||||
|
||||
|
||||
def checkout_commit(sha: str, worktree_dir: Path) -> None:
|
||||
"""
|
||||
将指定 commit 的代码检出到独立工作目录(不影响当前工作区)。
|
||||
|
||||
:param sha: 目标 commit SHA
|
||||
:param worktree_dir: git worktree 目录
|
||||
"""
|
||||
worktree_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||
if worktree_dir.exists():
|
||||
# 已存在则先移除旧 worktree
|
||||
run_git(["worktree", "remove", "--force", str(worktree_dir)])
|
||||
run_git(["worktree", "add", str(worktree_dir), sha])
|
||||
|
||||
|
||||
def get_changed_java_controller_files(base_sha: str, head_sha: str) -> List[str]:
|
||||
"""
|
||||
获取两次提交之间变更的 Controller 相关 Java 文件路径。
|
||||
|
||||
:param base_sha: 基准 commit(旧版本)
|
||||
:param head_sha: 目标 commit(新版本)
|
||||
:return: 相对路径列表,如 ["src/main/java/.../UserController.java"]
|
||||
"""
|
||||
diff_output = run_git(["diff", "--name-only", base_sha, head_sha])
|
||||
if not diff_output:
|
||||
return []
|
||||
|
||||
changed = []
|
||||
for line in diff_output.splitlines():
|
||||
line = line.strip()
|
||||
if line.endswith(".java") and "Controller" in line:
|
||||
changed.append(line.replace("\\", "/"))
|
||||
return changed
|
||||
|
||||
|
||||
def get_controller_files_diff(base_sha: str, head_sha: str, changed_files: List[str]) -> str:
|
||||
"""
|
||||
获取变更 Controller 文件的 Git diff,供 LLM 审核接口参数变更时参考。
|
||||
|
||||
:param base_sha: 旧版本 commit SHA
|
||||
:param head_sha: 新版本 commit SHA
|
||||
:param changed_files: 变更文件相对路径列表
|
||||
:return: diff 文本
|
||||
"""
|
||||
if not changed_files:
|
||||
return ""
|
||||
|
||||
try:
|
||||
return run_git(["diff", base_sha, head_sha, "--"] + changed_files)
|
||||
except RuntimeError as exc:
|
||||
print(f"[警告] 获取 Git diff 失败: {exc}")
|
||||
return ""
|
||||
|
||||
|
||||
def prepare_worktrees(repo_root: Path) -> tuple:
|
||||
"""
|
||||
准备新旧两个版本的代码工作目录,供 AST 解析器分别扫描。
|
||||
|
||||
:param repo_root: 仓库根目录
|
||||
:return: (新版本目录, 旧版本目录, 旧版本SHA);首次提交时旧版本目录为 None
|
||||
"""
|
||||
prev_sha = get_previous_commit_sha()
|
||||
current_dir = repo_root
|
||||
|
||||
if prev_sha is None:
|
||||
return current_dir, None, None
|
||||
|
||||
prev_dir = repo_root / ".gitea" / ".cache" / "prev-worktree"
|
||||
checkout_commit(prev_sha, prev_dir)
|
||||
return current_dir, prev_dir, prev_sha
|
||||
Reference in New Issue
Block a user