Merge pull request #7050 from DDSRem-Dev/codex-comment-migration

docs: 统一全项目中文注释和结构化契约说明
This commit is contained in:
DDSRem
2026-10-17 19:26:29 +08:00
committed by GitHub
parent 3c7431b7da
commit 2de976f6b3
2345 changed files with 143990 additions and 61534 deletions

View File

@@ -1,29 +1,34 @@
"""submit-pull-request Skill 的离线单元测试。"""
"""
submit-pull-request Skill 的离线单元测试。
"""
from __future__ import annotations
import importlib
import json
import os
import subprocess
import sys
from contextlib import contextmanager
from pathlib import Path
from unittest.mock import patch
import pytest
SCRIPT_DIR = Path(__file__).resolve().parents[1] / "skills" / "submit-pull-request" / "scripts"
if str(SCRIPT_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPT_DIR))
import clone_repository as clone_script # noqa: E402
import collect_pull_request as collect_script # noqa: E402
import pr_common as common # noqa: E402
import prepare_pull_request as prepare_script # noqa: E402
import submit_pull_request as submit_script # noqa: E402
# 只在导入脚本时添加搜索路径,避免改变后续测试的模块解析顺序。
with patch.object(sys, "path", [str(SCRIPT_DIR), *sys.path]):
clone_script = importlib.import_module("clone_repository")
collect_script = importlib.import_module("collect_pull_request")
common = importlib.import_module("pr_common")
prepare_script = importlib.import_module("prepare_pull_request")
submit_script = importlib.import_module("submit_pull_request")
def _git(root: Path, *arguments: str) -> str:
"""运行测试所需的本地 Git 命令。"""
"""
运行测试所需的本地 Git 命令。
"""
result = subprocess.run(
["git", *arguments],
cwd=root,
@@ -36,7 +41,9 @@ def _git(root: Path, *arguments: str) -> str:
def _repo(tmp_path: Path) -> Path:
"""创建有初始 Commit 的临时 clone 替身。"""
"""
创建有初始 Commit 的临时 clone 替身。
"""
root = tmp_path / "repo"
root.mkdir()
_git(root.parent, "init", str(root))
@@ -51,19 +58,25 @@ def _repo(tmp_path: Path) -> Path:
def _set_runtime_dir(monkeypatch, path: Path) -> None:
"""把 Skill 临时文件指向当前测试目录。"""
"""
把 Skill 临时文件指向当前测试目录。
"""
monkeypatch.setattr(common, "get_runtime_setting", lambda key: str(path))
def test_collect_requires_a_real_git_clone(tmp_path: Path) -> None:
"""没有 Git 仓库时必须明确失败,不回退到文件清单模式。"""
"""
没有 Git 仓库时必须明确失败,不回退到文件清单模式。
"""
with pytest.raises(common.PullRequestError) as error:
common.collect_changes(tmp_path)
assert error.value.reason == "git_required"
def test_collect_records_tracked_untracked_and_deleted_files(tmp_path: Path) -> None:
"""采集器应覆盖修改、新增和删除,并保留模式与摘要。"""
"""
采集器应覆盖修改、新增和删除,并保留模式与摘要。
"""
root = _repo(tmp_path)
(root / "tracked.py").write_text("value = 2\n", encoding="utf-8")
(root / "new.py").write_text("created = True\n", encoding="utf-8")
@@ -80,7 +93,9 @@ def test_collect_records_tracked_untracked_and_deleted_files(tmp_path: Path) ->
def test_collect_rejects_runtime_paths(tmp_path: Path) -> None:
"""运行时和敏感路径不能进入 PR。"""
"""
运行时和敏感路径不能进入 PR。
"""
root = _repo(tmp_path)
(root / ".env").write_text("SECRET=not-for-pr\n", encoding="utf-8")
with pytest.raises(common.PullRequestError) as error:
@@ -89,7 +104,9 @@ def test_collect_rejects_runtime_paths(tmp_path: Path) -> None:
def test_changes_preview_detects_post_preview_edit(tmp_path: Path, monkeypatch) -> None:
"""用户确认后若文件再次变化,提交前必须拒绝。"""
"""
用户确认后若文件再次变化,提交前必须拒绝。
"""
root = _repo(tmp_path)
_set_runtime_dir(monkeypatch, tmp_path / "runtime")
(root / "tracked.py").write_text("value = 2\n", encoding="utf-8")
@@ -108,17 +125,25 @@ def test_changes_preview_detects_post_preview_edit(tmp_path: Path, monkeypatch)
def test_ensure_fork_reuses_existing_fork() -> None:
"""已有且 parent 正确的 Fork 不应重复创建。"""
"""
已有且 parent 正确的 Fork 不应重复创建。
"""
class FakeClient:
"""已有 Fork 场景的最小 GitHub API 替身。"""
"""
已有 Fork 场景的最小 GitHub API 替身。
"""
def __init__(self) -> None:
"""记录是否错误地请求了创建 Fork。"""
"""
记录是否错误地请求了创建 Fork。
"""
self.created = False
def get_repo(self, repo: str) -> dict:
"""返回目标 Fork 及其 parent。"""
"""
返回目标 Fork 及其 parent。
"""
assert repo == "bot/MoviePilot"
return {
"fork": True,
@@ -127,7 +152,9 @@ def test_ensure_fork_reuses_existing_fork() -> None:
}
def create_fork(self, repo: str) -> dict:
"""记录创建调用,测试应保持为零次。"""
"""
记录创建调用,测试应保持为零次。
"""
self.created = True
return {}
@@ -139,25 +166,35 @@ def test_ensure_fork_reuses_existing_fork() -> None:
def test_ensure_fork_creates_after_not_found(monkeypatch) -> None:
"""不存在的 Fork 只创建一次,并等待异步创建完成。"""
"""
不存在的 Fork 只创建一次,并等待异步创建完成。
"""
class FakeClient:
"""异步 Fork 创建场景的最小 GitHub API 替身。"""
"""
异步 Fork 创建场景的最小 GitHub API 替身。
"""
def __init__(self) -> None:
"""初始化查询和创建计数。"""
"""
初始化查询和创建计数。
"""
self.lookups = 0
self.created = 0
def get_repo(self, repo: str) -> dict:
"""第一次查询返回 404,随后返回已创建 Fork。"""
"""
第一次查询返回 404,随后返回已创建 Fork。
"""
self.lookups += 1
if self.lookups == 1:
raise common.GitHubApiError("github_api_error", "not found", status=404)
return {"fork": True, "parent": {"full_name": "jxxghp/MoviePilot"}}
def create_fork(self, repo: str) -> dict:
"""记录一次 Fork 创建请求。"""
"""
记录一次 Fork 创建请求。
"""
self.created += 1
return {}
@@ -170,7 +207,9 @@ def test_ensure_fork_creates_after_not_found(monkeypatch) -> None:
def test_clone_repository_uses_upstream_base_and_writes_state(tmp_path: Path, monkeypatch) -> None:
"""clone 脚本应从上游基线创建新分支,而不是直接修改 Fork 默认分支。"""
"""
clone 脚本应从上游基线创建新分支,而不是直接修改 Fork 默认分支。
"""
source = _repo(tmp_path)
upstream_bare = tmp_path / "upstream.git"
fork_bare = tmp_path / "fork.git"
@@ -179,18 +218,26 @@ def test_clone_repository_uses_upstream_base_and_writes_state(tmp_path: Path, mo
base_sha = _git(source, "rev-parse", "main")
class FakeClient:
"""clone 脚本 API 依赖的最小替身。"""
"""
clone 脚本 API 依赖的最小替身。
"""
def get_user(self) -> dict:
"""返回当前用户。"""
"""
返回当前用户。
"""
return {"login": "bot"}
def get_repo(self, repo: str) -> dict:
"""返回目标仓库默认分支。"""
"""
返回目标仓库默认分支。
"""
return {"default_branch": "main"}
def get_ref(self, repo: str, branch: str) -> dict:
"""返回上游基线,工作分支模拟不存在。"""
"""
返回上游基线,工作分支模拟不存在。
"""
if repo == "jxxghp/MoviePilot":
return {"object": {"sha": base_sha}}
raise common.GitHubApiError("github_api_error", "not found", status=404)
@@ -214,7 +261,9 @@ def test_clone_repository_uses_upstream_base_and_writes_state(tmp_path: Path, mo
@contextmanager
def fake_git_auth(headers):
"""不让离线测试创建真实认证脚本。"""
"""
不让离线测试创建真实认证脚本。
"""
yield os.environ.copy()
monkeypatch.setattr(clone_script, "git_auth_environment", fake_git_auth)
@@ -232,7 +281,9 @@ def test_clone_repository_uses_upstream_base_and_writes_state(tmp_path: Path, mo
def test_prepare_without_token_stops_before_api_write(tmp_path: Path, monkeypatch) -> None:
"""没有 Token 时预览也应明确阻塞,而不是伪造可提交状态。"""
"""
没有 Token 时预览也应明确阻塞,而不是伪造可提交状态。
"""
root = _repo(tmp_path)
_set_runtime_dir(monkeypatch, tmp_path / "runtime")
(root / "tracked.py").write_text("value = 2\n", encoding="utf-8")
@@ -260,7 +311,9 @@ def test_prepare_without_token_stops_before_api_write(tmp_path: Path, monkeypatc
def test_submit_commits_pushes_and_creates_pr_with_fake_github(tmp_path: Path, monkeypatch) -> None:
"""提交脚本应真实创建本地 Commit,但用假 API 隔离外网副作用。"""
"""
提交脚本应真实创建本地 Commit,但用假 API 隔离外网副作用。
"""
root = _repo(tmp_path)
_git(root, "remote", "add", "origin", "https://github.com/bot/MoviePilot.git")
base_sha = _git(root, "rev-parse", "HEAD")
@@ -293,22 +346,32 @@ def test_submit_commits_pushes_and_creates_pr_with_fake_github(tmp_path: Path, m
)
class FakeClient:
"""提交流程使用的最小 GitHub API 替身。"""
"""
提交流程使用的最小 GitHub API 替身。
"""
def __init__(self, **kwargs) -> None:
"""初始化远端分支状态。"""
"""
初始化远端分支状态。
"""
self.remote_sha = None
def get_user(self) -> dict:
"""返回预览时使用的 Token 用户。"""
"""
返回预览时使用的 Token 用户。
"""
return {"login": "bot"}
def get_repo(self, repo: str) -> dict:
"""返回目标 Fork parent。"""
"""
返回目标 Fork parent。
"""
return {"fork": True, "parent": {"full_name": "jxxghp/MoviePilot"}}
def get_ref(self, repo: str, ref_branch: str) -> dict:
"""返回上游基线或模拟推送后的 Fork 分支。"""
"""
返回上游基线或模拟推送后的 Fork 分支。
"""
if repo == "jxxghp/MoviePilot":
return {"object": {"sha": base_sha}}
if self.remote_sha:
@@ -316,11 +379,15 @@ def test_submit_commits_pushes_and_creates_pr_with_fake_github(tmp_path: Path, m
raise common.GitHubApiError("github_api_error", "not found", status=404)
def list_open_pulls(self, repo: str, *, head: str, base: str) -> list[dict]:
"""模拟尚无开放 PR。"""
"""
模拟尚无开放 PR。
"""
return []
def create_pull(self, repo: str, payload: dict) -> dict:
"""返回已验证的 PR 对象。"""
"""
返回已验证的 PR 对象。
"""
return {
"html_url": "https://github.com/jxxghp/MoviePilot/pull/1",
"number": 1,
@@ -339,7 +406,9 @@ def test_submit_commits_pushes_and_creates_pr_with_fake_github(tmp_path: Path, m
real_run_git = submit_script.run_git
def run_git_with_fake_push(root_path: Path, *arguments: str, env=None):
"""让测试绕过网络 Push,但保留真实本地 Git 操作。"""
"""
让测试绕过网络 Push,但保留真实本地 Git 操作。
"""
if arguments and arguments[0] == "push":
fake_client.remote_sha = common.git_output(root_path, "rev-parse", "HEAD").decode().strip()
return subprocess.CompletedProcess(["git", *arguments], 0, b"", b"")
@@ -347,7 +416,9 @@ def test_submit_commits_pushes_and_creates_pr_with_fake_github(tmp_path: Path, m
@contextmanager
def fake_git_auth(headers):
"""为离线测试提供不含凭据的 Git 环境。"""
"""
为离线测试提供不含凭据的 Git 环境。
"""
yield os.environ.copy()
monkeypatch.setattr(submit_script, "run_git", run_git_with_fake_push)