fix(desktop): update pre-probe source checkouts from main over git
A source checkout without hermes_cli/source_check.py predates release
channels, so the only line it can be on is git. The desktop treated the
missing probe as unsupported and parked the user on a manual
`hermes update --help` card ("This checkout predates desktop
source-channel checks"), so an older non-bundled install could never
update itself from the app.
Report such a checkout as tracking main with an update available and let
apply take the normal git handoff. That update brings in the probe, so
later checks resolve normally. A probe that exists but fails still throws.
This commit is contained in:
@@ -7,7 +7,7 @@ import { expect, it, vi } from 'vitest'
|
||||
import { type CheckoutStrategyDeps, createCheckoutStrategy } from './checkout'
|
||||
import { readSourceUpdate, type SourceUpdate } from './checkout-source'
|
||||
|
||||
it('offers manual recovery only for a missing source probe, never for a broken probe', async (): Promise<void> => {
|
||||
it('moves a checkout without a source probe to main, but surfaces a broken probe', async (): Promise<void> => {
|
||||
const root: string = fs.mkdtempSync(path.join(os.tmpdir(), 'legacy-channel-'))
|
||||
const home: string = path.join(root, 'profile')
|
||||
const modulePath: string = path.join(root, 'hermes_cli', 'source_check.py')
|
||||
@@ -31,7 +31,9 @@ it('offers manual recovery only for a missing source probe, never for a broken p
|
||||
defaultUpdateBranch: 'main',
|
||||
updateHandoffDwellMs: 0,
|
||||
resolveUpdateRoot: (): string => root,
|
||||
resolveUpdaterBinary: vi.fn((): string => 'frozen-updater'),
|
||||
// No staged updater and no repo hand-off script: apply ends on the manual
|
||||
// command card, which exposes the target without spawning anything.
|
||||
resolveUpdaterBinary: vi.fn((): null => null),
|
||||
remoteGatewayActive: (): boolean => false,
|
||||
emitUpdateProgress: vi.fn(),
|
||||
rememberLog: vi.fn(),
|
||||
@@ -54,14 +56,8 @@ it('offers manual recovery only for a missing source probe, never for a broken p
|
||||
fs.rmSync(modulePath)
|
||||
}
|
||||
|
||||
expect(await strategy.check()).toMatchObject({ supported: false, reason: 'source-probe-unavailable' })
|
||||
const result: Awaited<ReturnType<typeof strategy.apply>> = await strategy.apply()
|
||||
expect(result).toMatchObject({ manual: true, command: 'hermes update --help' })
|
||||
expect(result.message).toContain('branch or channel')
|
||||
expect(result.command).not.toContain('--branch')
|
||||
expect(deps.stopBackendsForUpdate).not.toHaveBeenCalled()
|
||||
expect(deps.resolveUpdaterBinary).not.toHaveBeenCalled()
|
||||
expect(deps.quit).not.toHaveBeenCalled()
|
||||
expect(await strategy.check()).toMatchObject({ supported: true, updateAvailable: true, branch: 'main' })
|
||||
expect(await strategy.apply()).toMatchObject({ ok: true, manual: true, command: 'hermes update' })
|
||||
}
|
||||
|
||||
fs.writeFileSync(modulePath, 'def main():\n raise RuntimeError("invalid channel configuration")\n')
|
||||
|
||||
@@ -25,9 +25,6 @@ export interface SourceUpdateProbe {
|
||||
|
||||
const execute: typeof execFile.__promisify__ = promisify(execFile)
|
||||
|
||||
export const SOURCE_PROBE_RECOVERY: string =
|
||||
'This checkout predates desktop source-channel checks. Run `hermes update --help` in this installation, then choose the intended branch or channel explicitly before updating.'
|
||||
|
||||
export function sourceUpdateEnvironment(updateRoot: string, hermesHome: string): NodeJS.ProcessEnv {
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
...process.env,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
wrapHandoffForDetachedConsole
|
||||
} from '../updater-process'
|
||||
|
||||
import { SOURCE_PROBE_RECOVERY, type SourceUpdate, sourceUpdateEnvironment } from './checkout-source'
|
||||
import { type SourceUpdate, sourceUpdateEnvironment } from './checkout-source'
|
||||
|
||||
import type { UpdaterApplyResultWire, UpdaterMechanism, UpdaterStatusWire, UpdaterStrategy } from './index'
|
||||
|
||||
@@ -77,10 +77,13 @@ export function createCheckoutStrategy(deps: CheckoutStrategyDeps): UpdaterStrat
|
||||
async function check(opts: { force?: boolean } = {}): Promise<UpdaterStatusWire> {
|
||||
const root: string = deps.resolveUpdateRoot()
|
||||
|
||||
// A checkout without the source probe predates source channels, so it can
|
||||
// only be on the git line: move it to main. Its update pulls the probe in.
|
||||
const status: UpdaterStatusWire = (await deps.readSourceUpdate(root, opts)) ?? {
|
||||
supported: false,
|
||||
reason: 'source-probe-unavailable',
|
||||
message: SOURCE_PROBE_RECOVERY,
|
||||
supported: true,
|
||||
updateAvailable: true,
|
||||
behind: null,
|
||||
branch: deps.defaultUpdateBranch,
|
||||
hermesRoot: root
|
||||
}
|
||||
|
||||
@@ -101,16 +104,6 @@ export function createCheckoutStrategy(deps: CheckoutStrategyDeps): UpdaterStrat
|
||||
async function applyBody(): Promise<UpdaterApplyResultWire> {
|
||||
const status: UpdaterStatusWire = await check({ force: true })
|
||||
|
||||
if (status.reason === 'source-probe-unavailable') {
|
||||
return {
|
||||
ok: true,
|
||||
manual: true,
|
||||
command: 'hermes update --help',
|
||||
message: status.message,
|
||||
hermesRoot: status.hermesRoot
|
||||
}
|
||||
}
|
||||
|
||||
if (!status.supported || status.error) {
|
||||
return { ok: false, error: status.error ?? status.reason, message: status.message }
|
||||
}
|
||||
|
||||
@@ -106,9 +106,9 @@ replace a selected release channel with its default branch.
|
||||
|
||||
For branch-tracking source installs, the desktop keeps the current named branch
|
||||
unless an explicit desktop branch override exists. A detached checkout uses the
|
||||
default branch. Older checkouts without source-channel probing show manual
|
||||
recovery instructions instead of guessing a target: inspect `hermes update --help`
|
||||
in that installation and choose the intended branch or channel before updating.
|
||||
default branch. Older checkouts without source-channel probing predate release
|
||||
channels, so the desktop updates them from `main` over git; that update brings in
|
||||
the probing.
|
||||
|
||||
Packaged desktop feed channels derive from their build tag and package owner.
|
||||
Changing a source channel is not an MSIX or Store channel switch. Canary builds
|
||||
|
||||
Reference in New Issue
Block a user