From b56314aa404fa5f77b8d84af78a12942cc89de35 Mon Sep 17 00:00:00 2001 From: ethernet Date: Wed, 23 Sep 2026 09:27:46 -0400 Subject: [PATCH] feat(release): warn that attempt builds are not upgrade-safe Hand-installed attempt builds share the plain package version with the published release, so the updater never replaces them. The diagnostic page for an attempt ref now says so above the file table (decision 25). --- scripts/render-builds-table.py | 9 ++++++++- tests/scripts/test_render_builds_publication.py | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/render-builds-table.py b/scripts/render-builds-table.py index 9289a9cd11..f75df96e2d 100644 --- a/scripts/render-builds-table.py +++ b/scripts/render-builds-table.py @@ -53,7 +53,7 @@ from urllib.parse import quote # Direct-script invocation starts with scripts/, not the repository root. sys.path.insert(0, str(Path(__file__).resolve().parents[1])) -from scripts.releases import handoff, r2, semver, stable # noqa: E402 +from scripts.releases import handoff, r2, semver, stable, versioning # noqa: E402 MARKER = "" END_MARKER = "" @@ -409,6 +409,13 @@ def render_page(tag: str, assets_by_app: dict, base_url: str, f"

Release {_link(tag_url)}{html.escape(tag)}. Only objects this release " "actually staged in the bucket are listed.

", ] + attempt = versioning.parse_attempt_ref(tag) + if attempt is not None: + version = attempt[0] + body.append("

" + + html.escape(f"Attempt builds are not upgrade-safe: every attempt of {version} has the same " + f"package version, so an installed attempt is not replaced by the published {version}.") + + "

") if incomplete_jobs: body.append("

Build incomplete. Jobs not successful: " + html.escape(", ".join(incomplete_jobs)) diff --git a/tests/scripts/test_render_builds_publication.py b/tests/scripts/test_render_builds_publication.py index 2c9b11625c..df70800731 100644 --- a/tests/scripts/test_render_builds_publication.py +++ b/tests/scripts/test_render_builds_publication.py @@ -118,6 +118,16 @@ def test_incomplete_tag_keeps_channel_and_links_diagnostics(monkeypatch, r2_serv assert r2_server.store['releases/canary/index.html'][0] == b'previous good page' +def test_attempt_page_warns_and_canary_page_does_not(): + base = 'https://cdn.example' + sentence = ('Attempt builds are not upgrade-safe: every attempt of 1.2.3 has the same ' + 'package version, so an installed attempt is not replaced by the published 1.2.3.') + page = rbt.render_page('rc.1-v1.2.3', {}, base) + assert sentence in page + for tag in ('v1.2.3', 'v1.2.3+canary.20260818T101010Z', 'abandoned-rc.1-v1.2.3'): + assert sentence not in rbt.render_page(tag, {}, base) + + @pytest.mark.parametrize('version,name', [ ('1.2.3', 'HermesBundled-1.2.3-win-x64.msix'), ('1.2.3+canary.20260818T000000Z', 'HermesBundled-1.2.3+canary.20260818T000000Z-win-x64.msix'),