feat(kvb-git): follow the pkgmgr merge flow of each worktree
pkgmgr worktree flow (pkgmgr 7fb2296, live after its release) records per worktree the refs merged in before a gate (pull) and the branches the finished branch merges into (push). The skills now act on it: - hotfix.py sync merges, after origin/<default> and the register's base chain, every entry of the flow's pull list that is not merged already; an invalid flow file stops sync with exit 2 before any merge. pkgmgr starts only when <git-dir>/pkgmgr/flow.yml exists, so a sync without a flow, and the tests, never run the system pkgmgr wrapper. - kvb-org-split merges a finished sidetree into each push target of the flow in order, its upstream when none is set. - kvb-git-commit-next names the push targets the branch flows into when it closes. Word budgets kept (kvb-git-hotfix and kvb-org-split trimmed back under 600), skill text 2807 -> 2809 tokens. Tests: 38 hotfix tests OK, 3 new (pull list merged after the chain, invalid flow refused before any merge, no pkgmgr start without a flow file). 🎯 Fix: 93 % 💥 Break: 3 % 💸 Cost: 100 % ⏱️ Time: 99 % 🛡️ Security: 100 % 🏆 Score: 91 🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 % Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 1e1fd0e79821ad9a8d4fea99b38ac59ecb02d7b2)
This commit is contained in:
1 parent
7199e6bfba
commit
7618492d66
5 files changed
+110
-27
No files matched your search
@@ -503,6 +503,40 @@ class TestHotfix(unittest.TestCase):
|
||||
result = self.sync(self.feature, "work/feature")
|
||||
self.assertEqual((result.returncode, result.stdout), (0, f"merged\torigin/main\t{self.fix}\n"), result.stderr)
|
||||
|
||||
def fake_flow(self, flow: dict) -> None:
|
||||
fake = self.base / "bin" / "pkgmgr"
|
||||
fake.parent.mkdir(exist_ok=True)
|
||||
fake.write_text(f"#!/bin/sh\nprintf '%s' '{json.dumps(flow)}'\n", encoding="utf-8")
|
||||
fake.chmod(0o755)
|
||||
self.env["PATH"] = f"{fake.parent}:/usr/bin:/bin"
|
||||
(self.work / ".git" / "pkgmgr").mkdir()
|
||||
(self.work / ".git" / "pkgmgr" / "flow.yml").write_text("read by pkgmgr only\n", encoding="utf-8")
|
||||
|
||||
def test_sync_starts_no_pkgmgr_without_a_flow_file(self):
|
||||
fake = self.base / "bin" / "pkgmgr"
|
||||
fake.parent.mkdir()
|
||||
fake.write_text(f"#!/bin/sh\ntouch {self.base / 'pkgmgr-ran'}\nexit 2\n", encoding="utf-8")
|
||||
fake.chmod(0o755)
|
||||
self.env["PATH"] = f"{fake.parent}:/usr/bin:/bin"
|
||||
self.assertEqual(self.merges(self.sync(self.work, "work/side")), [["merged", "origin/main"], ["merged", "line"]])
|
||||
self.assertFalse((self.base / "pkgmgr-ran").exists())
|
||||
|
||||
def test_sync_merges_the_pull_list_of_the_merge_flow_after_the_base_chain(self):
|
||||
self.commit(self.feature, "feat.txt", "feat\n", "feature work")
|
||||
self.fake_flow({"source": "file", "pull": ["origin/main", "feature"], "push": ["line"], "warnings": []})
|
||||
result = self.sync(self.work, "work/side")
|
||||
self.assertEqual(self.merges(result), [["merged", "origin/main"], ["merged", "line"], ["merged", "feature"]])
|
||||
self.assertTrue((self.work / "feat.txt").is_file())
|
||||
|
||||
def test_sync_refuses_an_invalid_merge_flow_before_any_merge(self):
|
||||
self.fake_flow({"source": "invalid", "pull": [], "push": [], "warnings": ["pkgmgr/flow.yml ignored: not a mapping"]})
|
||||
before = self.head(self.work)
|
||||
result = self.sync(self.work, "work/side")
|
||||
self.assertEqual((result.returncode, result.stdout), (2, ""))
|
||||
self.assertIn("is invalid", result.stderr)
|
||||
self.assertIn("not a mapping", result.stderr)
|
||||
self.assertEqual(self.head(self.work), before)
|
||||
|
||||
def test_the_base_chain_follows_only_open_rows_of_this_repository(self):
|
||||
self.git(self.other, "branch", "line")
|
||||
gone = self.base / "gone"
|
||||
|
||||
Reference in new issue
Block a user