diff --git a/apps/desktop/src/desktop-auto-update.ts b/apps/desktop/src/desktop-auto-update.ts index 1dd05a9355..572c576e8e 100644 --- a/apps/desktop/src/desktop-auto-update.ts +++ b/apps/desktop/src/desktop-auto-update.ts @@ -306,6 +306,14 @@ export function createDesktopAutoUpdateService( if (!args.enabled) { return currentInfo; } + // A downloaded update is a staged ShipIt install. Re-checking tears that + // staging down (Squirrel replaces update. with a fresh partial + // extraction), so a Relaunch issued afterwards installs a directory + // without the app bundle and ShipIt aborts three times, leaving the user + // on the old version. Hold the staged install until it is applied. + if (currentInfo.updateDownloaded) { + return currentInfo; + } if (inflight !== null) { return inflight; } diff --git a/apps/desktop/test/desktop-auto-update.test.ts b/apps/desktop/test/desktop-auto-update.test.ts index 62edde773b..4f39292bf0 100644 --- a/apps/desktop/test/desktop-auto-update.test.ts +++ b/apps/desktop/test/desktop-auto-update.test.ts @@ -367,6 +367,44 @@ describe("desktop auto-update service", () => { }); }); + it("holds a downloaded update by skipping re-checks that would tear down its staging", async () => { + const updater = new DesktopAutoUpdaterAdapterStub(); + updater.updateCheckResult = createUpdateCheckResult("0.0.2"); + let currentTime = Date.parse(checkedAt); + const service = createDesktopAutoUpdateService({ + currentVersion: "0.0.1", + enabled: true, + forceDevUpdateConfig: false, + logger: createLogger(createLoggerMessages()), + now: () => currentTime, + platform: "macos", + updater, + }); + + await service.checkForUpdates(); + expect(updater.checkForUpdatesCalls).toBe(1); + + updater.emitUpdateDownloaded(createDownloadedEvent("0.0.2")); + await service.checkForUpdates(); + // Advance past the active-check throttle so this reaches checkForUpdates. + currentTime += 16 * 60 * 1000; + await service.checkAfterActive(); + + // The staged ShipIt install stays untouched: no further checks run and + // the info keeps reporting the downloaded update. + expect(updater.checkForUpdatesCalls).toBe(1); + expect(service.getInfo()).toEqual({ + downloadState: "downloaded", + lastCheckedAt: checkedAt, + latestVersion: "0.0.2", + pendingVersion: "0.0.2", + platform: "macos", + updateAvailable: true, + updateDownloaded: true, + version: "0.0.1", + }); + }); + it("does not initialize electron-updater in dev mode without the override", async () => { const updater = new DesktopAutoUpdaterAdapterStub(); const enabled = shouldEnableDesktopAutoUpdate({