aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/changelog.py23
-rw-r--r--scripts/test_changelog.py37
2 files changed, 59 insertions, 1 deletions
diff --git a/scripts/changelog.py b/scripts/changelog.py
index 8db0bf97..e930fd82 100644
--- a/scripts/changelog.py
+++ b/scripts/changelog.py
@@ -17,6 +17,7 @@ SECTION_RE = re.compile(r"^##\s+(?:\[(?P<bracketed>[^\]]+)\]|(?P<plain>.+?))\s*$
VERSION_WITH_DATE_RE = re.compile(r"^(?P<version>.+?)\s+-\s+\d{4}-\d{2}-\d{2}$")
DEFAULT_RELEASE_REPO = "ogulcancelik/herdr"
DEFAULT_LATEST_JSON_PATH = Path("website/latest.json")
+PROTOCOL_SOURCE_PATH = Path("src/server/protocol.rs")
ASSET_TARGETS = (
"linux-x86_64",
"linux-aarch64",
@@ -124,12 +125,25 @@ def prepare_release(text: str, version: str, release_date: str) -> str:
return rebuilt + "\n"
-def build_latest_json(version: str, notes: str, assets: dict[str, str]) -> str:
+def read_protocol_version(source_path: Path = PROTOCOL_SOURCE_PATH) -> int:
+ content = source_path.read_text(encoding="utf-8")
+ match = re.search(r"pub const PROTOCOL_VERSION: u32 = (\d+);", content)
+ if not match:
+ raise ChangelogError(f"could not read PROTOCOL_VERSION from {source_path}")
+ return int(match.group(1))
+
+
+def build_latest_json(
+ version: str, notes: str, assets: dict[str, str], protocol: int | None = None
+) -> str:
normalized_version = normalize_version(version)
normalized_notes = notes.strip()
if not normalized_notes:
raise ChangelogError("release notes are empty")
+ if protocol is None:
+ protocol = read_protocol_version()
+
missing_targets = [target for target in ASSET_TARGETS if target not in assets]
if missing_targets:
raise ChangelogError(f"missing asset targets: {', '.join(missing_targets)}")
@@ -139,6 +153,7 @@ def build_latest_json(version: str, notes: str, assets: dict[str, str]) -> str:
return json.dumps(
{
"version": normalized_version,
+ "protocol": protocol,
"notes": normalized_notes,
"assets": ordered_assets,
},
@@ -194,6 +209,7 @@ def manifest_from_release_payload(payload: dict[str, Any], version: str) -> dict
return {
"version": normalized_version,
+ "protocol": read_protocol_version(),
"notes": notes,
"assets": manifest_assets,
}
@@ -208,6 +224,10 @@ def canonicalize_manifest(manifest: dict[str, Any], label: str) -> dict[str, Any
if not isinstance(notes, str) or not notes.strip():
raise ChangelogError(f"{label} is missing non-empty release notes")
+ protocol = manifest.get("protocol")
+ if not isinstance(protocol, int):
+ raise ChangelogError(f"{label} is missing an integer protocol")
+
assets = manifest.get("assets")
if not isinstance(assets, dict):
raise ChangelogError(f"{label} is missing an assets object")
@@ -221,6 +241,7 @@ def canonicalize_manifest(manifest: dict[str, Any], label: str) -> dict[str, Any
return {
"version": normalize_version(version),
+ "protocol": protocol,
"notes": notes.strip(),
"assets": normalized_assets,
}
diff --git a/scripts/test_changelog.py b/scripts/test_changelog.py
index 10af5c47..5778b6ac 100644
--- a/scripts/test_changelog.py
+++ b/scripts/test_changelog.py
@@ -13,6 +13,7 @@ from scripts.changelog import (
extract_section_body,
manifest_from_release_payload,
prepare_release,
+ read_protocol_version,
)
@@ -50,6 +51,7 @@ class ChangelogScriptTests(unittest.TestCase):
)
)
+ self.assertEqual(manifest["protocol"], read_protocol_version())
self.assertEqual(manifest["notes"], "### Fixed\n- One")
def test_build_latest_json_embeds_notes_and_release_assets(self) -> None:
@@ -62,6 +64,7 @@ class ChangelogScriptTests(unittest.TestCase):
)
self.assertEqual(manifest["version"], "0.1.1")
+ self.assertEqual(manifest["protocol"], read_protocol_version())
self.assertEqual(manifest["notes"], "### Fixed\n- Smoothed Claude flapping.")
self.assertEqual(
manifest["assets"],
@@ -94,6 +97,7 @@ class ChangelogScriptTests(unittest.TestCase):
manifest,
{
"version": "0.1.1",
+ "protocol": read_protocol_version(),
"notes": "### Fixed\n- One",
"assets": {
"linux-x86_64": "https://example.com/linux-x86_64",
@@ -136,6 +140,7 @@ class ChangelogScriptTests(unittest.TestCase):
canonicalize_manifest(
{
"version": "0.1.1",
+ "protocol": read_protocol_version(),
"notes": "### Fixed\n- One",
"assets": {
"linux-x86_64": "https://example.com/linux-x86_64",
@@ -149,6 +154,7 @@ class ChangelogScriptTests(unittest.TestCase):
def test_ensure_manifest_matches_expected_normalizes_whitespace(self) -> None:
actual = {
"version": "v0.1.1",
+ "protocol": read_protocol_version(),
"notes": "\n### Fixed\n- One\n",
"assets": {
"linux-x86_64": " https://example.com/linux-x86_64 ",
@@ -159,6 +165,7 @@ class ChangelogScriptTests(unittest.TestCase):
}
expected = {
"version": "0.1.1",
+ "protocol": read_protocol_version(),
"notes": "### Fixed\n- One",
"assets": {
"linux-x86_64": "https://example.com/linux-x86_64",
@@ -176,6 +183,7 @@ class ChangelogScriptTests(unittest.TestCase):
ensure_manifest_matches_expected(
{
"version": "0.1.1",
+ "protocol": read_protocol_version(),
"notes": "### Fixed\n- Different",
"assets": {
"linux-x86_64": "https://example.com/linux-x86_64",
@@ -186,6 +194,7 @@ class ChangelogScriptTests(unittest.TestCase):
},
{
"version": "0.1.1",
+ "protocol": read_protocol_version(),
"notes": "### Fixed\n- One",
"assets": {
"linux-x86_64": "https://example.com/linux-x86_64",
@@ -197,6 +206,34 @@ class ChangelogScriptTests(unittest.TestCase):
"test manifest",
)
+ def test_canonicalize_manifest_requires_protocol(self) -> None:
+ with self.assertRaisesRegex(ChangelogError, "missing an integer protocol"):
+ canonicalize_manifest(
+ {
+ "version": "0.1.1",
+ "notes": "### Fixed\n- One",
+ "assets": default_release_assets("0.1.1"),
+ },
+ "test manifest",
+ )
+
+ def test_ensure_manifest_matches_expected_rejects_different_protocol(self) -> None:
+ actual = {
+ "version": "0.1.1",
+ "protocol": read_protocol_version() + 1,
+ "notes": "### Fixed\n- One",
+ "assets": default_release_assets("0.1.1"),
+ }
+ expected = {
+ "version": "0.1.1",
+ "protocol": read_protocol_version(),
+ "notes": "### Fixed\n- One",
+ "assets": default_release_assets("0.1.1"),
+ }
+
+ with self.assertRaisesRegex(ChangelogError, "does not match"):
+ ensure_manifest_matches_expected(actual, expected, "test manifest")
+
if __name__ == "__main__":
unittest.main()