fix(desktop): allow prerelease runtime compatibility checks

This commit is contained in:
digua committed 2026-06-21 23:34:22 +08:00
1 parent 2bfae1db93
commit 66c8eeeef4
3 files changed
+137 -5

No files matched your search

@@ -81,6 +81,57 @@ test('current runtime satisfying minRuntimeVersion is compatible', () => {
})
})
test('prerelease current runtime satisfying stable minRuntimeVersion is compatible', () => {
const userDataDir = makeTempDir()
writeMeta(userDataDir, {
formatVersion: 1,
minRuntimeVersion: '0.25.1',
dataCompatibilityVersion: 1,
reasons: ['segment-schema'],
updatedBy: { runtime: 'cli', module: 'chat-db-migration', version: '0.25.1' },
updatedAt: 1780830000,
})
assert.doesNotThrow(() => {
assertDataDirCompatible(makePathProvider(userDataDir), { version: '0.26.4-beta.1', kind: 'desktop' })
})
})
test('prerelease current runtime is compared by its stable core version', () => {
const equalDir = makeTempDir()
writeMeta(equalDir, {
formatVersion: 1,
minRuntimeVersion: '0.26.4',
dataCompatibilityVersion: 1,
reasons: ['segment-schema'],
updatedBy: { runtime: 'cli', module: 'chat-db-migration', version: '0.26.4' },
updatedAt: 1780830000,
})
assert.doesNotThrow(() => {
assertDataDirCompatible(makePathProvider(equalDir), { version: '0.26.4-beta.1', kind: 'desktop' })
})
const newerDir = makeTempDir()
writeMeta(newerDir, {
formatVersion: 1,
minRuntimeVersion: '0.26.5',
dataCompatibilityVersion: 1,
reasons: ['segment-schema'],
updatedBy: { runtime: 'cli', module: 'chat-db-migration', version: '0.26.5' },
updatedAt: 1780830000,
})
assert.throws(
() => assertDataDirCompatible(makePathProvider(newerDir), { version: '0.26.4-beta.1', kind: 'desktop' }),
(error) =>
error instanceof DataDirCompatibilityError &&
error.code === 'DATA_DIR_REQUIRES_NEWER_RUNTIME' &&
error.currentVersion === '0.26.4-beta.1' &&
error.minRuntimeVersion === '0.26.5'
)
})
test('current runtime below minRuntimeVersion is blocked', () => {
const userDataDir = makeTempDir()
writeMeta(userDataDir, {
@@ -220,3 +271,23 @@ test('raising minRuntimeVersion writes atomically and never lowers existing requ
assert.equal(meta?.updatedAt, 1780830001)
assert.equal(fs.existsSync(path.join(userDataDir, '.chatlab-meta.json')), true)
})
test('raising minRuntimeVersion records prerelease runtime by stable core version', () => {
const userDataDir = makeTempDir()
const meta = raiseDataDirMinRuntimeVersion(makePathProvider(userDataDir), {
minRuntimeVersion: '0.25.1',
dataCompatibilityVersion: 1,
reason: 'segment-schema',
runtime: { version: '0.26.4-beta.1', kind: 'desktop' },
module: 'chat-db-migration',
now: () => 1780830000,
})
assert.deepEqual(meta.updatedBy, { runtime: 'desktop', module: 'chat-db-migration', version: '0.26.4' })
assert.deepEqual(readDataDirCompatibilityMeta(userDataDir)?.updatedBy, {
runtime: 'desktop',
module: 'chat-db-migration',
version: '0.26.4',
})
})
+22 -5
View File
@@ -90,10 +90,11 @@ export function assertDataDirCompatible(
const meta = readDataDirCompatibilityMeta(userDataDir)
if (!meta) return
if (!isStableSemver(runtime.version)) {
const runtimeStableVersion = normalizeRuntimeStableVersion(runtime.version)
if (!runtimeStableVersion) {
throw new DataDirCompatibilityError(
'DATA_DIR_REQUIRES_NEWER_RUNTIME',
`ChatLab data directory compatibility check requires a stable runtime version; current version is ${runtime.version}.`,
`ChatLab data directory compatibility check requires a valid runtime semver; current version is ${runtime.version}.`,
{
userDataDir,
metaPath: getMetaPath(userDataDir),
@@ -103,7 +104,7 @@ export function assertDataDirCompatible(
)
}
if (compareStableSemver(runtime.version, meta.minRuntimeVersion) < 0) {
if (compareStableSemver(runtimeStableVersion, meta.minRuntimeVersion) < 0) {
const env = options.env ?? process.env
if (env.CHATLAB_ALLOW_INCOMPATIBLE_DATA_DIR === '1') {
const warn = options.warn ?? console.warn
@@ -138,7 +139,7 @@ export function raiseDataDirMinRuntimeVersion(
const metaPath = getMetaPath(userDataDir)
assertStableVersion(input.minRuntimeVersion, userDataDir, metaPath, 'Invalid minRuntimeVersion.')
assertStableVersion(input.runtime.version, userDataDir, metaPath, 'Invalid runtime version.')
const runtimeStableVersion = assertRuntimeComparableVersion(input.runtime.version, userDataDir, metaPath)
if (!isRuntimeKind(input.runtime.kind)) {
throw createInvalidMetaError(userDataDir, metaPath, 'Invalid runtime kind.')
}
@@ -166,7 +167,7 @@ export function raiseDataDirMinRuntimeVersion(
updatedBy: {
runtime: input.runtime.kind,
module: input.module,
version: input.runtime.version,
version: runtimeStableVersion,
},
updatedAt: now(),
}
@@ -253,6 +254,22 @@ function isStableSemver(version: unknown): version is string {
return typeof version === 'string' && /^\d+\.\d+\.\d+$/.test(version)
}
function assertRuntimeComparableVersion(version: string, userDataDir: string, metaPath: string): string {
const normalized = normalizeRuntimeStableVersion(version)
if (!normalized) {
throw createInvalidMetaError(userDataDir, metaPath, 'Invalid runtime version.')
}
return normalized
}
// 当前运行时允许使用 beta/rc 等 prerelease;数据目录门禁比较和 meta 写入只使用稳定 core 版本。
function normalizeRuntimeStableVersion(version: string): string | null {
const match = /^v?(\d+\.\d+\.\d+)(-[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?$/.exec(version.trim())
if (!match) return null
if (match[1] === '0.0.0' && match[2]) return null
return match[1]
}
function compareStableSemver(left: string, right: string): number {
const leftParts = left.split('.').map(Number)
const rightParts = right.split('.').map(Number)