fix: harden skill template contracts and scaffolding
All checks were successful
技能自动化发布 / release (push) Successful in 4s
All checks were successful
技能自动化发布 / release (push) Successful in 4s
Align scaffold slug replacement, Action manifest strict boundaries, metadata prune API, field permission validation, and task_logs readonly semantics with documented template contracts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,8 +10,10 @@ import unittest
|
||||
from _support import get_skill_root
|
||||
|
||||
TEMPLATE_MARKER = ".openclaw-skill-template"
|
||||
TEMPLATE_SLUG = "your-skill-slug"
|
||||
TEMPLATE_SLUG_KEBAB = "your-skill-slug"
|
||||
TEMPLATE_SLUG_UNDERSCORE = "your_skill_slug"
|
||||
SCAFFOLD_TEST_SLUG = "query-demo-records"
|
||||
SCAFFOLD_TEST_SLUG_UNDERSCORE = "query_demo_records"
|
||||
|
||||
|
||||
def _read_skill_slug() -> str:
|
||||
@@ -27,7 +29,7 @@ def _read_skill_slug() -> str:
|
||||
class TestScaffoldGuard(unittest.TestCase):
|
||||
def test_template_repo_has_marker(self) -> None:
|
||||
slug = _read_skill_slug()
|
||||
if slug != TEMPLATE_SLUG:
|
||||
if slug != TEMPLATE_SLUG_KEBAB:
|
||||
self.skipTest(f"当前 SKILL_SLUG={slug!r},非模板占位,跳过 template marker 断言")
|
||||
marker = os.path.join(get_skill_root(), TEMPLATE_MARKER)
|
||||
self.assertTrue(
|
||||
@@ -37,7 +39,7 @@ class TestScaffoldGuard(unittest.TestCase):
|
||||
|
||||
def test_business_skill_must_not_keep_template_marker(self) -> None:
|
||||
slug = _read_skill_slug()
|
||||
if slug == TEMPLATE_SLUG:
|
||||
if slug == TEMPLATE_SLUG_KEBAB:
|
||||
self.skipTest("当前仍为模板占位 slug,由 test_template_repo_has_marker 守护")
|
||||
marker = os.path.join(get_skill_root(), TEMPLATE_MARKER)
|
||||
self.assertFalse(
|
||||
@@ -64,7 +66,7 @@ class TestScaffoldGuard(unittest.TestCase):
|
||||
|
||||
def test_scaffold_replaces_slug_and_copies_actions_manifest(self) -> None:
|
||||
slug = _read_skill_slug()
|
||||
if slug != TEMPLATE_SLUG:
|
||||
if slug != TEMPLATE_SLUG_KEBAB:
|
||||
self.skipTest("仅在 skill-template 源仓库运行 scaffold 集成测试")
|
||||
|
||||
import subprocess
|
||||
@@ -94,7 +96,9 @@ class TestScaffoldGuard(unittest.TestCase):
|
||||
with open(actions_path, encoding="utf-8") as f:
|
||||
manifest = json.load(f)
|
||||
self.assertEqual(manifest.get("skill"), SCAFFOLD_TEST_SLUG)
|
||||
self.assertNotIn(TEMPLATE_SLUG, json.dumps(manifest))
|
||||
manifest_raw = json.dumps(manifest)
|
||||
self.assertNotIn(TEMPLATE_SLUG_KEBAB, manifest_raw)
|
||||
self.assertNotIn(TEMPLATE_SLUG_UNDERSCORE, manifest_raw)
|
||||
|
||||
actions_md = os.path.join(dest, "references", "ACTIONS.md")
|
||||
self.assertTrue(os.path.isfile(actions_md), msg="scaffold must copy references/ACTIONS.md")
|
||||
@@ -109,7 +113,32 @@ class TestScaffoldGuard(unittest.TestCase):
|
||||
constants_path = os.path.join(dest, "scripts", "util", "constants.py")
|
||||
with open(constants_path, encoding="utf-8") as f:
|
||||
constants_text = f.read()
|
||||
self.assertNotIn(TEMPLATE_SLUG, constants_text)
|
||||
self.assertNotIn(TEMPLATE_SLUG_KEBAB, constants_text)
|
||||
self.assertNotIn(TEMPLATE_SLUG_UNDERSCORE, constants_text)
|
||||
self.assertIn(f'SKILL_SLUG = "{SCAFFOLD_TEST_SLUG}"', constants_text)
|
||||
self.assertIn(
|
||||
f'LOG_LOGGER_NAME = "openclaw.skill.{SCAFFOLD_TEST_SLUG_UNDERSCORE}"',
|
||||
constants_text,
|
||||
)
|
||||
|
||||
skill_md_path = os.path.join(dest, "SKILL.md")
|
||||
with open(skill_md_path, encoding="utf-8") as f:
|
||||
skill_md = f.read()
|
||||
self.assertIn(f"slug: {SCAFFOLD_TEST_SLUG}", skill_md)
|
||||
self.assertNotIn(TEMPLATE_SLUG_KEBAB, skill_md)
|
||||
self.assertNotIn(TEMPLATE_SLUG_UNDERSCORE, skill_md)
|
||||
|
||||
def test_scaffold_ps1_matches_python_placeholder_rules(self) -> None:
|
||||
slug = _read_skill_slug()
|
||||
if slug != TEMPLATE_SLUG_KEBAB:
|
||||
self.skipTest("仅在 skill-template 源仓库运行 scaffold PS1 文案测试")
|
||||
|
||||
ps1_path = os.path.join(get_skill_root(), "tools", "scaffold_skill.ps1")
|
||||
with open(ps1_path, encoding="utf-8") as f:
|
||||
text = f.read()
|
||||
self.assertIn("your-skill-slug", text)
|
||||
self.assertIn("your_skill_slug", text)
|
||||
self.assertIn('.Replace("-", "_")', text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user