From 2e3e3a1536e3846ced826c82218b67588444863a Mon Sep 17 00:00:00 2001 From: Hampus Date: Thu, 8 Oct 2026 00:04:58 +0200 Subject: [PATCH] fix(desktop): fix manual update wording and retry Velopack (#3261) --- .../channel_header_components/UpdaterIcon.tsx | 3 +- fluxer_desktop/src/main/Updater.test.mjs | 32 +++++++++++++++++++ fluxer_desktop/src/main/Updater.ts | 21 ++++++++++-- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/fluxer_app/src/features/channel/components/channel_header_components/UpdaterIcon.tsx b/fluxer_app/src/features/channel/components/channel_header_components/UpdaterIcon.tsx index ba0031661..6f4c62f7d 100644 --- a/fluxer_app/src/features/channel/components/channel_header_components/UpdaterIcon.tsx +++ b/fluxer_app/src/features/channel/components/channel_header_components/UpdaterIcon.tsx @@ -159,7 +159,7 @@ export const UpdaterIcon = observer(() => { : i18n._(DOWNLOADING_UPDATE_2_DESCRIPTOR, {percent}); } if (Platform.isElectron && (store.nativeAwaitingDownload || store.nativeManualUpdateAvailable)) { - if (store.nativeManualUpdateAvailable) { + if (store.nativeManualUpdateAvailable && store.nativeManualDownloadOptions.length > 0) { return version ? i18n._(CHOOSE_LINUX_PACKAGE_DESCRIPTOR, {version}) : i18n._(CHOOSE_LINUX_PACKAGE_2_DESCRIPTOR); } const size = store.updateInfo.native.downloadSize; @@ -188,6 +188,7 @@ export const UpdaterIcon = observer(() => { store.nativeAwaitingDownload, store.nativeDownloadInFlight, store.nativeDownloadProgressSupported, + store.nativeManualDownloadOptions, store.nativeManualUpdateAvailable, store.nativeUpdateReady, store.updateInfo.native.downloadSize, diff --git a/fluxer_desktop/src/main/Updater.test.mjs b/fluxer_desktop/src/main/Updater.test.mjs index 552756dd1..810653523 100644 --- a/fluxer_desktop/src/main/Updater.test.mjs +++ b/fluxer_desktop/src/main/Updater.test.mjs @@ -547,6 +547,38 @@ describe('Updater Windows apply failures', () => { assert.equal(updater.applyState.attempt.version, PUBLISHED_VERSION); }); + test('keeps offering the installer when no newer release than the failed one is out', async () => { + const updater = loadWindowsUpdater({ + installedVersion: CURRENT_VERSION, + remoteUpdate: {Version: PUBLISHED_VERSION, Size: 100}, + applyAttempt: {version: PUBLISHED_VERSION, attemptedAt: 0}, + }); + + await updater.check(); + + assert.deepEqual(types(updater.events), ['checking', 'error', 'available']); + assert.equal(updater.events[2].downloadStarted, false); + assert.equal(updater.applyState.cleared, 0); + }); + + test('retries the in-app update when a newer release than the failed one is out', async () => { + const newerVersion = '2026.905.101010'; + const updater = loadWindowsUpdater({ + installedVersion: CURRENT_VERSION, + pendingRestart: {Version: PUBLISHED_VERSION, Size: 100}, + remoteUpdate: {Version: newerVersion, Size: 200}, + applyAttempt: {version: PUBLISHED_VERSION, attemptedAt: 0}, + }); + + await updater.check(); + + assert.equal(updater.applyState.cleared, 1); + assert.equal(updater.applyState.attempt, null); + assert.deepEqual(types(updater.events), ['checking', 'available']); + assert.equal(updater.events[1].version, newerVersion); + assert.equal(updater.events[1].downloadUrl, undefined); + }); + test('resumes normal updates once the installed version catches up', async () => { const updater = loadWindowsUpdater({ installedVersion: PUBLISHED_VERSION, diff --git a/fluxer_desktop/src/main/Updater.ts b/fluxer_desktop/src/main/Updater.ts index 42948f6d5..4ef9d972a 100644 --- a/fluxer_desktop/src/main/Updater.ts +++ b/fluxer_desktop/src/main/Updater.ts @@ -218,12 +218,27 @@ async function checkVelopackForUpdates( send(getMainWindow(), {type: 'checking', context}); const updateManager = createVelopackUpdateManager(); const failedApply = resolveFailedVelopackApply(updateManager); - if (failedApply) { + let update: Awaited>; + try { + update = await updateManager.checkForUpdatesAsync(); + } catch (error) { + if (!failedApply) throw error; await sendVelopackApplyFailure(context, getMainWindow, failedApply); return; } - const pendingUpdate = updateManager.getUpdatePendingRestart(); - const update = await updateManager.checkForUpdatesAsync(); + if (failedApply) { + const updateVersion = update ? getVelopackUpdateVersion(update) : null; + if (!updateVersion || compareVersions(updateVersion, failedApply.version) <= 0) { + await sendVelopackApplyFailure(context, getMainWindow, failedApply); + return; + } + log.info('A release newer than the update that failed to apply is out, retrying the in-app update', { + failedVersion: failedApply.version, + updateVersion, + }); + clearVelopackApplyAttempt(); + } + const pendingUpdate = failedApply ? null : updateManager.getUpdatePendingRestart(); if (!update) { if (pendingUpdate) { pendingVelopackUpdate = pendingUpdate;