Skip to content

Add Sparkle-based app updater and release appcast artifacts#4

Merged
nikuscs merged 1 commit intomainfrom
feature/add-app-updater
Feb 16, 2026
Merged

Add Sparkle-based app updater and release appcast artifacts#4
nikuscs merged 1 commit intomainfrom
feature/add-app-updater

Conversation

@nikuscs
Copy link
Copy Markdown
Owner

@nikuscs nikuscs commented Feb 16, 2026

Integrates Sparkle into the macOS app and adds a new updater view model exposed in the menu bar via a Check for Updates action. Adds SUFeedURL and SUPublicEDKey to the app Info.plist and wires Sparkle as an Xcode package dependency. Updates the release workflow to produce a versioned zip, sign it with Sparkle, generate appcast.xml, and upload zip/appcast alongside the DMG. This enables in-app update checks against GitHub Releases artifacts.


Open with Devin

@nikuscs nikuscs requested a review from sousavf as a code owner February 16, 2026 15:19
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

<item>
<title>Version ${VERSION}</title>
<pubDate>${PUB_DATE}</pubDate>
<sparkle:version>${VERSION}</sparkle:version>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Appcast sparkle:version uses marketing version instead of build number, breaking update detection

The appcast.xml sets sparkle:version to the semantic version string (e.g., 1.2.3), but the app's CFBundleVersion is set to a computed build number (e.g., 10203 for version 1.2.3) at .github/workflows/release.yml:135.

Root Cause and Impact

Sparkle compares sparkle:version from the appcast against the running app's CFBundleVersion to determine if an update is available. The workflow computes CFBundleVersion as MAJOR * 10000 + MINOR * 100 + PATCH (e.g., version 1.2.3 → build 10203) at line 135:

BUILD=$((MAJOR * 10000 + MINOR * 100 + PATCH))

But the appcast sets sparkle:version to the raw semantic version string ${VERSION} (e.g., 1.2.3):

<sparkle:version>${VERSION}</sparkle:version>

Sparkle's SUStandardVersionComparator splits version strings by . and compares components. When comparing appcast's 1.2.3 (components: [1, 2, 3]) against the installed app's 10203 (single component: [10203]), the first component comparison is 1 vs 10203 — the installed version always appears newer.

Impact: Sparkle will never offer updates to users because it always thinks the installed version is newer than the version advertised in the appcast. The entire auto-update feature is non-functional.

The fix is to set sparkle:version to the same computed build number used for CFBundleVersion, e.g.:

<sparkle:version>${BUILD}</sparkle:version>

This requires computing the BUILD variable in the "Generate appcast.xml" step or passing it as an output from the version step.

Prompt for agents
In .github/workflows/release.yml, the 'Generate appcast.xml' step at line 273 sets sparkle:version to the semantic version string (VERSION, e.g. '1.2.3'), but it must match CFBundleVersion which is computed as MAJOR*10000 + MINOR*100 + PATCH (e.g. 10203) at line 135.

To fix this:
1. In the 'Get version from tag' step (around line 127), add an output for the build number by adding this line after line 135:
   echo "build=$BUILD" >> $GITHUB_OUTPUT

2. In the 'Generate appcast.xml' step (around line 259), add a BUILD variable:
   BUILD="${{ steps.version.outputs.build }}"

3. Change line 273 from:
   <sparkle:version>${VERSION}</sparkle:version>
   to:
   <sparkle:version>${BUILD}</sparkle:version>

This ensures sparkle:version matches CFBundleVersion so Sparkle can correctly detect when updates are available.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@nikuscs nikuscs merged commit ffbc41b into main Feb 16, 2026
1 check passed
@nikuscs nikuscs deleted the feature/add-app-updater branch February 16, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant