From 4fc4f0f11ec9e991641284c785709c6e6b3c4a00 Mon Sep 17 00:00:00 2001 From: Chris Portscheller Date: Fri, 2 Oct 2026 18:11:52 -0500 Subject: [PATCH] fix(release): release-all checks, uploads and verifies plugin-info.json plugin-info.json (the "View details" panel) was never uploaded by release-all.sh, so the CDN kept serving the previous release's metadata until someone uploaded it by hand. The script now refuses to publish unless the file names the release and its zip, uploads it after the manifest, and checks the CDN serves the new version. --- RELEASING.md | 4 +++- bin/release-all.sh | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/RELEASING.md b/RELEASING.md index 8ecd807..e963a5b 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -41,7 +41,9 @@ This runs `build.sh`, produces `dist/webdecoy-.zip`, and regenerates rejects a package whose hash doesn't match). `cdn-files/update-info.json` is git-ignored on purpose — it's a per-build artifact, uploaded to the CDN rather than committed. `cdn-files/plugin-info.json` (the "View details" metadata) is -tracked; bump its `version`/`download_url`/changelog when they change. +tracked; bump its `version`, `download_url` and changelog with every release. +`bin/release-all.sh` refuses to publish until it names the release, then +uploads it with the zip and manifest and checks what the CDN serves. ## 3. Upload to the CDN diff --git a/bin/release-all.sh b/bin/release-all.sh index b65c5ed..1cfabd5 100755 --- a/bin/release-all.sh +++ b/bin/release-all.sh @@ -108,6 +108,16 @@ MANIFEST_VER="$(python3 -c "import json;print(json.load(open('cdn-files/update-i [ "${MANIFEST_VER}" = "${VERSION}" ] || die "update-info.json says version ${MANIFEST_VER}, expected ${VERSION}" ok "zip and manifest agree on ${ZIP_SHA}" +# plugin-info.json is the "View details" panel self-hosted installs read. It is +# tracked and edited by hand, so check it names this release before anything is +# uploaded; it used to be left out of the upload entirely and went stale. +INFO_VER="$(python3 -c "import json;print(json.load(open('cdn-files/plugin-info.json'))['version'])")" +INFO_URL="$(python3 -c "import json;print(json.load(open('cdn-files/plugin-info.json'))['download_url'])")" +[ "${INFO_VER}" = "${VERSION}" ] || die "cdn-files/plugin-info.json says version ${INFO_VER}, expected ${VERSION} — bump it first" +[ "${INFO_URL}" = "${CDN_BASE}/${SLUG}-${VERSION}.zip" ] \ + || die "cdn-files/plugin-info.json download_url is ${INFO_URL}, expected ${CDN_BASE}/${SLUG}-${VERSION}.zip" +ok "plugin-info.json names ${VERSION}" + if [ "${DO_PUBLISH}" = "1" ]; then say "Publishing to R2" # Zip BEFORE manifest: a manifest naming a zip that is not there yet breaks every @@ -118,6 +128,10 @@ if [ "${DO_PUBLISH}" = "1" ]; then npx wrangler r2 object put "${R2_BUCKET}/wordpress/update-info.json" \ --file=./cdn-files/update-info.json --remote >/dev/null 2>&1 || die "R2 upload of the manifest failed" ok "uploaded update-info.json" + npx wrangler r2 object put "${R2_BUCKET}/wordpress/plugin-info.json" \ + --file=./cdn-files/plugin-info.json --content-type application/json --remote >/dev/null 2>&1 \ + || die "R2 upload of plugin-info.json failed" + ok "uploaded plugin-info.json" say "Verifying what the CDN actually serves" served="$(curl -fsS "${CDN_BASE}/${SLUG}-${VERSION}.zip" | shasum -a 256 | cut -d' ' -f1)" \ @@ -127,6 +141,9 @@ if [ "${DO_PUBLISH}" = "1" ]; then served_ver="$(curl -fsS "${CDN_BASE}/update-info.json" | python3 -c "import json,sys;print(json.load(sys.stdin)['version'])")" [ "${served_ver}" = "${VERSION}" ] || die "CDN manifest says ${served_ver}" ok "CDN manifest says ${VERSION}" + served_info="$(curl -fsS "${CDN_BASE}/plugin-info.json?v=${VERSION}" | python3 -c "import json,sys;print(json.load(sys.stdin)['version'])")" + [ "${served_info}" = "${VERSION}" ] || die "CDN plugin-info.json says ${served_info}" + ok "CDN plugin-info.json says ${VERSION}" else ok "dry run — nothing uploaded to R2" fi