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:
Stephen Zhou
2026-07-12 15:57:46 +00:00
committed by GitHub
co-authored by autofix-ci[bot]
parent fde08d24fe
commit a84c2d36a3
6213 changed files with 227959 additions and 187183 deletions
+3 -1
View File
@@ -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',
)
})
})
+20 -5
View File
@@ -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}]`,
}
}
+6 -4
View File
@@ -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()
})
+12 -9
View File
@@ -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
}
+4 -2
View File
@@ -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 {
+31 -20
View File
@@ -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
View File
@@ -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`
}
+12 -9
View File
@@ -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 })
}
+13 -6
View File
@@ -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,
+18 -3
View File
@@ -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',
+6 -7
View File
@@ -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`