Files
CraftKit/migration/tests/test_git_integrate.py
T

80 lines
4.2 KiB
Python

"""验证预集成 Skill 的文档契约和隔离 Git 行为。"""
from __future__ import annotations
import subprocess
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
SKILL = ROOT / "plugins/git/skills/integrate/SKILL.md"
class GitIntegrateTests(unittest.TestCase):
"""在临时仓库中验证 worktree 集成不会移动输入引用。"""
def git(self, repo: Path, *args: str, check: bool = True) -> subprocess.CompletedProcess[str]:
"""执行测试仓库中的 Git 命令并保留失败状态供冲突断言。"""
return subprocess.run(["git", "-C", str(repo), *args], capture_output=True, text=True, encoding="utf-8", check=check)
def make_repo(self, root: Path, conflict: bool = False) -> tuple[Path, str, str]:
"""创建具有源、目标分叉的隔离仓库。"""
repo = root / "repo"; repo.mkdir(); self.git(repo, "init", "-q")
self.git(repo, "config", "user.name", "Test User"); self.git(repo, "config", "user.email", "test@example.invalid")
(repo / "base.txt").write_text("base\n", encoding="utf-8")
self.git(repo, "add", "base.txt"); self.git(repo, "commit", "-q", "-m", "base")
self.git(repo, "branch", "target"); self.git(repo, "switch", "-q", "-c", "source")
source_file = repo / ("base.txt" if conflict else "source.txt")
source_file.write_text("source\n", encoding="utf-8")
self.git(repo, "add", "-A"); self.git(repo, "commit", "-q", "-m", "source")
source_hash = self.git(repo, "rev-parse", "source").stdout.strip()
self.git(repo, "switch", "-q", "target")
target_file = repo / ("base.txt" if conflict else "target.txt")
target_file.write_text("target\n", encoding="utf-8")
self.git(repo, "add", "-A"); self.git(repo, "commit", "-q", "-m", "target")
target_hash = self.git(repo, "rev-parse", "target").stdout.strip()
return repo, source_hash, target_hash
def test_isolated_merge_preserves_source_and_target_refs(self) -> None:
"""预集成分支发生 merge 后,源和目标引用必须保持原哈希。"""
with tempfile.TemporaryDirectory() as temp:
root = Path(temp); repo, source_hash, target_hash = self.make_repo(root)
worktree = root / "integration"
self.git(repo, "worktree", "add", "-q", "-b", "pre/integration", str(worktree), "target")
self.git(worktree, "merge", "--no-edit", "source")
self.assertEqual(source_hash, self.git(repo, "rev-parse", "source").stdout.strip())
self.assertEqual(target_hash, self.git(repo, "rev-parse", "target").stdout.strip())
self.assertTrue((worktree / "source.txt").is_file())
self.assertTrue((worktree / "target.txt").is_file())
def test_conflict_stops_before_automatic_resolution(self) -> None:
"""真实冲突应停留在未合并状态,不移动源或目标引用。"""
with tempfile.TemporaryDirectory() as temp:
root = Path(temp); repo, source_hash, target_hash = self.make_repo(root, conflict=True)
worktree = root / "integration"
self.git(repo, "worktree", "add", "-q", "-b", "pre/conflict", str(worktree), "target")
result = self.git(worktree, "merge", "--no-edit", "source", check=False)
self.assertNotEqual(0, result.returncode)
self.assertIn("UU base.txt", self.git(worktree, "status", "--short").stdout)
self.assertEqual(source_hash, self.git(repo, "rev-parse", "source").stdout.strip())
self.assertEqual(target_hash, self.git(repo, "rev-parse", "target").stdout.strip())
def test_skill_separates_stages_and_protects_delivery(self) -> None:
"""Skill 必须保留阶段授权、环境配置阻断和强推禁用边界。"""
text = SKILL.read_text(encoding="utf-8")
for value in ("assess", "prepare", "publish", "独立 worktree", "环境配置", "私钥"):
self.assertIn(value, text)
publish = (SKILL.parent / "references/publish.md").read_text(encoding="utf-8")
self.assertIn("默认不改用 `--force`", publish)
if __name__ == "__main__":
unittest.main()