🐛 fix(ci): validate thirdparty skills without local sync
This commit is contained in:
@@ -16,14 +16,6 @@ LEGACY_WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-superpowers
|
||||
UPDATE_SCRIPT = ROOT / ".gitea" / "ci" / "update_thirdparty_skills.sh"
|
||||
SYNC_SCRIPT = ROOT / ".gitea" / "ci" / "sync_thirdparty_skills.sh"
|
||||
SKILLS_MD = ROOT / "SKILLS.md"
|
||||
MATT_POCOCK_LIST = (
|
||||
ROOT / "skills" / "thirdparty" / ".sources" / "matt-pocock-skills.list"
|
||||
)
|
||||
UI_UX_PRO_MAX_LIST = ROOT / "skills" / "thirdparty" / ".sources" / "ui-ux-pro-max.list"
|
||||
UI_UX_PRO_MAX_DIR = ROOT / "skills" / "thirdparty" / "ui-ux-pro-max"
|
||||
BROOKS_LINT_LIST = ROOT / "skills" / "thirdparty" / ".sources" / "brooks-lint.list"
|
||||
CODEBASE_RECON_LIST = ROOT / "skills" / "thirdparty" / ".sources" / "codebase-recon.list"
|
||||
PATHFINDING_DIR = ROOT / "skills" / "thirdparty" / "pathfinding"
|
||||
|
||||
|
||||
def load_manifest() -> dict:
|
||||
@@ -59,6 +51,7 @@ def extract_workflow_region(name: str) -> str:
|
||||
|
||||
|
||||
class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
|
||||
def test_manifest_declares_all_thirdparty_sources(self):
|
||||
data = load_manifest()
|
||||
self.assertEqual(
|
||||
@@ -66,11 +59,10 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
[
|
||||
"matt-pocock-skills",
|
||||
"ui-ux-pro-max",
|
||||
"andrej-karpathy-skills",
|
||||
"brooks-lint",
|
||||
"codebase-recon",
|
||||
"codebase-migrate",
|
||||
"uncle-bob-craft",
|
||||
"cangjie-skill",
|
||||
"darwin-skill",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -93,10 +85,7 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
self.assertIn("grilling", matt["include_skill_dirs"])
|
||||
self.assertIn("to-tickets", matt["include_skill_dirs"])
|
||||
|
||||
def test_matt_pocock_source_and_required_workflow_skills_are_materialized(self):
|
||||
self.assertTrue(MATT_POCOCK_LIST.is_file())
|
||||
|
||||
synced = set(MATT_POCOCK_LIST.read_text(encoding="utf-8").splitlines())
|
||||
def test_matt_pocock_manifest_includes_required_workflow_skills(self):
|
||||
manifest_skills = set(
|
||||
next(
|
||||
item
|
||||
@@ -111,36 +100,43 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
"domain-modeling",
|
||||
"to-spec",
|
||||
"to-tickets",
|
||||
"implement",
|
||||
"tdd",
|
||||
"codebase-design",
|
||||
"code-review",
|
||||
"handoff",
|
||||
}
|
||||
|
||||
self.assertEqual(synced, manifest_skills)
|
||||
self.assertTrue(required <= synced)
|
||||
self.assertTrue(required <= manifest_skills)
|
||||
legacy_main_chain = {
|
||||
"using-superpowers",
|
||||
"brainstorming",
|
||||
"writing-plans",
|
||||
"executing-plans",
|
||||
}
|
||||
self.assertTrue(legacy_main_chain.isdisjoint(synced))
|
||||
for name in required:
|
||||
self.assertTrue((ROOT / "skills" / "thirdparty" / name / "SKILL.md").is_file())
|
||||
self.assertTrue(legacy_main_chain.isdisjoint(manifest_skills))
|
||||
|
||||
def test_karpathy_manifest_uses_copy_skill_dirs_sync_mode(self):
|
||||
def test_copy_skill_root_sources_declare_curated_paths(self):
|
||||
data = load_manifest()
|
||||
karpathy = next(
|
||||
item for item in data["sources"] if item["id"] == "andrej-karpathy-skills"
|
||||
)
|
||||
self.assertEqual(karpathy["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(karpathy["snapshot_dir"], "andrej-karpathy-skills")
|
||||
self.assertEqual(karpathy["skills_subdir"], "skills")
|
||||
self.assertEqual(
|
||||
karpathy["source_list"], "skills/thirdparty/.sources/andrej-karpathy-skills.list"
|
||||
)
|
||||
sources = {item["id"]: item for item in data["sources"]}
|
||||
|
||||
expected = {
|
||||
"cangjie-skill": {
|
||||
"snapshot_dir": "cangjie-skill",
|
||||
"output_name": "cangjie-skill",
|
||||
"required_paths": {"SKILL.md", "methodology", "extractors", "templates"},
|
||||
},
|
||||
"darwin-skill": {
|
||||
"snapshot_dir": "darwin-skill",
|
||||
"output_name": "darwin-skill",
|
||||
"required_paths": {"SKILL.md", "references", "scripts", "templates"},
|
||||
},
|
||||
}
|
||||
for source_id, contract in expected.items():
|
||||
source = sources[source_id]
|
||||
self.assertEqual(source["sync_mode"], "copy_skill_root")
|
||||
self.assertEqual(source["snapshot_dir"], contract["snapshot_dir"])
|
||||
self.assertEqual(source["output_name"], contract["output_name"])
|
||||
self.assertTrue(contract["required_paths"] <= set(source["include_paths"]))
|
||||
|
||||
def test_ui_ux_pro_max_uses_render_skill_sync_mode(self):
|
||||
data = load_manifest()
|
||||
@@ -168,39 +164,11 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
recon["source_list"], "skills/thirdparty/.sources/codebase-recon.list"
|
||||
)
|
||||
self.assertEqual(recon["include_skill_dirs"], ["codebase-recon", "pathfinding"])
|
||||
|
||||
migrate = next(
|
||||
item for item in data["sources"] if item["id"] == "codebase-migrate"
|
||||
)
|
||||
self.assertEqual(recon["include_skill_dirs"], ["codebase-recon"])
|
||||
self.assertEqual(
|
||||
migrate["upstream_repo"],
|
||||
"https://github.com/ComposioHQ/awesome-codex-skills.git",
|
||||
recon["overlay_patch"],
|
||||
".gitea/ci/thirdparty-skill-overlays/codebase-recon.patch",
|
||||
)
|
||||
self.assertEqual(migrate["upstream_ref"], "master")
|
||||
self.assertEqual(migrate["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(migrate["snapshot_dir"], "awesome-codex-skills")
|
||||
self.assertEqual(migrate["skills_subdir"], ".")
|
||||
self.assertEqual(
|
||||
migrate["source_list"], "skills/thirdparty/.sources/codebase-migrate.list"
|
||||
)
|
||||
self.assertEqual(migrate["include_skill_dirs"], ["codebase-migrate"])
|
||||
|
||||
craft = next(
|
||||
item for item in data["sources"] if item["id"] == "uncle-bob-craft"
|
||||
)
|
||||
self.assertEqual(
|
||||
craft["upstream_repo"],
|
||||
"https://github.com/sickn33/antigravity-awesome-skills.git",
|
||||
)
|
||||
self.assertEqual(craft["upstream_ref"], "main")
|
||||
self.assertEqual(craft["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(craft["snapshot_dir"], "antigravity-awesome-skills")
|
||||
self.assertEqual(craft["skills_subdir"], "skills")
|
||||
self.assertEqual(
|
||||
craft["source_list"], "skills/thirdparty/.sources/uncle-bob-craft.list"
|
||||
)
|
||||
self.assertEqual(craft["include_skill_dirs"], ["uncle-bob-craft"])
|
||||
|
||||
def test_workflow_inlines_update_and_sync_in_single_serial_job(self):
|
||||
text = WORKFLOW.read_text(encoding="utf-8")
|
||||
@@ -254,11 +222,12 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
self.assertIn("skills/thirdparty/", text)
|
||||
self.assertNotIn("Third-party Skills (superpowers)", text)
|
||||
|
||||
def test_non_legacy_thirdparty_source_lists_exist(self):
|
||||
self.assertTrue(UI_UX_PRO_MAX_LIST.is_file())
|
||||
self.assertTrue(CODEBASE_RECON_LIST.is_file())
|
||||
self.assertIn("ui-ux-pro-max", UI_UX_PRO_MAX_LIST.read_text(encoding="utf-8"))
|
||||
self.assertIn("pathfinding", CODEBASE_RECON_LIST.read_text(encoding="utf-8"))
|
||||
def test_manifest_declares_unique_thirdparty_source_lists(self):
|
||||
source_lists = [entry["source_list"] for entry in load_manifest()["sources"]]
|
||||
self.assertEqual(len(source_lists), len(set(source_lists)))
|
||||
self.assertTrue(
|
||||
all(path.startswith("skills/thirdparty/.sources/") for path in source_lists)
|
||||
)
|
||||
|
||||
def test_superpowers_source_and_vendored_skills_are_absent(self):
|
||||
data = load_manifest()
|
||||
@@ -289,17 +258,6 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
set(),
|
||||
)
|
||||
|
||||
def test_codebase_recon_pathfinding_dependency_is_synced(self):
|
||||
self.assertTrue((PATHFINDING_DIR / "SKILL.md").is_file())
|
||||
self.assertTrue(
|
||||
(PATHFINDING_DIR / "references" / "confidence.md").is_file()
|
||||
)
|
||||
|
||||
def test_ui_ux_pro_max_output_exists_with_data_and_scripts(self):
|
||||
self.assertTrue((UI_UX_PRO_MAX_DIR / "SKILL.md").is_file())
|
||||
self.assertTrue((UI_UX_PRO_MAX_DIR / "data").is_dir())
|
||||
self.assertTrue((UI_UX_PRO_MAX_DIR / "scripts").is_dir())
|
||||
|
||||
def test_inline_update_materializes_manifest_before_target_checkout(self):
|
||||
text = WORKFLOW.read_text(encoding="utf-8")
|
||||
self.assertIn('manifest_copy="$tmp_dir/thirdparty_skills.json"', text)
|
||||
@@ -325,7 +283,7 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
self.assertNotIn("exclude_skill_dirs", text)
|
||||
self.assertNotIn("is_excluded_skill_dir", text)
|
||||
|
||||
def test_inline_sync_generates_karpathy_outputs_in_temp_repo(self):
|
||||
def test_inline_sync_applies_codebase_recon_overlay_in_temp_repo(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
tmp_root = Path(tmp_dir)
|
||||
mirror = tmp_root / "origin.git"
|
||||
@@ -394,12 +352,40 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
manifest_data["sources"] = [
|
||||
entry
|
||||
for entry in manifest_data["sources"]
|
||||
if entry["id"] == "andrej-karpathy-skills"
|
||||
if entry["id"] == "codebase-recon"
|
||||
]
|
||||
(work / ".gitea" / "ci" / "thirdparty_skills.json").write_text(
|
||||
json.dumps(manifest_data, indent=2) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
overlay_path = Path(manifest_data["sources"][0]["overlay_patch"])
|
||||
shutil.copy2(ROOT / overlay_path, work / overlay_path)
|
||||
fixture_commit = run_command(
|
||||
"git",
|
||||
"-C",
|
||||
str(work),
|
||||
"add",
|
||||
".gitea/ci/thirdparty_skills.json",
|
||||
overlay_path.as_posix(),
|
||||
)
|
||||
self.assertEqual(fixture_commit.returncode, 0, msg=fixture_commit.stderr)
|
||||
fixture_commit = run_command(
|
||||
"git",
|
||||
"-C",
|
||||
str(work),
|
||||
"-c",
|
||||
"user.name=test",
|
||||
"-c",
|
||||
"user.email=test@example.invalid",
|
||||
"commit",
|
||||
"-m",
|
||||
"test: configure thirdparty sync fixture",
|
||||
)
|
||||
self.assertEqual(fixture_commit.returncode, 0, msg=fixture_commit.stderr)
|
||||
fixture_push = run_command(
|
||||
"git", "-C", str(work), "push", "origin", "HEAD:main"
|
||||
)
|
||||
self.assertEqual(fixture_push.returncode, 0, msg=fixture_push.stderr)
|
||||
sync_script = extract_workflow_region("sync_thirdparty_skills")
|
||||
script_path = work / ".sync-thirdparty-test.sh"
|
||||
script_path.write_text(
|
||||
@@ -431,15 +417,28 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
)
|
||||
|
||||
generated_list = (
|
||||
work / "skills" / "thirdparty" / ".sources" / "andrej-karpathy-skills.list"
|
||||
work / "skills" / "thirdparty" / ".sources" / "codebase-recon.list"
|
||||
)
|
||||
generated_skill = (
|
||||
work / "skills" / "thirdparty" / "karpathy-guidelines" / "SKILL.md"
|
||||
work / "skills" / "thirdparty" / "codebase-recon" / "SKILL.md"
|
||||
)
|
||||
generated_reference = (
|
||||
work
|
||||
/ "skills"
|
||||
/ "thirdparty"
|
||||
/ "codebase-recon"
|
||||
/ "references"
|
||||
/ "confidence-calibration.md"
|
||||
)
|
||||
self.assertTrue(generated_list.is_file())
|
||||
self.assertTrue(generated_skill.is_file())
|
||||
self.assertTrue(generated_reference.is_file())
|
||||
self.assertIn(
|
||||
"karpathy-guidelines", generated_list.read_text(encoding="utf-8")
|
||||
"codebase-recon", generated_list.read_text(encoding="utf-8")
|
||||
)
|
||||
self.assertIn(
|
||||
"[confidence-calibration.md](references/confidence-calibration.md)",
|
||||
generated_skill.read_text(encoding="utf-8"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user