fix(desktop): report the current commit in updater status

This commit is contained in:
Brooklyn Nicholson
2026-09-28 08:06:29 -05:00
committed by brooklyn!
parent be84a141f6
commit 7dbbb0f4a6
2 changed files with 130 additions and 1 deletions

View File

@@ -0,0 +1,101 @@
import * as fs from 'node:fs'
import * as os from 'node:os'
import * as path from 'node:path'
import { expect, it, vi } from 'vitest'
import { type CheckoutStrategyDeps, createCheckoutStrategy, readStampedCommit } from './checkout'
import type { SourceUpdate } from './checkout-source'
const STAMPED: string = 'a'.repeat(40)
const PROBED: string = 'b'.repeat(40)
function writeStamp(root: string, commit: string): void {
fs.writeFileSync(path.join(root, 'install-stamp.json'), JSON.stringify({ schemaVersion: 2, commit, source: 'git' }))
}
function deps(root: string, status: SourceUpdate | null, isWindows: boolean): CheckoutStrategyDeps {
return {
readSourceUpdate: vi.fn(async (): Promise<SourceUpdate | null> => status),
hermesHome: 'home',
isWindows,
isMac: process.platform === 'darwin',
defaultUpdateBranch: 'main',
updateHandoffDwellMs: 0,
resolveUpdateRoot: (): string => root,
resolveUpdaterBinary: vi.fn((): null => null),
remoteGatewayActive: (): boolean => false,
emitUpdateProgress: vi.fn(),
rememberLog: vi.fn(),
startHermes: vi.fn(async (): Promise<void> => {}),
stopBackendsForUpdate: vi.fn(async (): Promise<void> => {}),
repairMacUpdaterHelper: vi.fn(),
preflightStateDb: vi.fn(),
runningAppBundle: (): null => null,
markQuittingForHandoff: vi.fn(),
quit: vi.fn()
}
}
it.each([
['windows-handoff', true],
['posix-handoff', false]
])(
'%s reports the checkout commit even when the source probe never supplied one',
async (_mechanism: string, isWindows: boolean): Promise<void> => {
const root: string = fs.mkdtempSync(path.join(os.tmpdir(), 'checkout-sha-'))
try {
// A probe-less checkout (the manual path: no hermes_cli/source_check.py)
// previously reported no currentSha at all — the commit showed nowhere.
writeStamp(root, STAMPED)
const strategy: ReturnType<typeof createCheckoutStrategy> = createCheckoutStrategy(deps(root, null, isWindows))
expect(await strategy.check()).toMatchObject({
supported: true,
mechanism: isWindows ? 'windows-handoff' : 'posix-handoff',
currentSha: STAMPED
})
} finally {
fs.rmSync(root, { recursive: true, force: true })
}
}
)
it('fills currentSha from the install stamp when the probe omitted it, but never overrides the probe', async (): Promise<void> => {
const root: string = fs.mkdtempSync(path.join(os.tmpdir(), 'checkout-sha-'))
try {
writeStamp(root, STAMPED)
// A probe status that carries no currentSha (stale cache shapes, error
// statuses) still leaves the badge with a commit to show.
const bare: SourceUpdate = { supported: true, error: 'fetch-failed', behind: null }
expect(await createCheckoutStrategy(deps(root, bare, false)).check()).toMatchObject({ currentSha: STAMPED })
// The probe's own answer — including its currentSha — always wins.
const probed: SourceUpdate = { supported: true, currentSha: PROBED, behind: 0, updateAvailable: false }
expect(await createCheckoutStrategy(deps(root, probed, false)).check()).toMatchObject({ currentSha: PROBED })
} finally {
fs.rmSync(root, { recursive: true, force: true })
}
})
it('readStampedCommit returns the stamped commit, or null for absent and malformed stamps', (): void => {
const root: string = fs.mkdtempSync(path.join(os.tmpdir(), 'checkout-stamp-'))
try {
expect(readStampedCommit(root)).toBeNull()
writeStamp(root, STAMPED)
expect(readStampedCommit(root)).toBe(STAMPED)
fs.writeFileSync(path.join(root, 'install-stamp.json'), JSON.stringify({ commit: null, source: 'git' }))
expect(readStampedCommit(root)).toBeNull()
fs.writeFileSync(path.join(root, 'install-stamp.json'), '{not json')
expect(readStampedCommit(root)).toBeNull()
} finally {
fs.rmSync(root, { recursive: true, force: true })
}
})

View File

@@ -1,6 +1,6 @@
// Checkout update policy and handoff execution. The shell supplies process and UI dependencies.
import { existsSync } from 'node:fs'
import { existsSync, readFileSync } from 'node:fs'
import * as path from 'node:path'
import { updateHandoffConflict, writeUpdateMarker } from '../update-marker'
@@ -66,6 +66,22 @@ export function buildManualUpdateCommand(currentBranch: string | null | undefine
: 'hermes update'
}
/**
* The commit this checkout was installed at, from the install stamp the
* updater already trusts (written by the CLI's completion tail next to the
* checkout it attests). Read-only display data for `currentSha`; never a
* git spawn and never an update input. Null when absent or malformed.
*/
export function readStampedCommit(root: string): string | null {
try {
const stamp = JSON.parse(readFileSync(path.join(root, 'install-stamp.json'), 'utf8')) as { commit?: unknown }
return typeof stamp.commit === 'string' && stamp.commit ? stamp.commit : null
} catch {
return null
}
}
/**
* The checkout strategy: windows-handoff on win32, posix-handoff elsewhere.
* The bodies are the production update flow; the mechanism stamp rides on
@@ -89,6 +105,18 @@ export function createCheckoutStrategy(deps: CheckoutStrategyDeps): UpdaterStrat
status.mechanism = mechanism
// Display data only (#122727): the statusbar and command palette read
// currentSha, but a probe-less checkout never supplied it. The install
// stamp names the checkout's commit without a git spawn; never let it
// override the probe and never let it influence the update decision.
if (!status.currentSha) {
const stamped: string | null = readStampedCommit(root)
if (stamped) {
status.currentSha = stamped
}
}
return status
}