aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/changelog.py42
-rw-r--r--scripts/preview.py16
-rw-r--r--scripts/test_changelog.py4
-rw-r--r--scripts/test_preview.py8
4 files changed, 68 insertions, 2 deletions
diff --git a/scripts/changelog.py b/scripts/changelog.py
index 9fcae9cd..46c3688d 100644
--- a/scripts/changelog.py
+++ b/scripts/changelog.py
@@ -19,6 +19,7 @@ DEFAULT_RELEASE_REPO = "herdrdev/herdr"
DEFAULT_LATEST_JSON_PATH = Path("distribution/latest.json")
DEFAULT_PRODUCT_ANNOUNCEMENT_PATH = Path("docs/next/product-announcement.json")
PROTOCOL_SOURCE_PATH = Path("src/protocol/wire.rs")
+ENDPOINT_PROTOCOL_SOURCE_PATH = Path("src/protocol/endpoint.rs")
CORE_ASSET_TARGETS = (
"linux-x86_64",
"linux-aarch64",
@@ -138,6 +139,18 @@ def read_protocol_version(source_path: Path = PROTOCOL_SOURCE_PATH) -> int:
return int(match.group(1))
+def read_endpoint_protocol_generation(
+ source_path: Path = ENDPOINT_PROTOCOL_SOURCE_PATH,
+) -> int:
+ content = source_path.read_text(encoding="utf-8")
+ match = re.search(r"pub const ENDPOINT_PROTOCOL_GENERATION: u32 = (\d+);", content)
+ if not match:
+ raise ChangelogError(
+ f"could not read ENDPOINT_PROTOCOL_GENERATION from {source_path}"
+ )
+ return int(match.group(1))
+
+
def normalize_announcement(value: Any, label: str) -> dict[str, str] | None:
if value is None:
return None
@@ -225,7 +238,14 @@ def normalize_release_metadata(value: Any, label: str, version: str) -> dict[str
if not isinstance(value, dict):
raise ChangelogError(f"{label} must be an object")
- allowed_keys = {"notes", "announcement", "assets", "sha256", "protocol"}
+ allowed_keys = {
+ "notes",
+ "announcement",
+ "assets",
+ "sha256",
+ "protocol",
+ "endpoint_generation",
+ }
extra_keys = sorted(set(value) - allowed_keys)
if extra_keys:
raise ChangelogError(f"{label} has unsupported field(s): {', '.join(extra_keys)}")
@@ -244,6 +264,11 @@ def normalize_release_metadata(value: Any, label: str, version: str) -> dict[str
inferred_protocol = infer_protocol_from_notes(notes)
if inferred_protocol is not None:
metadata["protocol"] = inferred_protocol
+ endpoint_generation = value.get("endpoint_generation")
+ if endpoint_generation is not None:
+ if not isinstance(endpoint_generation, int):
+ raise ChangelogError(f"{label}.endpoint_generation must be an integer")
+ metadata["endpoint_generation"] = endpoint_generation
if "assets" in value:
metadata["assets"] = normalize_assets(
value.get("assets"),
@@ -305,9 +330,11 @@ def build_latest_json(
ordered_sha256 = normalize_sha256(sha256, "sha256")
normalized_announcement = normalize_announcement(announcement, "root")
archived_releases = normalize_releases(releases)
+ endpoint_generation = read_endpoint_protocol_generation()
current_metadata: dict[str, Any] = {
"notes": normalized_notes,
"protocol": protocol,
+ "endpoint_generation": endpoint_generation,
"assets": ordered_assets,
}
current_metadata["sha256"] = ordered_sha256
@@ -322,6 +349,7 @@ def build_latest_json(
manifest: dict[str, Any] = {
"version": normalized_version,
"protocol": protocol,
+ "endpoint_generation": endpoint_generation,
"notes": normalized_notes,
"assets": ordered_assets,
}
@@ -397,6 +425,7 @@ def manifest_from_release_payload(
return {
"version": normalized_version,
"protocol": protocol if protocol is not None else read_protocol_version(),
+ "endpoint_generation": read_endpoint_protocol_generation(),
"notes": notes,
"assets": manifest_assets,
"sha256": manifest_sha256,
@@ -415,6 +444,9 @@ def canonicalize_manifest(manifest: dict[str, Any], label: str) -> dict[str, Any
protocol = manifest.get("protocol")
if not isinstance(protocol, int):
raise ChangelogError(f"{label} is missing an integer protocol")
+ endpoint_generation = manifest.get("endpoint_generation")
+ if endpoint_generation is not None and not isinstance(endpoint_generation, int):
+ raise ChangelogError(f"{label} endpoint_generation must be an integer")
assets = manifest.get("assets")
if not isinstance(assets, dict):
@@ -423,13 +455,16 @@ def canonicalize_manifest(manifest: dict[str, Any], label: str) -> dict[str, Any
normalized_assets = normalize_assets(assets, f"{label} assets")
normalized_sha256 = normalize_sha256(manifest.get("sha256"), f"{label} sha256")
- return {
+ canonical = {
"version": normalize_version(version),
"protocol": protocol,
"notes": notes.strip(),
"assets": normalized_assets,
"sha256": normalized_sha256,
}
+ if endpoint_generation is not None:
+ canonical["endpoint_generation"] = endpoint_generation
+ return canonical
def ensure_manifest_matches_expected(
@@ -495,6 +530,9 @@ def archived_releases_from_current_manifest(manifest: dict[str, Any]) -> dict[st
protocol = manifest.get("protocol")
if isinstance(protocol, int):
metadata["protocol"] = protocol
+ endpoint_generation = manifest.get("endpoint_generation")
+ if isinstance(endpoint_generation, int):
+ metadata["endpoint_generation"] = endpoint_generation
assets = manifest.get("assets")
if isinstance(assets, dict):
metadata["assets"] = normalize_assets(
diff --git a/scripts/preview.py b/scripts/preview.py
index 16c52b6e..935ee9b7 100644
--- a/scripts/preview.py
+++ b/scripts/preview.py
@@ -38,6 +38,7 @@ TYPE_HEADINGS = {
}
TYPE_ORDER = ("Added", "Fixed", "Performance", "Maintenance", "Other")
COMMIT_RE = re.compile(r"^(?P<kind>[a-z]+)(?:\([^)]+\))?!?:\s+(?P<body>.+)$")
+ENDPOINT_PROTOCOL_SOURCE_PATH = Path("src/protocol/endpoint.rs")
def run_git(args: list[str]) -> str:
@@ -48,6 +49,18 @@ def normalize_version(version: str) -> str:
return version.strip().removeprefix("v")
+def read_endpoint_protocol_generation(
+ source_path: Path = ENDPOINT_PROTOCOL_SOURCE_PATH,
+) -> int:
+ content = source_path.read_text(encoding="utf-8")
+ match = re.search(r"pub const ENDPOINT_PROTOCOL_GENERATION: u32 = (\d+);", content)
+ if not match:
+ raise ValueError(
+ f"could not read ENDPOINT_PROTOCOL_GENERATION from {source_path}"
+ )
+ return int(match.group(1))
+
+
def latest_stable_tag(ref: str | None = None) -> str:
args = ["describe", "--tags", "--match", "v[0-9]*", "--abbrev=0"]
if ref:
@@ -215,11 +228,13 @@ def build_manifest(
current = read_json(output) or {}
builds = current.get("builds") if isinstance(current.get("builds"), dict) else {}
builds = dict(builds)
+ endpoint_generation = read_endpoint_protocol_generation()
builds[build_id] = {
"base_version": normalize_version(base_version),
"commit": commit,
"built_at": built_at,
"protocol": protocol,
+ "endpoint_generation": endpoint_generation,
"tag": tag,
"assets": assets,
}
@@ -239,6 +254,7 @@ def build_manifest(
"commit": commit,
"built_at": built_at,
"protocol": protocol,
+ "endpoint_generation": endpoint_generation,
"notes": notes.strip(),
"assets": assets,
"builds": ordered_builds,
diff --git a/scripts/test_changelog.py b/scripts/test_changelog.py
index 6a9d12dd..f08088a3 100644
--- a/scripts/test_changelog.py
+++ b/scripts/test_changelog.py
@@ -20,6 +20,7 @@ from scripts.changelog import (
load_product_announcement,
manifest_from_release_payload,
prepare_release,
+ read_endpoint_protocol_generation,
read_protocol_version,
)
@@ -346,6 +347,7 @@ class ChangelogScriptTests(unittest.TestCase):
{
"version": "0.1.1",
"protocol": read_protocol_version(),
+ "endpoint_generation": read_endpoint_protocol_generation(),
"notes": "### Fixed\n- One",
"assets": {
"linux-x86_64": "https://example.com/linux-x86_64",
@@ -436,6 +438,7 @@ class ChangelogScriptTests(unittest.TestCase):
actual = {
"version": "v0.1.1",
"protocol": read_protocol_version(),
+ "endpoint_generation": read_endpoint_protocol_generation(),
"notes": "\n### Fixed\n- One\n",
"assets": {
"linux-x86_64": " https://example.com/linux-x86_64 ",
@@ -449,6 +452,7 @@ class ChangelogScriptTests(unittest.TestCase):
expected = {
"version": "0.1.1",
"protocol": read_protocol_version(),
+ "endpoint_generation": read_endpoint_protocol_generation(),
"notes": "### Fixed\n- One",
"assets": {
"linux-x86_64": "https://example.com/linux-x86_64",
diff --git a/scripts/test_preview.py b/scripts/test_preview.py
index 0f586437..d3613d83 100644
--- a/scripts/test_preview.py
+++ b/scripts/test_preview.py
@@ -49,6 +49,10 @@ class PreviewNotesTests(unittest.TestCase):
self.assertEqual(data["channel"], "preview")
self.assertEqual(data["build_id"], "2026-06-02-abcdef123456")
self.assertEqual(
+ data["endpoint_generation"],
+ preview.read_endpoint_protocol_generation(),
+ )
+ self.assertEqual(
data["assets"]["linux-x86_64"]["sha256"],
"deadbeef",
)
@@ -62,6 +66,10 @@ class PreviewNotesTests(unittest.TestCase):
)
self.assertEqual(data["assets"]["windows-x86_64"]["format"], "zip")
self.assertIn("2026-06-02-abcdef123456", data["builds"])
+ self.assertEqual(
+ data["builds"]["2026-06-02-abcdef123456"]["endpoint_generation"],
+ preview.read_endpoint_protocol_generation(),
+ )
def test_windows_preview_asset_requires_sha256(self):
with tempfile.TemporaryDirectory() as tmp: