fix(release): use v<semver> tag format for nightly releases#2186
Conversation
Nightly releases were being tagged as 'nightly-v<version>' (e.g.
'nightly-v0.0.21-nightly.20260417.58'). This tag is not valid semver
because the 'nightly-v' prefix does not match semver's leading
(optional 'v' + digit) grammar.
electron-updater's GitHubProvider relies on the 'semver' package in
two places when resolving updates from the releases.atom feed:
1. Channel matching (providers/GitHubProvider.js:68):
const hrefChannel = semver.prerelease(hrefTag)?.[0] || null;
With 'channel = nightly' and allowPrerelease = true, a release is
only picked when its tag parses as a semver prerelease whose first
identifier equals 'nightly'. semver.prerelease('nightly-v...') is
null, so no nightly release ever matches and the updater throws
'No published versions on GitHub' (pingdotgg#2181).
2. Release notes (providers/GitHubProvider.js:189):
const versionRelease = /\/tag\/v?([^/]+)$/.exec(...)[1];
if (semver.valid(versionRelease) && ...) { ... }
Same reason: the remainder after stripping an optional 'v' must
be valid semver, which 'nightly-v...' is not.
Dropping the 'nightly-' prefix yields 'v<base>-nightly.<date>.<run>',
which IS valid semver with prerelease identifier 'nightly' — exactly
the format electron-updater expects for a custom channel. Stable
tags remain 'v<semver>' and are unaffected.
Changes:
- scripts/resolve-nightly-release.ts: emit 'v<version>' instead of
'nightly-v<version>'.
- scripts/resolve-nightly-release.test.ts,
scripts/release-smoke.ts: update fixtures for the new tag.
- scripts/resolve-previous-release-tag.ts:
- parseStableTag now rejects tags whose first prerelease identifier
is 'nightly' (new nightly tags also start with 'v', so the stable
resolver has to exclude them explicitly).
- parseNightlyTag accepts both the new 'v<version>' format and the
legacy 'nightly-v<version>' format so release-note diffs against
the last published nightly keep working across the transition.
- .github/workflows/release.yml:
- last_nightly_tag lookup now matches 'v*-nightly.*' in addition to
legacy 'nightly-v*'.
- The push-tags trigger excludes 'v*-nightly.*' so the new nightly
tags don't accidentally re-trigger the stable release path.
Existing 'nightly-v*' tags stay in the repo as inert history; no
retagging is performed. Nightly users affected by pingdotgg#2181 currently
cannot update at all, so there is no update-path regression — only
forward progress.
Closes pingdotgg#2181
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Approved This PR changes the nightly release tag format from You can customize Macroscope's approvability policy. Learn more. |
Closes #2181
What
Drop the
nightly-prefix from nightly release tags so they become valid semver that electron-updater can parse.nightly-v0.0.21-nightly.20260417.58v0.0.21-nightly.20260417.58Stable tags (
v<semver>) are unchanged. Existingnightly-v*tags stay in the repo as inert history — no retagging.Why
The nightly update track has never actually worked. #2181 reports it, and you can reproduce it on 0.0.20: switch to the Nightly channel → "Check for updates" →
Error: No published versions on GitHub.Root cause is in
electron-updater'sGitHubProvider, which uses thesemverpackage to parse tags fromreleases.atom. Two places, same problem:1. Channel matching —
providers/GitHubProvider.js:68:With
autoUpdater.channel = 'nightly'andallowPrerelease = true, a release is selected only whenhrefChannel === 'nightly'. For that to hold, the tag must be valid semver with a prerelease identifiernightly.semver.prerelease('v0.0.21-nightly.20260417.58')→['nightly', '20260417', 58]✅semver.prerelease('nightly-v0.0.21-nightly.20260417.58')→null❌ (the leadingnightly-vbreaks semver's grammar, which requires either a digit or an optionalv+ digit)So no entry in the atom feed matches and the loop exits with
tag == null, throwingNo published versions on GitHub.2. Release notes computation —
providers/GitHubProvider.js:189:The optional
v?strip doesn't help either — the remainder (nightly-v0.0.21-...) still isn'tsemver.valid(), so nightlies never show up in release notes either.Fix
The minimal, library-aligned fix: make the tag valid semver. Dropping the
nightly-prefix yieldsv<base>-nightly.<date>.<run>, which:semver.valid()✅nightly— matchesautoUpdater.channel = 'nightly'✅0.0.21-nightly.20260417.58 < 0.0.21 < 0.0.22) ✅Changes
scripts/resolve-nightly-release.ts— emitv<version>instead ofnightly-v<version>.scripts/resolve-nightly-release.test.ts,scripts/release-smoke.ts— fixtures updated for the new tag.scripts/resolve-previous-release-tag.ts:parseStableTagnow rejects tags whose first prerelease identifier isnightly(the new nightly tags also start withv, so the stable resolver has to skip them explicitly).parseNightlyTagaccepts both the newv<version>format and the legacynightly-v<version>format so the "previous nightly" release-note diff keeps working across the transition..github/workflows/release.yml:last_nightly_taglookup matchesv*-nightly.*in addition to legacynightly-v*.push.tagstrigger excludesv*-nightly.*so creating a new nightly tag doesn't accidentally re-trigger the stable release path.No runtime code (
apps/desktop/*) is touched. No library patches, no workarounds — just aligning the tag we publish with the formatelectron-updateralready expects.Why not a runtime workaround in
main.ts?I considered a desktop-side workaround (fetch recent releases via GitHub API, pick the latest nightly ourselves, point
autoUpdater.setFeedURLat that release as agenericprovider). Decided against it because:GitHubProvider, nightly uses custom logic) that need to stay in sync forever.nightly-v*tag format indefinitely, with client-side logic whose only job is to work around that format.The tag-format change is 5 files, 15 insertions, 6 deletions — all in release tooling, none in runtime.
Testing
bun fmt,bun lint,bun typecheck,bun run testall pass.scripts/resolve-nightly-release.test.tsasserts the new tag shape.node scripts/resolve-nightly-release.tsandnode scripts/resolve-previous-release-tag.tsfor both channels against the current repo tags —previous_tagresolution correctly findsv0.0.19for stable and the lastnightly-v*legacy tag for nightly.Risks / compatibility
nightly-v*tags: untouched, no rename. They remain in git history and on the Releases page.nightly-v*build: they cannot update today anyway (that's the bug). After this PR the next nightly will bev<semver>,semver.gtpicks it up correctly, and they transition forward. No "stuck user" scenario.v<semver>without a-nightly.*prerelease.push.tagstrigger: the added!v*-nightly.*exclusion prevents the stable path from firing when the nightly job creates the new-format tag.Note
Fix nightly release tag format to use
v<semver>-nightly.<date>.<run>resolveNightlyReleaseMetadatain resolve-nightly-release.ts to generate tags asv<semver>-nightly.<date>.<run>instead ofnightly-v<semver>-nightly.<date>.<run>.parseNightlyTagin resolve-previous-release-tag.ts to accept both the newv*-nightly.*format and the legacynightly-v*format.parseStableTagto exclude nightly-tagged versions from being treated as stable releases.v*-nightly.*tags from triggering the stable release job, and to search both tag formats when finding the last nightly.v*-nightly.*format; oldnightly-v*tags remain recognized for backward compatibility.Macroscope summarized 5a0162d.