feat: add version update flow

This commit is contained in:
fawney19
2026-05-13 22:21:07 +08:00
parent 8b813f645f
commit acd44328d6
13 changed files with 451 additions and 160 deletions

View File

@@ -0,0 +1,45 @@
import { describe, expect, it } from 'vitest'
import type { CheckUpdateResponse } from '@/api/admin'
import {
buildUpdateErrorStatus,
describeUpdateStatus,
} from '../updateStatus'
function updateStatus(overrides: Partial<CheckUpdateResponse> = {}): CheckUpdateResponse {
return {
current_version: '0.7.0-rc27',
latest_version: null,
has_update: false,
release_url: null,
release_notes: null,
published_at: null,
error: null,
...overrides,
}
}
describe('updateStatus', () => {
it('describes loading and latest states', () => {
expect(describeUpdateStatus(null)).toBe('检查中')
expect(describeUpdateStatus(updateStatus())).toBe('已是最新')
})
it('prioritizes update availability over latest-version text', () => {
expect(describeUpdateStatus(updateStatus({
latest_version: 'v0.7.0-rc28',
has_update: true,
release_url: 'https://github.com/fawney19/Aether/releases/tag/v0.7.0-rc28',
}))).toBe('有新版本')
})
it('preserves the current version when building an error state', () => {
const status = buildUpdateErrorStatus(
updateStatus({ current_version: '0.7.0-rc28' }),
new Error('network down')
)
expect(status.current_version).toBe('0.7.0-rc28')
expect(status.has_update).toBe(false)
expect(status.error).toBe('network down')
})
})

View File

@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest'
import { formatDisplayVersion } from '../version'
describe('formatDisplayVersion', () => {
it('adds one v prefix to unprefixed versions', () => {
expect(formatDisplayVersion('0.7.0-rc28')).toBe('v0.7.0-rc28')
})
it('keeps existing v prefixes intact', () => {
expect(formatDisplayVersion('v0.7.0-rc28')).toBe('v0.7.0-rc28')
})
it('preserves git describe development suffixes', () => {
expect(formatDisplayVersion('0.7.0-rc28-11-g63149fe2-dirty')).toBe(
'v0.7.0-rc28-11-g63149fe2-dirty'
)
})
})

View File

@@ -0,0 +1,23 @@
import type { CheckUpdateResponse } from '@/api/admin'
export function describeUpdateStatus(status: CheckUpdateResponse | null): string {
if (!status) return '检查中'
if (status.has_update) return '有新版本'
if (status.error) return '检查失败'
return '已是最新'
}
export function buildUpdateErrorStatus(
previousStatus: CheckUpdateResponse | null,
error: unknown
): CheckUpdateResponse {
return {
current_version: previousStatus?.current_version || '',
latest_version: null,
has_update: false,
release_url: null,
release_notes: null,
published_at: null,
error: error instanceof Error ? error.message : '检查更新失败'
}
}

View File

@@ -0,0 +1,5 @@
export function formatDisplayVersion(version: string): string {
const normalized = version.trim()
if (!normalized) return ''
return normalized.startsWith('v') || normalized.startsWith('V') ? normalized : `v${normalized}`
}