9442a718da
The honesty half (no fabricated counts) leaves shallow installs permanently count-less. The compare API knows the full graph regardless of local clone depth: GET /repos/<o>/<r>/compare/<current>...<target> returns ahead_by — exactly the behind count the shallow boundary lost. - hermes_cli/banner.py: _github_compare_behind() (bounded, unauthenticated, best-effort); wired into _check_via_rev and the shallow branch of _check_via_local_git. ahead_by==0 with differing tips = local-ahead => 0. - hermes_cli/update_cmd.py: hermes update --check shallow path prints the exact count when recoverable, presence-only wording otherwise. - apps/desktop/electron/update-count.ts: compareApiUrl() + parseCompareBehindCount() pure helpers; main.ts fetches the count when resolveBehindCount() returns null, and the SSH-official passive path stops fabricating behind:1 (uses compare API + updateAvailable flag). - apps/desktop/src/lib/version-status.ts: updateAvailable now applies to the client target too, so a shallow desktop install shows '(update)' instead of nothing (or the old frozen '(+1)'). Fixes #84591; CLI siblings of #78253 / #53479 behavior. E2E: live compare API returned 61/62 for real 61/62-commit gaps and 0 for the reversed (local-ahead) pair; real shallow-clone fixture (depth-1 clone + depth-1 fetch, merge-base broken) recovers the exact count with the API and falls back to the honest sentinel offline.
98 lines
3.8 KiB
TypeScript
98 lines
3.8 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { en } from '@/i18n/en'
|
|
|
|
import { resolveVersionStatus } from './version-status'
|
|
|
|
const copy = en.shell.statusbar
|
|
|
|
const client = (over: Partial<Parameters<typeof resolveVersionStatus>[0]> = {}) =>
|
|
resolveVersionStatus({ applying: false, copy, remote: false, restarting: false, target: 'client', ...over })
|
|
|
|
const backend = (over: Partial<Parameters<typeof resolveVersionStatus>[0]> = {}) =>
|
|
resolveVersionStatus({ applying: false, copy, remote: true, restarting: false, target: 'backend', ...over })
|
|
|
|
describe('resolveVersionStatus', () => {
|
|
it('labels a current local client with its version and sha detail', () => {
|
|
const status = client({ sha: 'abc1234', version: '0.4.2' })
|
|
|
|
expect(status.label).toBe('v0.4.2')
|
|
expect(status.detail).toBe('abc1234')
|
|
expect(status.hasUpdate).toBe(false)
|
|
expect(status.unknown).toBe(false)
|
|
})
|
|
|
|
it('appends the commit diff when the client is behind', () => {
|
|
const status = client({ behind: 12, branch: 'main', version: '0.4.2' })
|
|
|
|
expect(status.label).toBe('v0.4.2 (+12)')
|
|
expect(status.hasUpdate).toBe(true)
|
|
expect(status.tooltip).toContain('12 commits behind main')
|
|
})
|
|
|
|
// FAIL-BEFORE (#84591 class): a shallow install reports behind:null +
|
|
// updateAvailable. The client target ignored updateAvailable entirely, so
|
|
// the statusbar showed no update at all — and further back, the fabricated
|
|
// behind:1 rendered a frozen "(+1)" while the real distance grew to 61.
|
|
it('shows a count-free update hint when the client count is unknown', () => {
|
|
const status = client({ behind: 0, updateAvailable: true, version: '0.4.2' })
|
|
|
|
expect(status.label).toBe(`v0.4.2 (${copy.update})`)
|
|
expect(status.label).not.toContain('+1')
|
|
expect(status.hasUpdate).toBe(true)
|
|
})
|
|
|
|
it('names the client as one of two versions in remote mode', () => {
|
|
expect(client({ remote: true, version: '0.4.2' }).label).toBe('client v0.4.2')
|
|
})
|
|
|
|
it('falls back to the sha, then to unknown, when there is no version', () => {
|
|
expect(client({ sha: 'abc1234' }).label).toBe('abc1234')
|
|
expect(client({ sha: 'abc1234' }).unknown).toBe(false)
|
|
expect(client().label).toBe(copy.unknown)
|
|
expect(client().unknown).toBe(true)
|
|
})
|
|
|
|
it('drops the diff and the sha detail while an apply is in flight', () => {
|
|
const applying = client({ applying: true, behind: 3, sha: 'abc1234', version: '0.4.2' })
|
|
|
|
expect(applying.label).toBe('v0.4.2 · update')
|
|
expect(applying.detail).toBeUndefined()
|
|
expect(applying.hasUpdate).toBe(false)
|
|
|
|
expect(client({ applying: true, restarting: true, version: '0.4.2' }).label).toBe('v0.4.2 · restart')
|
|
})
|
|
|
|
it('leads the tooltip with the apply message while applying', () => {
|
|
expect(client({ applyMessage: 'Pulling…', applying: true, version: '0.4.2' }).tooltip).toBe(
|
|
'Pulling… · Hermes Desktop v0.4.2'
|
|
)
|
|
expect(client({ applying: true, version: '0.4.2' }).tooltip).toBe(
|
|
`${copy.updateInProgress} · Hermes Desktop v0.4.2`
|
|
)
|
|
})
|
|
|
|
it('labels the backend target distinctly and never claims a client sha', () => {
|
|
const status = backend({ sha: 'abc1234', version: '0.4.2' })
|
|
|
|
expect(status.label).toBe('backend v0.4.2')
|
|
expect(status.detail).toBeUndefined()
|
|
expect(status.tooltip).toBe('Backend v0.4.2')
|
|
})
|
|
|
|
it('falls back to (update) for a backend that cannot count commits', () => {
|
|
const status = backend({ updateAvailable: true, version: '0.4.2' })
|
|
|
|
expect(status.label).toBe('backend v0.4.2 (update)')
|
|
expect(status.hasUpdate).toBe(true)
|
|
})
|
|
|
|
it('prefers the exact commit diff over the generic (update) hint', () => {
|
|
expect(backend({ behind: 4, updateAvailable: true, version: '0.4.2' }).label).toBe('backend v0.4.2 (+4)')
|
|
})
|
|
|
|
it('hides a backend row that has no version at all', () => {
|
|
expect(backend().unknown).toBe(true)
|
|
})
|
|
})
|