d791f5584c
- skills/manage-release -> skills/releaser(git mv,内容不变) - releaser 的 frontmatter/标题改名,description 保留旧名作为触发词 - skills/manage-release/ 保留为纯弃用占位(SKILL.md + README.md,指向 releaser), 已装软链与旧项目 .pouch.yaml 不再悬空或失效 - 同步或引用:AGENTS.md、README.md、docs/getting-started.md、orc(routing/SKILL/README)、 ack delivery、builder(SKILL/README/contract)、memory-distill、pouch onboard 与 suggest_skills - 测试:catalog 需列出旧名占位,新增弃用占位断言,orc children 纳入旧名占位
137 lines
5.6 KiB
Python
137 lines
5.6 KiB
Python
from __future__ import annotations
|
||
|
||
import subprocess
|
||
import sys
|
||
import tempfile
|
||
import unittest
|
||
from pathlib import Path
|
||
|
||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||
CATALOG = REPO_ROOT / "skills" / "pouch" / "scripts" / "catalog.py"
|
||
SUGGEST = REPO_ROOT / "skills" / "pouch" / "scripts" / "suggest_skills.py"
|
||
|
||
|
||
def _run(script: Path, *args: str) -> subprocess.CompletedProcess[str]:
|
||
return subprocess.run(
|
||
[sys.executable, str(script), *args],
|
||
check=False,
|
||
capture_output=True,
|
||
text=True,
|
||
)
|
||
|
||
|
||
class CatalogTests(unittest.TestCase):
|
||
def test_repo_skills_have_lede_and_example(self) -> None:
|
||
result = _run(CATALOG, "--skills-dir", str(REPO_ROOT / "skills"))
|
||
self.assertEqual(result.returncode, 0, result.stderr)
|
||
for name in (
|
||
"ack",
|
||
"builder",
|
||
"deployer",
|
||
"host-sec-check",
|
||
"releaser",
|
||
"note-style",
|
||
"pouch",
|
||
# 旧名兼容占位,仍须可列出(见 test_manage_release_is_deprecation_stub)
|
||
"manage-release",
|
||
):
|
||
self.assertIn(f"| {name} |", result.stdout)
|
||
self.assertIn("/ack 初始化", result.stdout)
|
||
self.assertIn("用 builder 初始化这个项目", result.stdout)
|
||
self.assertNotIn("触发词", result.stdout)
|
||
|
||
def test_manage_release_is_deprecation_stub(self) -> None:
|
||
"""旧名只保留指向 releaser 的占位,不得再携带流程或参考资料。"""
|
||
stub = REPO_ROOT / "skills" / "manage-release"
|
||
skill = (stub / "SKILL.md").read_text(encoding="utf-8")
|
||
self.assertIn("name: manage-release", skill)
|
||
self.assertIn("已弃用", skill)
|
||
self.assertIn("../releaser/SKILL.md", skill)
|
||
self.assertTrue((REPO_ROOT / "skills" / "releaser" / "SKILL.md").is_file())
|
||
self.assertFalse((stub / "references").exists())
|
||
self.assertFalse((stub / "templates").exists())
|
||
|
||
def test_missing_readme_fails(self) -> None:
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
skill = Path(tmp) / "demo"
|
||
skill.mkdir()
|
||
(skill / "SKILL.md").write_text(
|
||
"---\nname: demo\ndescription: d\n---\n# demo\n",
|
||
encoding="utf-8",
|
||
)
|
||
result = _run(CATALOG, "--skills-dir", tmp)
|
||
self.assertEqual(result.returncode, 1)
|
||
self.assertIn("缺少 README.md", result.stderr)
|
||
|
||
def test_extracts_first_sentence_and_skips_hash_comments(self) -> None:
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
skill = Path(tmp) / "demo"
|
||
skill.mkdir()
|
||
(skill / "SKILL.md").write_text(
|
||
"---\nname: demo\ndescription: d\n---\n# demo\n",
|
||
encoding="utf-8",
|
||
)
|
||
(skill / "README.md").write_text(
|
||
"# demo\n\n"
|
||
"这是一句话说明。后面还有一句不该进短清单。\n\n"
|
||
"## 使用示例\n\n"
|
||
"```text\n"
|
||
"# 注释\n"
|
||
"用 demo 做这件事。\n"
|
||
"```\n",
|
||
encoding="utf-8",
|
||
)
|
||
result = _run(CATALOG, "--skills-dir", tmp)
|
||
self.assertEqual(result.returncode, 0, result.stderr)
|
||
self.assertIn("这是一句话说明。", result.stdout)
|
||
self.assertNotIn("不该进短清单", result.stdout)
|
||
self.assertIn("用 demo 做这件事。", result.stdout)
|
||
|
||
|
||
class SuggestSkillsTests(unittest.TestCase):
|
||
def test_pouch_repo_is_not_an_app(self) -> None:
|
||
result = _run(SUGGEST, str(REPO_ROOT))
|
||
self.assertEqual(result.returncode, 0, result.stderr)
|
||
self.assertIn("this_is_pouch_repo: true", result.stdout)
|
||
self.assertNotIn("suggested:", result.stdout)
|
||
|
||
def test_dockerfile_suggests_builder(self) -> None:
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
root = Path(tmp)
|
||
(root / "Dockerfile").write_text("FROM scratch\n", encoding="utf-8")
|
||
result = _run(SUGGEST, str(root))
|
||
self.assertEqual(result.returncode, 0, result.stderr)
|
||
self.assertIn("this_is_pouch_repo: false", result.stdout)
|
||
self.assertIn("builder", result.stdout)
|
||
self.assertIn("Dockerfile", result.stdout)
|
||
self.assertIn("用 builder 初始化", result.stdout)
|
||
self.assertIn("不要 `pouch init builder`", result.stdout)
|
||
|
||
def test_existing_makefile_builder_is_already(self) -> None:
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
root = Path(tmp)
|
||
(root / "makefile.builder").write_text("build:\n", encoding="utf-8")
|
||
result = _run(SUGGEST, str(root))
|
||
self.assertEqual(result.returncode, 0, result.stderr)
|
||
self.assertIn("already:", result.stdout)
|
||
self.assertIn("builder", result.stdout)
|
||
self.assertIn("init: (none)", result.stdout)
|
||
|
||
def test_compose_and_ack_dir(self) -> None:
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
root = Path(tmp)
|
||
(root / "compose.yaml").write_text("services: {}\n", encoding="utf-8")
|
||
(root / ".pouch" / "ack").mkdir(parents=True)
|
||
result = _run(SUGGEST, str(root))
|
||
self.assertEqual(result.returncode, 0, result.stderr)
|
||
self.assertIn("deployer", result.stdout)
|
||
self.assertIn("compose.yaml", result.stdout)
|
||
self.assertIn("ack", result.stdout)
|
||
self.assertIn(".pouch/ack", result.stdout)
|
||
self.assertIn("用 deployer 初始化", result.stdout)
|
||
self.assertNotIn("/ack 初始化", result.stdout)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|