♻️ refactor(test): consolidate repository checks
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPT = ROOT / "scripts" / "playbook.py"
|
||||
MODE_ROOTS = {
|
||||
"snapshot": Path("custom/playbook"),
|
||||
"subtree": Path("docs/standards/playbook"),
|
||||
}
|
||||
|
||||
|
||||
def run_playbook(
|
||||
script: Path, config: Path, project_root: Path
|
||||
) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
[sys.executable, str(script), "-config", str(config)],
|
||||
cwd=project_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
def copy_subtree_source(destination: Path) -> None:
|
||||
destination.mkdir(parents=True)
|
||||
shutil.copy2(ROOT / ".gitattributes", destination / ".gitattributes")
|
||||
|
||||
for name in ("scripts", "templates"):
|
||||
shutil.copytree(
|
||||
ROOT / name,
|
||||
destination / name,
|
||||
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
||||
)
|
||||
|
||||
(destination / "docs").mkdir()
|
||||
for name in ("common", "tsl", "markdown"):
|
||||
shutil.copytree(ROOT / "docs" / name, destination / "docs" / name)
|
||||
|
||||
(destination / "rulesets").mkdir()
|
||||
shutil.copy2(
|
||||
ROOT / "rulesets" / "index.md",
|
||||
destination / "rulesets" / "index.md",
|
||||
)
|
||||
for name in ("tsl", "markdown"):
|
||||
shutil.copytree(
|
||||
ROOT / "rulesets" / name,
|
||||
destination / "rulesets" / name,
|
||||
)
|
||||
|
||||
(destination / "skills").mkdir()
|
||||
shutil.copytree(
|
||||
ROOT / "skills" / "style-cleanup",
|
||||
destination / "skills" / "style-cleanup",
|
||||
)
|
||||
|
||||
|
||||
def write_config(project_root: Path, install_mode: str, playbook_root: Path) -> Path:
|
||||
config = project_root / "playbook.toml"
|
||||
config.write_text(
|
||||
f"""
|
||||
[playbook]
|
||||
project_root = "."
|
||||
playbook_root = "{playbook_root.as_posix()}"
|
||||
install_mode = "{install_mode}"
|
||||
|
||||
[sync_rules]
|
||||
date = "2026-01-01"
|
||||
no_backup = true
|
||||
|
||||
[sync_memory_bank]
|
||||
project_name = "Demo"
|
||||
no_backup = true
|
||||
|
||||
[sync_prompts]
|
||||
no_backup = true
|
||||
|
||||
[sync_standards]
|
||||
langs = ["tsl", "markdown"]
|
||||
gitattr_mode = "overwrite"
|
||||
no_backup = true
|
||||
|
||||
[install_skills]
|
||||
agents_home = ".test-agents"
|
||||
mode = "list"
|
||||
skills = ["style-cleanup"]
|
||||
no_backup = true
|
||||
""".lstrip(),
|
||||
encoding="utf-8",
|
||||
newline="\n",
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
def seed_custom_files(project_root: Path) -> None:
|
||||
custom_memory = project_root / "memory-bank" / "custom.md"
|
||||
custom_memory.parent.mkdir(parents=True)
|
||||
custom_memory.write_text("custom memory\n", encoding="utf-8", newline="\n")
|
||||
|
||||
custom_prompt = project_root / "docs" / "prompts" / "custom.md"
|
||||
custom_prompt.parent.mkdir(parents=True)
|
||||
custom_prompt.write_text("custom prompt\n", encoding="utf-8", newline="\n")
|
||||
|
||||
(project_root / "CLAUDE.md").write_text(
|
||||
"# Existing Claude\n\nKeep this.\n",
|
||||
encoding="utf-8",
|
||||
newline="\n",
|
||||
)
|
||||
|
||||
|
||||
class PlaybookDeploymentTests(unittest.TestCase):
|
||||
def test_playbook_deployment_modes(self):
|
||||
for install_mode, playbook_root in MODE_ROOTS.items():
|
||||
with self.subTest(install_mode=install_mode):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
project_root = Path(tmp_dir) / "project"
|
||||
project_root.mkdir()
|
||||
|
||||
if install_mode == "subtree":
|
||||
source_root = project_root / playbook_root
|
||||
copy_subtree_source(source_root)
|
||||
script = source_root / "scripts" / "playbook.py"
|
||||
else:
|
||||
source_root = ROOT
|
||||
script = SCRIPT
|
||||
|
||||
seed_custom_files(project_root)
|
||||
config = write_config(project_root, install_mode, playbook_root)
|
||||
|
||||
for run_number in (1, 2):
|
||||
result = run_playbook(script, config, project_root)
|
||||
self.assertEqual(
|
||||
result.returncode,
|
||||
0,
|
||||
msg=(
|
||||
f"{install_mode} run {run_number} failed\n"
|
||||
f"{result.stdout}{result.stderr}"
|
||||
),
|
||||
)
|
||||
|
||||
expected_paths = (
|
||||
"AGENTS.md",
|
||||
"AGENT_RULES.md",
|
||||
"AGENT_RULES.local.md",
|
||||
"CLAUDE.md",
|
||||
".gitattributes",
|
||||
"memory-bank/project-brief.md",
|
||||
"memory-bank/active-context.md",
|
||||
"docs/prompts/system/agent-behavior.md",
|
||||
".agents/index.md",
|
||||
".agents/tsl/index.md",
|
||||
".agents/markdown/index.md",
|
||||
".test-agents/skills/style-cleanup/SKILL.md",
|
||||
)
|
||||
missing = [
|
||||
path
|
||||
for path in expected_paths
|
||||
if not (project_root / path).exists()
|
||||
]
|
||||
self.assertEqual(missing, [])
|
||||
|
||||
self.assertEqual(
|
||||
(project_root / "memory-bank/custom.md").read_text(
|
||||
encoding="utf-8"
|
||||
),
|
||||
"custom memory\n",
|
||||
)
|
||||
self.assertEqual(
|
||||
(project_root / "docs/prompts/custom.md").read_text(
|
||||
encoding="utf-8"
|
||||
),
|
||||
"custom prompt\n",
|
||||
)
|
||||
|
||||
claude_text = (project_root / "CLAUDE.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertIn("Keep this.", claude_text)
|
||||
self.assertEqual(
|
||||
claude_text.count("<!-- playbook:claude:start -->"), 1
|
||||
)
|
||||
|
||||
docs_prefix = f"{playbook_root.as_posix()}/docs"
|
||||
agents_index = (project_root / ".agents/index.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertIn(f"- {docs_prefix}", agents_index)
|
||||
|
||||
installed_skill = (
|
||||
project_root
|
||||
/ ".test-agents/skills/style-cleanup/SKILL.md"
|
||||
).read_text(encoding="utf-8")
|
||||
self.assertIn(
|
||||
f"`{docs_prefix}/tsl/code_style.md`", installed_skill
|
||||
)
|
||||
self.assertNotIn("`docs/tsl/code_style.md`", installed_skill)
|
||||
|
||||
rules_text = (project_root / "AGENT_RULES.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertIn(
|
||||
f"`{playbook_root.as_posix()}/` 是 Playbook 模板/供应商目录",
|
||||
rules_text,
|
||||
)
|
||||
|
||||
if install_mode == "snapshot":
|
||||
snapshot_root = project_root / playbook_root
|
||||
self.assertTrue((snapshot_root / "SOURCE.md").is_file())
|
||||
self.assertTrue(
|
||||
(snapshot_root / "scripts/playbook.py").is_file()
|
||||
)
|
||||
self.assertTrue((snapshot_root / "skills").is_dir())
|
||||
else:
|
||||
self.assertFalse((source_root / "SOURCE.md").exists())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user