mirror of
https://github.com/langgenius/dify.git
synced 2026-09-24 23:22:26 +08:00
style: format with vp fmt (#38803)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
autofix-ci[bot]
parent
fde08d24fe
commit
a84c2d36a3
@@ -62,7 +62,9 @@ describe('evaluateCompat', () => {
|
||||
})
|
||||
|
||||
it('strips suffixes on the range bounds too', () => {
|
||||
expect(evaluateCompat('1.6.5', { minDify: '1.6.0-alpha', maxDify: '1.7.0-rc' }).status).toBe('compatible')
|
||||
expect(evaluateCompat('1.6.5', { minDify: '1.6.0-alpha', maxDify: '1.7.0-rc' }).status).toBe(
|
||||
'compatible',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -43,18 +43,33 @@ export function evaluateCompat(
|
||||
|
||||
const server = tryParse(serverVersion)
|
||||
if (server === undefined)
|
||||
return { status: 'unknown', detail: `server version ${JSON.stringify(clamp(serverVersion))} is not valid semver` }
|
||||
return {
|
||||
status: 'unknown',
|
||||
detail: `server version ${JSON.stringify(clamp(serverVersion))} is not valid semver`,
|
||||
}
|
||||
|
||||
const min = tryParse(range.minDify)
|
||||
const max = tryParse(range.maxDify)
|
||||
if (min === undefined || max === undefined)
|
||||
return { status: 'unknown', detail: `compat range ${JSON.stringify(`>=${range.minDify} <=${range.maxDify}`)} is not valid semver` }
|
||||
return {
|
||||
status: 'unknown',
|
||||
detail: `compat range ${JSON.stringify(`>=${range.minDify} <=${range.maxDify}`)} is not valid semver`,
|
||||
}
|
||||
|
||||
if (compare(core(server), core(min)) < 0)
|
||||
return { status: 'too_old', detail: `server ${serverVersion} is older than the minimum ${range.minDify}` }
|
||||
return {
|
||||
status: 'too_old',
|
||||
detail: `server ${serverVersion} is older than the minimum ${range.minDify}`,
|
||||
}
|
||||
|
||||
if (compare(core(server), core(max)) > 0)
|
||||
return { status: 'too_new', detail: `server ${serverVersion} is newer than the tested maximum ${range.maxDify}` }
|
||||
return {
|
||||
status: 'too_new',
|
||||
detail: `server ${serverVersion} is newer than the tested maximum ${range.maxDify}`,
|
||||
}
|
||||
|
||||
return { status: 'compatible', detail: `server ${serverVersion} in [${range.minDify}, ${range.maxDify}]` }
|
||||
return {
|
||||
status: 'compatible',
|
||||
detail: `server ${serverVersion} in [${range.minDify}, ${range.maxDify}]`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ describe('enforceDifyVersion', () => {
|
||||
const store = fakeStore()
|
||||
const probe = vi.fn(async () => server('1.5.0'))
|
||||
|
||||
await expect(enforceDifyVersion(HOST, { store, probe })).rejects.toMatchObject({ code: ErrorCode.VersionSkew })
|
||||
await expect(enforceDifyVersion(HOST, { store, probe })).rejects.toMatchObject({
|
||||
code: ErrorCode.VersionSkew,
|
||||
})
|
||||
expect(store.marked).toHaveLength(0)
|
||||
})
|
||||
|
||||
@@ -60,9 +62,9 @@ describe('enforceDifyVersion', () => {
|
||||
const store = fakeStore(true)
|
||||
const probe = vi.fn(async () => server('1.5.0'))
|
||||
|
||||
await expect(enforceDifyVersion(HOST, { store, probe, forceFresh: true }))
|
||||
.rejects
|
||||
.toMatchObject({ code: ErrorCode.VersionSkew })
|
||||
await expect(
|
||||
enforceDifyVersion(HOST, { store, probe, forceFresh: true }),
|
||||
).rejects.toMatchObject({ code: ErrorCode.VersionSkew })
|
||||
expect(probe).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
|
||||
@@ -11,14 +11,19 @@ import { versionInfo } from './info'
|
||||
|
||||
export type ServerVersionProbe = (host: string) => Promise<ServerVersionResponse>
|
||||
|
||||
const UPGRADE_HINT
|
||||
= `upgrade the Dify server to >= ${difyCompat.minDify} `
|
||||
+ '(https://docs.dify.ai/en/getting-started/install-self-hosted)'
|
||||
const UPGRADE_HINT =
|
||||
`upgrade the Dify server to >= ${difyCompat.minDify} ` +
|
||||
'(https://docs.dify.ai/en/getting-started/install-self-hosted)'
|
||||
|
||||
// /_version is unauthenticated; same timeout/no-retry budget as the auto-nudge probe.
|
||||
function buildDefaultProbe(insecure: boolean): ServerVersionProbe {
|
||||
return async (host) => {
|
||||
const http = createHttpClient({ baseURL: openAPIBase(host), timeoutMs: META_PROBE_TIMEOUT_MS, retryAttempts: 0, insecure })
|
||||
const http = createHttpClient({
|
||||
baseURL: openAPIBase(host),
|
||||
timeoutMs: META_PROBE_TIMEOUT_MS,
|
||||
retryAttempts: 0,
|
||||
insecure,
|
||||
})
|
||||
return new MetaClient(http).serverVersion()
|
||||
}
|
||||
}
|
||||
@@ -44,16 +49,14 @@ export async function enforceDifyVersion(
|
||||
host: string,
|
||||
opts: EnforceOptions = {},
|
||||
): Promise<ServerVersionResponse | undefined> {
|
||||
const store = opts.store ?? await loadCompatStore()
|
||||
if (opts.forceFresh !== true && store.isFreshCompatible(host))
|
||||
return undefined
|
||||
const store = opts.store ?? (await loadCompatStore())
|
||||
if (opts.forceFresh !== true && store.isFreshCompatible(host)) return undefined
|
||||
|
||||
const probe = opts.probe ?? buildDefaultProbe(opts.insecure === true)
|
||||
let server: ServerVersionResponse
|
||||
try {
|
||||
server = await probe(host)
|
||||
}
|
||||
catch {
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ export function shortVersion(): string {
|
||||
|
||||
export function longVersion(): string {
|
||||
const { version, commit, buildDate, channel } = versionInfo
|
||||
return `difyctl ${version} (commit ${commit.slice(0, 7)}, built ${buildDate}, channel ${channel})\n`
|
||||
+ `compat: ${compatString()}`
|
||||
return (
|
||||
`difyctl ${version} (commit ${commit.slice(0, 7)}, built ${buildDate}, channel ${channel})\n` +
|
||||
`compat: ${compatString()}`
|
||||
)
|
||||
}
|
||||
|
||||
export function userAgent(): string {
|
||||
|
||||
@@ -23,14 +23,16 @@ function emitterSpy() {
|
||||
return { emit: (line: string) => lines.push(line), lines }
|
||||
}
|
||||
|
||||
function baseDeps(overrides: Partial<{
|
||||
store: NudgeStore
|
||||
probe: Probe
|
||||
emit: (line: string) => void
|
||||
isTty: boolean
|
||||
format: string
|
||||
clientVersion: string
|
||||
}> & { store: NudgeStore } & { probe: Probe } & { emit: (line: string) => void }) {
|
||||
function baseDeps(
|
||||
overrides: Partial<{
|
||||
store: NudgeStore
|
||||
probe: Probe
|
||||
emit: (line: string) => void
|
||||
isTty: boolean
|
||||
format: string
|
||||
clientVersion: string
|
||||
}> & { store: NudgeStore } & { probe: Probe } & { emit: (line: string) => void },
|
||||
) {
|
||||
return {
|
||||
isTty: true,
|
||||
format: '',
|
||||
@@ -52,10 +54,8 @@ describe('maybeNudgeCompat', () => {
|
||||
store = await loadNudgeStore({ store: getCache(CACHE_NUDGE), now: fixedNow })
|
||||
})
|
||||
afterEach(async () => {
|
||||
if (prevCacheDir === undefined)
|
||||
delete process.env[ENV_CACHE_DIR]
|
||||
else
|
||||
process.env[ENV_CACHE_DIR] = prevCacheDir
|
||||
if (prevCacheDir === undefined) delete process.env[ENV_CACHE_DIR]
|
||||
else process.env[ENV_CACHE_DIR] = prevCacheDir
|
||||
await rm(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
@@ -121,7 +121,9 @@ describe('maybeNudgeCompat', () => {
|
||||
})
|
||||
|
||||
it('does not warn when server version yields unknown verdict', async () => {
|
||||
const probe = vi.fn(async () => ({ version: '', edition: 'SELF_HOSTED' } as ServerVersionResponse))
|
||||
const probe = vi.fn(
|
||||
async () => ({ version: '', edition: 'SELF_HOSTED' }) as ServerVersionResponse,
|
||||
)
|
||||
const { emit, lines } = emitterSpy()
|
||||
|
||||
await maybeNudgeCompat(HOST, baseDeps({ store, probe, emit }))
|
||||
@@ -161,8 +163,12 @@ describe('maybeNudgeCompat', () => {
|
||||
|
||||
it('never throws even when every dependency explodes', async () => {
|
||||
const explodingStore: NudgeStore = {
|
||||
canWarn: () => { throw new Error('canWarn boom') },
|
||||
markWarned: async () => { throw new Error('markWarned boom') },
|
||||
canWarn: () => {
|
||||
throw new Error('canWarn boom')
|
||||
},
|
||||
markWarned: async () => {
|
||||
throw new Error('markWarned boom')
|
||||
},
|
||||
}
|
||||
const probe: Probe = async () => {
|
||||
throw new Error('probe boom')
|
||||
@@ -171,10 +177,15 @@ describe('maybeNudgeCompat', () => {
|
||||
throw new Error('emit boom')
|
||||
}
|
||||
|
||||
await expect(maybeNudgeCompat(HOST, baseDeps({
|
||||
store: explodingStore,
|
||||
probe,
|
||||
emit,
|
||||
}))).resolves.toBeUndefined()
|
||||
await expect(
|
||||
maybeNudgeCompat(
|
||||
HOST,
|
||||
baseDeps({
|
||||
store: explodingStore,
|
||||
probe,
|
||||
emit,
|
||||
}),
|
||||
),
|
||||
).resolves.toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
+10
-16
@@ -28,33 +28,27 @@ export type NudgeDeps = {
|
||||
// before any I/O so the happy path costs nothing in steady state.
|
||||
export async function maybeNudgeCompat(host: string, deps: NudgeDeps): Promise<void> {
|
||||
try {
|
||||
if (!deps.isTty)
|
||||
return
|
||||
if (SUPPRESSED_FORMATS.has(deps.format))
|
||||
return
|
||||
if (!deps.store.canWarn(host, deps.now?.()))
|
||||
return
|
||||
if (!deps.isTty) return
|
||||
if (SUPPRESSED_FORMATS.has(deps.format)) return
|
||||
if (!deps.store.canWarn(host, deps.now?.())) return
|
||||
|
||||
let server: ServerVersionResponse
|
||||
try {
|
||||
server = await deps.probe(host)
|
||||
}
|
||||
catch {
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
const verdict = evaluateCompat(server.version)
|
||||
// Only "too new" is a soft nudge here; "too old" is hard-failed up front by
|
||||
// enforceDifyVersion, so the command never reaches this path for it.
|
||||
if (verdict.status !== 'too_new')
|
||||
return
|
||||
if (verdict.status !== 'too_new') return
|
||||
|
||||
deps.emit(formatBanner(deps.clientVersion, server.version, deps.color === true))
|
||||
await deps.store.markWarned(host, deps.now?.()).catch(() => {
|
||||
// disk failure must not propagate; the user already saw the banner.
|
||||
})
|
||||
}
|
||||
catch {
|
||||
} catch {
|
||||
// belt-and-braces: any unexpected throw must not affect the business command
|
||||
}
|
||||
}
|
||||
@@ -62,9 +56,9 @@ export async function maybeNudgeCompat(host: string, deps: NudgeDeps): Promise<v
|
||||
function formatBanner(clientVersion: string, serverVersion: string, color: boolean): string {
|
||||
const { yellow } = colorScheme(color)
|
||||
const { minDify, maxDify } = difyCompat
|
||||
const line
|
||||
= `warning: difyctl ${clientVersion} may be incompatible with server `
|
||||
+ `${serverVersion} (tested: ${minDify}..${maxDify}). `
|
||||
+ 'Run `difyctl version` for details.'
|
||||
const line =
|
||||
`warning: difyctl ${clientVersion} may be incompatible with server ` +
|
||||
`${serverVersion} (tested: ${minDify}..${maxDify}). ` +
|
||||
'Run `difyctl version` for details.'
|
||||
return `${yellow(line)}\n`
|
||||
}
|
||||
|
||||
@@ -75,7 +75,9 @@ describe('runVersionProbe', () => {
|
||||
it('distinguishes loadActive disk failure from no-host configured in the detail', async () => {
|
||||
const errReport = await runVersionProbe({
|
||||
skipServer: false,
|
||||
loadActive: async () => { throw new Error('disk-explode') },
|
||||
loadActive: async () => {
|
||||
throw new Error('disk-explode')
|
||||
},
|
||||
probe: async () => ({ version: '1.6.4', edition: 'CLOUD' }),
|
||||
})
|
||||
expect(errReport.server.reachable).toBe(false)
|
||||
@@ -131,7 +133,9 @@ describe('runVersionProbe', () => {
|
||||
const report = await runVersionProbe({
|
||||
skipServer: false,
|
||||
loadActive: async () => active(),
|
||||
probe: async () => { throw new Error('timeout') },
|
||||
probe: async () => {
|
||||
throw new Error('timeout')
|
||||
},
|
||||
})
|
||||
|
||||
expect(report.server.reachable).toBe(false)
|
||||
@@ -162,7 +166,9 @@ describe('runVersionProbe', () => {
|
||||
try {
|
||||
process.env[ENV_CONFIG_DIR] = configDir
|
||||
const reg = Registry.empty('file')
|
||||
reg.upsert(url.host, 'test@dify.ai', { account: { id: 'acct-1', email: 'test@dify.ai', name: 'Test' } })
|
||||
reg.upsert(url.host, 'test@dify.ai', {
|
||||
account: { id: 'acct-1', email: 'test@dify.ai', name: 'Test' },
|
||||
})
|
||||
reg.setHost(url.host)
|
||||
reg.setAccount('test@dify.ai')
|
||||
reg.setScheme(url.host, url.protocol.replace(':', ''))
|
||||
@@ -176,12 +182,9 @@ describe('runVersionProbe', () => {
|
||||
expect(report.server.version).toBe('1.6.4')
|
||||
expect(report.server.edition).toBe('CLOUD')
|
||||
expect(report.compat.status).toBe('compatible')
|
||||
}
|
||||
finally {
|
||||
if (prevConfig === undefined)
|
||||
delete process.env[ENV_CONFIG_DIR]
|
||||
else
|
||||
process.env[ENV_CONFIG_DIR] = prevConfig
|
||||
} finally {
|
||||
if (prevConfig === undefined) delete process.env[ENV_CONFIG_DIR]
|
||||
else process.env[ENV_CONFIG_DIR] = prevConfig
|
||||
await mock.stop()
|
||||
await rm(configDir, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
@@ -53,7 +53,12 @@ const defaultLoadActive = async (): Promise<ActiveContext | undefined> => {
|
||||
|
||||
function buildDefaultProbe(insecure: boolean): MetaProbe {
|
||||
return async (endpoint) => {
|
||||
const http = createHttpClient({ baseURL: openAPIBase(endpoint), timeoutMs: META_PROBE_TIMEOUT_MS, retryAttempts: 0, insecure })
|
||||
const http = createHttpClient({
|
||||
baseURL: openAPIBase(endpoint),
|
||||
timeoutMs: META_PROBE_TIMEOUT_MS,
|
||||
retryAttempts: 0,
|
||||
insecure,
|
||||
})
|
||||
return new MetaClient(http).serverVersion()
|
||||
}
|
||||
}
|
||||
@@ -99,8 +104,7 @@ export async function runVersionProbe(opts: RunVersionProbeOptions): Promise<Ver
|
||||
let loadFailed = false
|
||||
try {
|
||||
active = await loadActive()
|
||||
}
|
||||
catch {
|
||||
} catch {
|
||||
loadFailed = true
|
||||
}
|
||||
|
||||
@@ -119,13 +123,16 @@ export async function runVersionProbe(opts: RunVersionProbeOptions): Promise<Ver
|
||||
let serverInfo: ServerVersionResponse | undefined
|
||||
try {
|
||||
serverInfo = await probe(endpoint)
|
||||
}
|
||||
catch {
|
||||
} catch {
|
||||
serverInfo = undefined
|
||||
}
|
||||
|
||||
if (serverInfo === undefined)
|
||||
return { client, server: unreachableServer(endpoint), compat: compatBlock({ status: 'unknown', detail: 'server unreachable' }) }
|
||||
return {
|
||||
client,
|
||||
server: unreachableServer(endpoint),
|
||||
compat: compatBlock({ status: 'unknown', detail: 'server unreachable' }),
|
||||
}
|
||||
|
||||
return {
|
||||
client,
|
||||
|
||||
@@ -31,7 +31,12 @@ describe('renderVersionText', () => {
|
||||
it('renders all three blocks for a reachable, compatible server', () => {
|
||||
const report: VersionReport = {
|
||||
client: baseClient(),
|
||||
server: { endpoint: 'https://cloud.dify.ai', reachable: true, version: '1.6.4', edition: 'CLOUD' },
|
||||
server: {
|
||||
endpoint: 'https://cloud.dify.ai',
|
||||
reachable: true,
|
||||
version: '1.6.4',
|
||||
edition: 'CLOUD',
|
||||
},
|
||||
compat: compatible(),
|
||||
}
|
||||
const text = renderVersionText(report)
|
||||
@@ -127,7 +132,12 @@ describe('renderVersionText', () => {
|
||||
it('color=false produces no ANSI escape sequences regardless of TTY state', () => {
|
||||
const report: VersionReport = {
|
||||
client: baseClient({ channel: 'rc' }),
|
||||
server: { endpoint: 'https://cloud.dify.ai', reachable: true, version: '99.0.0', edition: 'SELF_HOSTED' },
|
||||
server: {
|
||||
endpoint: 'https://cloud.dify.ai',
|
||||
reachable: true,
|
||||
version: '99.0.0',
|
||||
edition: 'SELF_HOSTED',
|
||||
},
|
||||
compat: {
|
||||
minDify: '1.6.0',
|
||||
maxDify: '1.7.0',
|
||||
@@ -171,7 +181,12 @@ describe('renderVersionText', () => {
|
||||
const { renderVersionText: render } = await import('./render')
|
||||
const report: VersionReport = {
|
||||
client: baseClient({ channel: 'rc' }),
|
||||
server: { endpoint: 'https://cloud.dify.ai', reachable: true, version: '99.0.0', edition: 'SELF_HOSTED' },
|
||||
server: {
|
||||
endpoint: 'https://cloud.dify.ai',
|
||||
reachable: true,
|
||||
version: '99.0.0',
|
||||
edition: 'SELF_HOSTED',
|
||||
},
|
||||
compat: {
|
||||
minDify: '1.6.0',
|
||||
maxDify: '1.7.0',
|
||||
|
||||
@@ -39,14 +39,14 @@ export function renderVersionText(report: VersionReport, opts: RenderOptions = {
|
||||
lines.push('Server:')
|
||||
if (server.endpoint === '') {
|
||||
lines.push(` ${c.dim('(skipped — no host configured or --client passed)')}`)
|
||||
}
|
||||
else if (!server.reachable) {
|
||||
} else if (!server.reachable) {
|
||||
lines.push(` Endpoint: ${server.endpoint}`)
|
||||
lines.push(` Version: ${c.dim('(unreachable)')}`)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
lines.push(` Endpoint: ${server.endpoint}`)
|
||||
lines.push(` Version: ${server.version ?? ''}${server.edition !== undefined ? ` (${server.edition.toLowerCase()})` : ''}`)
|
||||
lines.push(
|
||||
` Version: ${server.version ?? ''}${server.edition !== undefined ? ` (${server.edition.toLowerCase()})` : ''}`,
|
||||
)
|
||||
}
|
||||
lines.push('')
|
||||
|
||||
@@ -56,8 +56,7 @@ export function renderVersionText(report: VersionReport, opts: RenderOptions = {
|
||||
|
||||
if (client.channel !== 'stable') {
|
||||
lines.push('')
|
||||
for (const line of prereleaseWarning(client.channel))
|
||||
lines.push(c.yellow(line))
|
||||
for (const line of prereleaseWarning(client.channel)) lines.push(c.yellow(line))
|
||||
}
|
||||
|
||||
return `${lines.join('\n')}\n`
|
||||
|
||||
Reference in New Issue
Block a user