diff --git a/packaging/macos/Info.plist b/packaging/macos/Info.plist index 7ceecbb..550a831 100644 --- a/packaging/macos/Info.plist +++ b/packaging/macos/Info.plist @@ -36,9 +36,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 3.2.0 + 3.6.0 CFBundleVersion - 1 + 3.6.0 LSMinimumSystemVersion 13.0 NSHumanReadableCopyright diff --git a/packaging/macos/build_app.sh b/packaging/macos/build_app.sh index a3e8231..66d47b3 100755 --- a/packaging/macos/build_app.sh +++ b/packaging/macos/build_app.sh @@ -78,6 +78,11 @@ APP_VERSION="$(tr -d '[:space:]' < "$REPO/VERSION" 2>/dev/null || true)" if [ -n "$APP_VERSION" ] && command -v plutil >/dev/null 2>&1; then plutil -replace CFBundleShortVersionString -string "$APP_VERSION" "$CONTENTS/Info.plist" echo "==> bundle CFBundleShortVersionString = $APP_VERSION (from VERSION)" + # Sparkle decides "is this newer?" from CFBundleVersion (the appcast's sparkle:version), + # not the short string. It stayed "1" on every build, so no installed copy was ever + # offered an update. Use the same version. + plutil -replace CFBundleVersion -string "$APP_VERSION" "$CONTENTS/Info.plist" + echo "==> bundle CFBundleVersion = $APP_VERSION (from VERSION)" fi printf 'APPL????' > "$CONTENTS/PkgInfo" diff --git a/tests/test_app_bundle.py b/tests/test_app_bundle.py index bc39b78..90ec337 100644 --- a/tests/test_app_bundle.py +++ b/tests/test_app_bundle.py @@ -75,3 +75,20 @@ def test_build_assembles_bundle_and_selftest_passes(): capture_output=True, text=True, timeout=60, ) assert st.returncode == 0, f"--selftest failed: {st.stderr}\n{st.stdout}" + + +def test_the_bundle_carries_the_release_version_as_its_build_number(): + # Sparkle offers an update only when the appcast's sparkle:version (CFBundleVersion) is + # higher than the installed one. It stayed "1" on every build, so no installed copy was + # ever offered an update. Both version keys now come from VERSION. + import plistlib + version = (REPO / "VERSION").read_text(encoding="utf-8").strip() + static = plistlib.loads((PKG / "Info.plist").read_bytes()) + assert static["CFBundleVersion"] == static["CFBundleShortVersionString"] == version, "static plist matches VERSION" + if sys.platform != "darwin": + return # the build itself needs macOS (Swift/AppKit launcher, plutil) + with tempfile.TemporaryDirectory() as td: + r = subprocess.run(["bash", str(BUILD), "--out", td, "--clean"], capture_output=True, text=True, timeout=120) + assert r.returncode == 0, r.stderr + built = plistlib.loads((Path(td) / "Sovereign AI Workstation.app" / "Contents" / "Info.plist").read_bytes()) + assert built["CFBundleVersion"] == built["CFBundleShortVersionString"] == version