mac: release script refuses a build number Sparkle would ignore (#1456)
Sparkle orders by <sparkle:version> (the build number), so a mint at or below the live appcast head gets its DMG silently shunted to old_updates after ten minutes of archive + notarize. Preflight against the live feed and fail with the number to use; assert post-generate_appcast too. Claude-Session: https://claude.ai/code/session_014mt8aQ3bwLs1kcqeP598xr
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+22
−0
ios/release-mac.sh+22 −0
diff --git a/ios/release-mac.sh b/ios/release-mac.sh| index 5650de9..11413bc 100755 |
| --- a/ios/release-mac.sh |
| +++ b/ios/release-mac.sh |
| @@ -49,6 +49,19 @@ BUILD="${2:?usage: release-mac.sh <marketing-version> <build-number>}" |
| RELEASES_REPO="${LCHAT_RELEASES_REPO:-elevenmessenger/releases}" |
| TEAM_ID="J5NDF5PCD8" |
| APP_NAME="Eleven" |
| + |
| +# Sparkle orders releases by <sparkle:version> — the BUILD number, not the |
| +# marketing version — so a build at or below the live feed's head is "old": |
| +# generate_appcast quietly shunts the fresh DMG to old_updates and ships |
| +# nothing, ten minutes and one notarization too late (the 0.9.1-as-build-1 |
| +# mint, 2026-08-28). Refuse up front instead. |
| +LIVE_HEAD="$(gh release download -R "$RELEASES_REPO" -p appcast.xml -O - 2>/dev/null \ |
| + | sed -n 's/.*<sparkle:version>\([0-9][0-9]*\)<\/sparkle:version>.*/\1/p' \ |
| + | sort -n | tail -1)" |
| +if [ -n "$LIVE_HEAD" ] && [ "$BUILD" -le "$LIVE_HEAD" ]; then |
| + echo "error: build $BUILD is not newer than the live appcast's head (build $LIVE_HEAD) — Sparkle would ignore it. Use $((LIVE_HEAD + 1))." >&2 |
| + exit 1 |
| +fi |
| # Keep in sync with the `packages.Sparkle.exactVersion` pin in ios/project.yml |
| # — generate_appcast's flags are matched against this exact release's --help. |
| SPARKLE_VERSION="2.9.4" |
| @@ -165,6 +178,15 @@ chmod +x "$TMP/sparkle-tools/bin/generate_appcast" |
| --maximum-deltas 0 \ |
| "$APPCAST_DIR" |
| +# Belt to the preflight's braces: if generate_appcast still didn't write this |
| +# build (it moves anything it deems old to old_updates and reports success), |
| +# say so plainly instead of letting the release-create step fail on a missing |
| +# file two commands later. |
| +grep -q "<sparkle:version>$BUILD</sparkle:version>" "$APPCAST_DIR/appcast.xml" || { |
| + echo "error: generate_appcast did not add build $BUILD to appcast.xml — nothing to publish" >&2 |
| + exit 1 |
| +} |
| + |
| # Embed the "what's new" HTML inline as this item's <description> so it renders |
| # in the in-app updater (see embed-release-notes.py for why inline beats a link). |
| if [ -n "$NOTES_HTML" ]; then |