fix(desktop): report a failed backend update check instead of "up to date"
Salvaged from #119803 by Overview3833 (rebased onto current main; the diff itself applies unchanged). `mapBackendCheck` folded the backend's `behind: null` into `behind: 0` and returned a status without `error`. But `null` is the endpoint's "the check could not run" answer — GitHub unreachable, rate limited, offline — and it carries the explanation in `message`. The remote overlay therefore fell through to the all-set copy ("the backend is on the latest version") whenever the check failed, and the message the backend sent was never shown. The local check path already reports `error: 'check-failed'` in this situation; only the backend mapping dropped it. Map a null from a supported (git) backend to the same failure state, so the overlay's `status.error` branch shows the backend's message with its retry affordance (and the "update available" toast stays suppressed, since we don't know the real distance). A check that ran and found no gap still reports "latest", and backends that cannot self-update keep taking the unsupported branch. Fixes #119801
This commit is contained in:
committed by
brooklyn!
parent
89cc403b23
commit
fa65609351
61
apps/desktop/src/store/updates-backend-check.test.ts
Normal file
61
apps/desktop/src/store/updates-backend-check.test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { BackendUpdateCheckResponse } from '@/types/hermes'
|
||||
|
||||
import { mapBackendCheck } from './updates'
|
||||
|
||||
const response = (over: Partial<BackendUpdateCheckResponse> = {}): BackendUpdateCheckResponse => ({
|
||||
install_method: 'git',
|
||||
current_version: '9.9.9',
|
||||
behind: 0,
|
||||
update_available: false,
|
||||
can_apply: true,
|
||||
update_command: null,
|
||||
message: null,
|
||||
...over
|
||||
})
|
||||
|
||||
describe('mapBackendCheck', () => {
|
||||
it('surfaces a failed check instead of claiming the backend is up to date', () => {
|
||||
// The endpoint answers `behind: null` + a message when it could not run the check
|
||||
// (GitHub unreachable, rate limited, offline). Folding that to 0 reported "you're on
|
||||
// the latest version" for a check that never happened.
|
||||
const status = mapBackendCheck(
|
||||
response({ behind: null, message: "Couldn't reach the update source — try again later." })
|
||||
)
|
||||
|
||||
expect(status.error).toBe('check-failed')
|
||||
expect(status.updateAvailable).not.toBe(true)
|
||||
expect(status.message).toContain("Couldn't reach the update source")
|
||||
expect(status.targetSha).toBeUndefined()
|
||||
})
|
||||
|
||||
it('still reports an up-to-date backend when the check ran and found no gap', () => {
|
||||
const status = mapBackendCheck(response({ behind: 0, message: "You're on the latest version." }))
|
||||
|
||||
expect(status.error).toBeUndefined()
|
||||
expect(status.behind).toBe(0)
|
||||
expect(status.updateAvailable).not.toBe(true)
|
||||
})
|
||||
|
||||
it('keeps a real gap intact', () => {
|
||||
const status = mapBackendCheck(response({ behind: 3, update_available: true }))
|
||||
|
||||
expect(status.error).toBeUndefined()
|
||||
expect(status.behind).toBe(3)
|
||||
expect(status.updateAvailable).toBe(true)
|
||||
expect(status.targetSha).toBe('backend:9.9.9')
|
||||
})
|
||||
|
||||
it('leaves a backend that cannot self-update to the unsupported branch', () => {
|
||||
// pip/nix and managed runtimes also answer `behind: null`, but `can_apply: false` renders
|
||||
// the "not available" copy first — those must not be turned into failures.
|
||||
const status = mapBackendCheck(
|
||||
response({ can_apply: false, behind: null, message: 'pip install -U hermes-agent' })
|
||||
)
|
||||
|
||||
expect(status.supported).toBe(false)
|
||||
expect(status.error).toBeUndefined()
|
||||
expect(status.message).toBe('pip install -U hermes-agent')
|
||||
})
|
||||
})
|
||||
@@ -488,11 +488,23 @@ function isRemoteMode(): boolean {
|
||||
return $connection.get()?.mode === 'remote'
|
||||
}
|
||||
|
||||
function mapBackendCheck(res: BackendUpdateCheckResponse): DesktopUpdateStatus {
|
||||
export function mapBackendCheck(res: BackendUpdateCheckResponse): DesktopUpdateStatus {
|
||||
const behind = res.behind ?? 0
|
||||
|
||||
// `behind: null` from a supported (git) backend is the endpoint's "the check
|
||||
// could not run" answer (GitHub unreachable, rate limited, offline) and
|
||||
// carries the explanation in `message`. Folding it to 0 made the overlay
|
||||
// report "the backend is on the latest version" whenever the check failed,
|
||||
// and hid that message. Surface the failure state the local check path
|
||||
// already uses so the overlay shows the reason and a retry; only a check
|
||||
// that actually ran may claim there is nothing to update. Backends that
|
||||
// cannot self-update also answer `behind: null`, but `can_apply: false`
|
||||
// renders the unsupported copy first — those must not become failures.
|
||||
const checkFailed = res.can_apply && res.behind === null
|
||||
|
||||
return {
|
||||
supported: res.can_apply,
|
||||
error: checkFailed ? 'check-failed' : undefined,
|
||||
message: res.message ?? undefined,
|
||||
updateAvailable: res.update_available,
|
||||
behind: behind > 0 ? behind : 0,
|
||||
|
||||
Reference in New Issue
Block a user