Files
playbook/test/test_tsl_playbook_sync.py
csh 0dcd968188 🐛 fix(tsl-playbook): sync node formatting configs
Publish package metadata and Prettier settings through the scoped tsl-playbook bundle sync.

Force-add only managed paths so the target branch ignore rules cannot drop the lockfile.
2026-07-30 13:47:49 +08:00

120 lines
3.9 KiB
Python

import re
import subprocess
import tempfile
import unittest
from pathlib import Path
from scripts.build_tsl_playbook import build
ROOT_CONFIG_CONTENTS = {
"package.json": b'{"name":"fixture"}\n',
"package-lock.json": b'{"lockfileVersion":3}\n',
".prettierrc.json": b'{"proseWrap":"preserve"}\n',
".prettierignore": b"skills/thirdparty/**\n",
}
ROOT = Path(__file__).resolve().parents[1]
SYNC_WORKFLOW = ROOT / ".gitea" / "workflows" / "sync-tsl-playbook.yml"
EXPECTED_MANAGED_PATHS = (
"AGENTS.md",
"package.json",
"package-lock.json",
".prettierrc.json",
".prettierignore",
"docs/tsl",
"skills/tsl-syntax-reference",
"skills/tsl-api-reference",
"tools/tsl-codegen",
)
class TslPlaybookSyncTests(unittest.TestCase):
def test_build_copies_root_config_files_verbatim(self):
with tempfile.TemporaryDirectory() as temp_dir:
repo_root = Path(temp_dir) / "repo"
output = Path(temp_dir) / "bundle"
write_minimal_sources(repo_root)
build(output, repo_root)
for filename, expected in ROOT_CONFIG_CONTENTS.items():
with self.subTest(filename=filename):
self.assertEqual(expected, (output / filename).read_bytes())
def test_non_file_root_config_fails_before_output_cleanup(self):
with tempfile.TemporaryDirectory() as temp_dir:
repo_root = Path(temp_dir) / "repo"
output = Path(temp_dir) / "bundle"
write_minimal_sources(repo_root)
invalid_config = repo_root / "package.json"
invalid_config.unlink()
invalid_config.mkdir()
output.mkdir()
sentinel = output / "keep.txt"
sentinel.write_text("keep\n", encoding="utf-8", newline="\n")
with self.assertRaisesRegex(
FileNotFoundError,
re.escape(str(invalid_config)),
):
build(output, repo_root)
self.assertEqual("keep\n", sentinel.read_text(encoding="utf-8"))
def test_root_config_files_are_not_ignored(self):
for filename in ROOT_CONFIG_CONTENTS:
with self.subTest(filename=filename):
self.assertTrue((ROOT / filename).is_file())
result = subprocess.run(
["git", "check-ignore", "--quiet", "--", filename],
cwd=ROOT,
check=False,
)
self.assertEqual(1, result.returncode, f"ignored: {filename}")
def test_workflow_owns_exact_bundle_paths(self):
text = SYNC_WORKFLOW.read_text(encoding="utf-8")
match = re.search(
r"^ {10}managed_paths=\(\n"
r'(?P<body>(?:^ {12}"[^"]+"\n)+)'
r"^ {10}\)$",
text,
flags=re.MULTILINE,
)
self.assertIsNotNone(match)
managed_paths = tuple(
line.strip().strip('"') for line in match.group("body").splitlines()
)
self.assertEqual(EXPECTED_MANAGED_PATHS, managed_paths)
self.assertIn('rm -rf -- "${managed_paths[@]}"', text)
self.assertIn('cp -R -- "$bundle/$path" "$path"', text)
self.assertIn('git add -f -A -- "${managed_paths[@]}"', text)
self.assertNotIn('cp -R "$bundle"/. "$REPO_DIR"/', text)
def write_minimal_sources(repo_root: Path) -> None:
for relative in (
"docs/tsl",
"skills/tsl-syntax-reference",
"skills/tsl-api-reference",
"tools/tsl-codegen",
):
(repo_root / relative).mkdir(parents=True)
ruleset = repo_root / "rulesets" / "tsl" / "index.md"
ruleset.parent.mkdir(parents=True)
ruleset.write_text(
"# TSL 智能体规则\n",
encoding="utf-8",
newline="\n",
)
for filename, content in ROOT_CONFIG_CONTENTS.items():
(repo_root / filename).write_bytes(content)
if __name__ == "__main__":
unittest.main()