from __future__ import annotations import json import subprocess import tempfile import unittest from pathlib import Path from pouch.yaml_io import safe_dump, safe_load REPO_ROOT = Path(__file__).resolve().parents[1] CREATE = REPO_ROOT / "skills" / "ship" / "scripts" / "create_ship.py" NEXT = REPO_ROOT / "skills" / "ship" / "scripts" / "next_step.py" def _run(script: Path, *args: str) -> subprocess.CompletedProcess[str]: return subprocess.run( ["python3", str(script), *args], cwd=REPO_ROOT, text=True, capture_output=True, check=False, ) class MultiRootRegressionDispatchTests(unittest.TestCase): def test_regression_dispatch_requires_all_tester_roots(self) -> None: with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) ship_id = "multi-project-regression" created = _run( CREATE, "--project-root", str(root), "--ship-id", ship_id, "--kind", "short", "--title", "列表页增加导出按钮", "--stop-at", "released", ) self.assertEqual(created.returncode, 0, created.stderr) ship_dir = root / ".pouch" / "ship" / ship_id (ship_dir / "spec.md").write_text( """# 导出按钮\n\n## 要做什么\n\n列表页给登录用户一个导出按钮。\n\n## 不做什么\n\n不改权限模型。\n\n## 可观察验收\n\n- 登录后列表页可见导出按钮\n\n## 怎么验\n\n- 浏览器打开 /list 看到按钮\n""", encoding="utf-8", ) tasks = safe_load((ship_dir / "tasks.yaml").read_text(encoding="utf-8")) tasks["tasks"][0].update( status="verified", expected=["登录用户看到导出"], verification=["打开 /list"], ) (ship_dir / "tasks.yaml").write_text(safe_dump(tasks), encoding="utf-8") current = safe_load((ship_dir / "current.yaml").read_text(encoding="utf-8")) current["delivery"]["state"] = "merged" current["evidence"]["commits"] = [{"sha": "abc1234deadbeef", "role": "head"}] (ship_dir / "current.yaml").write_text(safe_dump(current), encoding="utf-8") result = _run( NEXT, "--project-root", str(root), "--ship-id", ship_id, "--entry", "short", ) self.assertEqual(result.returncode, 0, result.stderr) doc = json.loads(result.stdout) self.assertEqual(doc["step"], "regress") self.assertEqual(doc["skill"], "tester") self.assertIn("所有 tester catalog", doc["summary"]) if __name__ == "__main__": unittest.main()