diff --git a/scripts/publish_zhenxun.py b/scripts/publish_zhenxun.py index 0a51b2a..c00e614 100644 --- a/scripts/publish_zhenxun.py +++ b/scripts/publish_zhenxun.py @@ -59,12 +59,13 @@ def publish(package, confirmed=False, request=None): parent = ref["object"]["sha"] if ref else None if parent: owned = call("GET", f"contents/FARM-MANIFEST.json?ref={BRANCH}", None) - if not owned or owned.get("encoding") != "base64": - raise ValueError("Existing preview branch is not generated by Farm") - previous = json.loads(base64.b64decode(owned["content"])) - if (previous.get("target") != "zhenxun" - or previous.get("plugin") != manifest["plugin"]): - raise ValueError("Existing preview branch ownership differs") + if owned is not None: + if owned.get("encoding") != "base64": + raise ValueError("Existing Farm manifest encoding is invalid") + previous = json.loads(base64.b64decode(owned["content"])) + if (previous.get("target") != "zhenxun" + or previous.get("plugin") != manifest["plugin"]): + raise ValueError("Existing preview branch ownership differs") tree = [] for name, content in sorted(files.items()): blob = call("POST", "git/blobs", { diff --git a/tests/test_zhenxun_package.py b/tests/test_zhenxun_package.py index ce4060a..774c67f 100644 --- a/tests/test_zhenxun_package.py +++ b/tests/test_zhenxun_package.py @@ -230,20 +230,38 @@ class ZhenxunPackageTests(unittest.TestCase): with self.assertRaisesRegex(ValueError, "not accessible"): publish(package, True, lambda *args: None) - def test_symlink_duplicate_and_unmanaged_branch_rejected(self): + def test_publish_replaces_unmanaged_main_and_preserves_history(self): from publish_zhenxun import publish - from zipfile import ZipInfo + from verify_zhenxun import read_package package, _ = self.clean_package() - with patch.dict("os.environ", {"FARM_RELEASE_TOKEN":"unit-test"}): - def unmanaged(method, path, data): - if path == "": - return {"default_branch": "main"} - if path.startswith("git/ref/"): - return {"object": {"sha": "existing"}} - return None + calls = [] - with self.assertRaisesRegex(ValueError, "not generated by Farm"): - publish(package, True, unmanaged) + def unmanaged(method, path, data): + calls.append((method, path, data)) + if path == "": + return {"default_branch": "main"} + if path.startswith("git/ref/"): + return {"object": {"sha": "existing"}} + if path.startswith("contents/"): + return None + return {"sha": "created"} + + with patch.dict("os.environ", {"FARM_RELEASE_TOKEN": "unit-test"}): + self.assertTrue(publish(package, True, unmanaged)["published"]) + tree = next(data for method, path, data in calls + if method == "POST" and path == "git/trees") + self.assertNotIn("base_tree", tree) + self.assertEqual({entry["path"] for entry in tree["tree"]}, + set(read_package(package))) + commit = next(data for method, path, data in calls + if method == "POST" and path == "git/commits") + self.assertEqual(commit["parents"], ["existing"]) + self.assertIn(("PATCH", "git/refs/heads/main", { + "sha": "created", "force": False, + }), calls) + + def test_symlink_and_duplicate_rejected(self): + from zipfile import ZipInfo for kind in ("duplicate", "link"): bad = self.root / (kind + ".zip") bad.write_bytes(self.bundle.read_bytes())