Skip to content

Build the appcast download URL from the release tag - #5

Merged
anibalribeiro merged 1 commit into
mainfrom
fix/appcast-tag-mismatch
Sep 4, 2026
Merged

Build the appcast download URL from the release tag#5
anibalribeiro merged 1 commit into
mainfrom
fix/appcast-tag-mismatch

Conversation

@anibalribeiro

Copy link
Copy Markdown
Owner

Closes the workflow_dispatch footgun left open when 1.1.0 shipped.

The problem

The appcast enclosure URL was hardcoded to releases/download/v{{VERSION}}, while a workflow_dispatch run tags manual-<version>. Checking publish on a manual run would have published a feed pointing at a URL that does not exist.

That would not have stayed contained. GitHub serves releases/latest/download/appcast.xml from whichever release is newest, and the manual release was created as a normal release, so it would have become latest and handed a broken feed to every installed copy of the app. The Homebrew step had the mirror-image problem: the cask URL is built from v<version>, absent under a manual tag, so it would have pointed brew users at a 404 too.

The fix

  • {{TAG}} replaces the hardcoded v{{VERSION}} in the template, and generate-appcast.sh takes the tag as a required fourth argument. It is not defaulted to v<version>, since a silent default is how this got in.
  • Manual publishes are created with --prerelease, so they can never become releases/latest.
  • The Homebrew tap step is skipped for manual runs.

Verification

Tests were written first and confirmed failing for the right reason before the fix. Beyond the suite, the strongest check: regenerating the live 1.1.0 appcast with this change and diffing it against what is actually published is byte-identical apart from the time-based pubDate, so real tag releases are unaffected.

The resolve-version logic was also simulated across all three trigger paths (tag push, manual publish, manual dry run) to confirm the tag and prerelease values come out right.

Made with Cursor

The enclosure URL was hardcoded to releases/download/v<version>, but a
workflow_dispatch run publishes under manual-<version>. Checking publish on
a manual run would therefore have produced a feed pointing at a URL that does
not exist.

Worse, that feed would not have stayed contained. GitHub serves
releases/latest/download/appcast.xml from whichever release is newest, and
the manual release was created as a normal one, so it would have become
"latest" and handed a broken feed to every installed copy of the app. The
Homebrew step had the same problem from the other direction: the cask URL is
built from v<version>, which does not exist under a manual tag.

So the tag is now a required argument rather than something derived from the
version, and manual publishes are constrained to be prereleases with the tap
left alone. Regenerating the live 1.1.0 feed with this change produces a
byte-identical result, so tag releases are unaffected.

Co-authored-by: Cursor <cursoragent@cursor.com>
@anibalribeiro
anibalribeiro merged commit 98dd0bb into main Sep 4, 2026
2 checks passed
@anibalribeiro
anibalribeiro deleted the fix/appcast-tag-mismatch branch September 4, 2026 10:43
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