fix(updater): keep prerelease users on the RC channel (#1053)
Detect when the running build is itself a prerelease (e.g. 1.3.17-rc.1) and auto-enable the RC feed in setupAutoUpdater. Without this, the default generic /releases/latest/download/ feed only advertises stable releases, so "Check for Updates" from a prerelease build could never find the next RC (e.g. 1.3.17-rc.2) unless the user knew to Shift-click.
This commit is contained in:
parent
749ba42cb2
commit
f0c96bd2bf
|
|
@ -97,6 +97,17 @@ export function isValidVersion(value: string): boolean {
|
|||
return parseVersion(value) !== null
|
||||
}
|
||||
|
||||
// Why: a user running a prerelease build (e.g. 1.3.17-rc.1) must stay on the
|
||||
// RC channel for "Check for Updates" to resolve the next RC (1.3.17-rc.2).
|
||||
// The default generic feed only advertises non-prerelease releases, so without
|
||||
// this detection a prerelease user would be stuck unless they knew to
|
||||
// Shift-click the menu item — effectively trapping them on the RC they
|
||||
// installed.
|
||||
export function isPrereleaseVersion(value: string): boolean {
|
||||
const parsed = parseVersion(value)
|
||||
return parsed !== null && parsed.prerelease.length > 0
|
||||
}
|
||||
|
||||
function compareIdentifiers(left: string, right: string): number {
|
||||
const leftNumeric = /^\d+$/.test(left)
|
||||
const rightNumeric = /^\d+$/.test(right)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { compareVersions } from './updater-fallback'
|
||||
import { compareVersions, isPrereleaseVersion } from './updater-fallback'
|
||||
|
||||
describe('compareVersions', () => {
|
||||
it('compares prerelease and build semver strings correctly', () => {
|
||||
|
|
@ -9,3 +9,19 @@ describe('compareVersions', () => {
|
|||
expect(compareVersions('v1.0.70-beta.2', '1.0.70-beta.1')).toBeGreaterThan(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isPrereleaseVersion', () => {
|
||||
it('recognises RC, beta, and alpha variants', () => {
|
||||
expect(isPrereleaseVersion('1.3.17-rc.1')).toBe(true)
|
||||
expect(isPrereleaseVersion('v1.3.17-rc.2')).toBe(true)
|
||||
expect(isPrereleaseVersion('1.0.0-beta.5')).toBe(true)
|
||||
expect(isPrereleaseVersion('2.1.0-alpha')).toBe(true)
|
||||
})
|
||||
|
||||
it('returns false for stable releases and unparseable values', () => {
|
||||
expect(isPrereleaseVersion('1.3.17')).toBe(false)
|
||||
expect(isPrereleaseVersion('v1.3.17')).toBe(false)
|
||||
expect(isPrereleaseVersion('1.3.17+build.5')).toBe(false)
|
||||
expect(isPrereleaseVersion('not-a-version')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -750,4 +750,43 @@ describe('updater', () => {
|
|||
|
||||
expect((autoUpdaterMock as Record<string, unknown>).verifyUpdateCodeSignature).toBeUndefined()
|
||||
})
|
||||
|
||||
// Why: a user running an RC (e.g. 1.3.17-rc.1) must stay on the RC channel
|
||||
// so the default "Check for Updates" path can find the next RC. The generic
|
||||
// /releases/latest/download/ feed only exposes non-prerelease releases.
|
||||
it('auto-enables the RC channel at setup when running a prerelease build', async () => {
|
||||
appMock.getVersion.mockReturnValue('1.3.17-rc.1')
|
||||
autoUpdaterMock.checkForUpdates.mockResolvedValue(undefined)
|
||||
|
||||
const { setupAutoUpdater } = await import('./updater')
|
||||
|
||||
const mainWindow = { webContents: { send: vi.fn() } }
|
||||
setupAutoUpdater(mainWindow as never, { getLastUpdateCheckAt: () => Date.now() })
|
||||
|
||||
expect(autoUpdaterMock.allowPrerelease).toBe(true)
|
||||
expect(autoUpdaterMock.setFeedURL).toHaveBeenCalledWith({
|
||||
provider: 'github',
|
||||
owner: 'stablyai',
|
||||
repo: 'orca'
|
||||
})
|
||||
expect(autoUpdaterMock.setFeedURL).not.toHaveBeenCalledWith(
|
||||
expect.objectContaining({ provider: 'generic' })
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps the generic feed at setup when running a stable release', async () => {
|
||||
appMock.getVersion.mockReturnValue('1.3.17')
|
||||
autoUpdaterMock.checkForUpdates.mockResolvedValue(undefined)
|
||||
|
||||
const { setupAutoUpdater } = await import('./updater')
|
||||
|
||||
const mainWindow = { webContents: { send: vi.fn() } }
|
||||
setupAutoUpdater(mainWindow as never, { getLastUpdateCheckAt: () => Date.now() })
|
||||
|
||||
expect(autoUpdaterMock.allowPrerelease).not.toBe(true)
|
||||
expect(autoUpdaterMock.setFeedURL).toHaveBeenCalledWith({
|
||||
provider: 'generic',
|
||||
url: 'https://github.com/stablyai/orca/releases/latest/download'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,7 +11,12 @@ import {
|
|||
markMacQuitAndInstallInFlight
|
||||
} from './updater-mac-install'
|
||||
import { registerAutoUpdaterHandlers } from './updater-events'
|
||||
import { compareVersions, isBenignCheckFailure, statusesEqual } from './updater-fallback'
|
||||
import {
|
||||
compareVersions,
|
||||
isBenignCheckFailure,
|
||||
isPrereleaseVersion,
|
||||
statusesEqual
|
||||
} from './updater-fallback'
|
||||
import { fetchNudge, shouldApplyNudge } from './updater-nudge'
|
||||
|
||||
const AUTO_UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000
|
||||
|
|
@ -476,15 +481,24 @@ export function setupAutoUpdater(
|
|||
;(autoUpdater as NsisUpdater).verifyUpdateCodeSignature = () => Promise.resolve(null)
|
||||
}
|
||||
|
||||
// Use the generic provider with GitHub's /releases/latest/download/ URL so
|
||||
// electron-updater always fetches the manifest (latest-mac.yml, latest.yml,
|
||||
// latest-linux.yml) from the latest non-prerelease release. This sidesteps
|
||||
// the broken /releases/latest API endpoint (returns 406) and automatically
|
||||
// excludes RC/prerelease versions without client-side filtering.
|
||||
autoUpdater.setFeedURL({
|
||||
provider: 'generic',
|
||||
url: 'https://github.com/stablyai/orca/releases/latest/download'
|
||||
})
|
||||
// Why: a user already running a prerelease (e.g. 1.3.17-rc.1) must stay on
|
||||
// the RC channel so "Check for Updates" can find the next RC (1.3.17-rc.2).
|
||||
// The generic /releases/latest/download/ feed only advertises non-prerelease
|
||||
// releases, so without this they'd never see the follow-up RC. Users on a
|
||||
// stable release keep the generic feed and must Shift-click to opt in.
|
||||
if (isPrereleaseVersion(app.getVersion())) {
|
||||
enableIncludePrerelease()
|
||||
} else {
|
||||
// Use the generic provider with GitHub's /releases/latest/download/ URL so
|
||||
// electron-updater always fetches the manifest (latest-mac.yml, latest.yml,
|
||||
// latest-linux.yml) from the latest non-prerelease release. This sidesteps
|
||||
// the broken /releases/latest API endpoint (returns 406) and automatically
|
||||
// excludes RC/prerelease versions without client-side filtering.
|
||||
autoUpdater.setFeedURL({
|
||||
provider: 'generic',
|
||||
url: 'https://github.com/stablyai/orca/releases/latest/download'
|
||||
})
|
||||
}
|
||||
|
||||
if (autoUpdaterInitialized) {
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue