From d764b16d0624fe77fefd6c2c796bf08d69838514 Mon Sep 17 00:00:00 2001 From: Xiyuan Chen <52963600+GareArc@users.noreply.github.com> Date: Tue, 23 Jun 2026 01:07:15 -0700 Subject: [PATCH] feat(cli): prepare for alpha release (#37794) --- cli/package.json | 6 +-- cli/scripts/lib/resolve-buildinfo.ts | 2 +- cli/scripts/release-naming.mjs | 1 + cli/scripts/release-naming.test.ts | 26 ++++++------- cli/scripts/release-r2-edge.test.ts | 2 +- cli/src/commands/version/version.test.ts | 2 +- cli/src/version/info.ts | 2 +- cli/src/version/render.test.ts | 47 +++++++++++++++++++++--- cli/src/version/render.ts | 15 +++++--- 9 files changed, 69 insertions(+), 34 deletions(-) diff --git a/cli/package.json b/cli/package.json index 7af5c7d0f53..3d25fb6b833 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,12 +1,12 @@ { "name": "@langgenius/difyctl", "type": "module", - "version": "0.1.0-rc.1", + "version": "0.1.0-alpha", "description": "Dify command-line interface", "difyctl": { - "channel": "rc", + "channel": "alpha", "compat": { - "minDify": "1.14.0", + "minDify": "1.15.0", "maxDify": "1.15.0" }, "release": { diff --git a/cli/scripts/lib/resolve-buildinfo.ts b/cli/scripts/lib/resolve-buildinfo.ts index ee0cc7b5506..10cdf2814b0 100644 --- a/cli/scripts/lib/resolve-buildinfo.ts +++ b/cli/scripts/lib/resolve-buildinfo.ts @@ -4,7 +4,7 @@ import { readFileSync } from 'node:fs' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' -export const BUILD_CHANNELS = ['dev', 'rc', 'stable'] as const +export const BUILD_CHANNELS = ['dev', 'alpha', 'rc', 'edge', 'stable'] as const export type BuildChannel = (typeof BUILD_CHANNELS)[number] export type BuildInfo = { diff --git a/cli/scripts/release-naming.mjs b/cli/scripts/release-naming.mjs index 5d7457b59b0..376c215633e 100644 --- a/cli/scripts/release-naming.mjs +++ b/cli/scripts/release-naming.mjs @@ -26,6 +26,7 @@ const SEMVER_CORE_LEN = 3 // Add channels here: { name, prerelease, versionForm }. const CHANNELS = [ { name: 'stable', prerelease: false, versionForm: /^\d+\.\d+\.\d+(\+[0-9A-Z.-]+)?$/i }, + { name: 'alpha', prerelease: true, versionForm: /^\d+\.\d+\.\d+-alpha(\.\d+)?$/ }, { name: 'rc', prerelease: true, versionForm: /^\d+\.\d+\.\d+-rc\.\d+$/ }, { name: 'edge', prerelease: true, versionForm: /^\d+\.\d+\.\d+-edge\.[0-9a-f]{7,40}$/ }, ] diff --git a/cli/scripts/release-naming.test.ts b/cli/scripts/release-naming.test.ts index ad2a699ef8d..559d15ad759 100644 --- a/cli/scripts/release-naming.test.ts +++ b/cli/scripts/release-naming.test.ts @@ -15,13 +15,13 @@ function run(args: string[]): { code: number, stdout: string, stderr: string } { } } -describe('release-naming compat-check (compat 1.14.0..1.15.0)', () => { +describe('release-naming compat-check (compat 1.15.0..1.15.0)', () => { it('accepts a version inside the window', () => { - expect(run(['compat-check', '1.14.7']).code).toBe(0) + expect(run(['compat-check', '1.15.0']).code).toBe(0) }) it('accepts the inclusive lower bound', () => { - expect(run(['compat-check', '1.14.0']).code).toBe(0) + expect(run(['compat-check', '1.15.0']).code).toBe(0) }) it('accepts the inclusive upper bound', () => { @@ -29,26 +29,22 @@ describe('release-naming compat-check (compat 1.14.0..1.15.0)', () => { }) it('accepts a v-prefixed tag', () => { - expect(run(['compat-check', 'v1.14.2']).code).toBe(0) + expect(run(['compat-check', 'v1.15.0']).code).toBe(0) }) it('rejects a version below the lower bound', () => { - expect(run(['compat-check', '1.13.9']).code).not.toBe(0) + expect(run(['compat-check', '1.14.9']).code).not.toBe(0) }) it('rejects a version above the upper bound', () => { expect(run(['compat-check', '1.15.1']).code).not.toBe(0) }) - it('treats a prerelease of the upper bound as in range (1.15.0-rc1 <= 1.15.0)', () => { - expect(run(['compat-check', '1.15.0-rc1']).code).toBe(0) + it('treats a prerelease of the bound as below it (1.15.0-rc1 < 1.15.0)', () => { + expect(run(['compat-check', '1.15.0-rc1']).code).not.toBe(0) }) - it('treats a prerelease of the lower bound as below it (1.14.0-rc1 < 1.14.0)', () => { - expect(run(['compat-check', '1.14.0-rc1']).code).not.toBe(0) - }) - - it('ignores build metadata on the upper bound (1.15.0+build == 1.15.0)', () => { + it('ignores build metadata on the bound (1.15.0+build == 1.15.0)', () => { expect(run(['compat-check', '1.15.0+build123']).code).toBe(0) }) @@ -64,7 +60,7 @@ describe('release-naming compat-check (compat 1.14.0..1.15.0)', () => { describe('release-naming github-env', () => { it('emits difyctlTag = tagPrefix + version', () => { const { stdout } = run(['github-env']) - expect(stdout).toMatch(/^difyctlTag=difyctl-v0\.1\.0-rc\.1$/m) + expect(stdout).toMatch(/^difyctlTag=difyctl-v0\.1\.0-alpha$/m) }) it('still emits the existing trace fields', () => { @@ -79,8 +75,8 @@ describe('release-naming edge channel', () => { expect(run(['channels']).stdout).toMatch(/^edge$/m) }) - it('edge-version derives -edge. stripping the rc prerelease', () => { - // package.json version is 0.1.0-rc.1 -> core 0.1.0 + it('edge-version derives -edge. stripping the alpha prerelease', () => { + // package.json version is 0.1.0-alpha -> core 0.1.0 expect(run(['edge-version', '2fd7b82']).stdout.trim()).toBe('0.1.0-edge.2fd7b82') }) diff --git a/cli/scripts/release-r2-edge.test.ts b/cli/scripts/release-r2-edge.test.ts index 1514c6a28e3..12e3ee1822c 100644 --- a/cli/scripts/release-r2-edge.test.ts +++ b/cli/scripts/release-r2-edge.test.ts @@ -81,7 +81,7 @@ describe('release-r2-edge manifest', () => { it('carries the compat window from package.json', () => { const { json } = buildManifest() - expect(json.compat).toEqual({ minDify: '1.14.0', maxDify: '1.15.0' }) + expect(json.compat).toEqual({ minDify: '1.15.0', maxDify: '1.15.0' }) }) it('lists all 5 targets with asset name + sha256 from the checksums file', () => { diff --git a/cli/src/commands/version/version.test.ts b/cli/src/commands/version/version.test.ts index affa01c959f..60512e01d04 100644 --- a/cli/src/commands/version/version.test.ts +++ b/cli/src/commands/version/version.test.ts @@ -158,6 +158,6 @@ describe('Version command', () => { if (output?.kind !== 'formatted') throw new Error('expected formatted output') - expect(output.data.text()).toContain('WARNING: This build is a release candidate') + expect(output.data.text()).toContain('WARNING: This build is a rc release') }) }) diff --git a/cli/src/version/info.ts b/cli/src/version/info.ts index e8d38180fca..c43fef07d36 100644 --- a/cli/src/version/info.ts +++ b/cli/src/version/info.ts @@ -1,7 +1,7 @@ import { arch, platform } from '@/sys/index' import { compatString } from './compat' -export type Channel = 'dev' | 'edge' | 'rc' | 'stable' +export type Channel = 'dev' | 'alpha' | 'edge' | 'rc' | 'stable' export type VersionInfo = { version: string diff --git a/cli/src/version/render.test.ts b/cli/src/version/render.test.ts index d1f40f13e58..c88ce998b9c 100644 --- a/cli/src/version/render.test.ts +++ b/cli/src/version/render.test.ts @@ -52,7 +52,7 @@ describe('renderVersionText', () => { expect(text).not.toContain('WARNING:') }) - it('appends RC warning when channel is rc', () => { + it('appends warning when channel is rc', () => { const report: VersionReport = { client: baseClient({ channel: 'rc' }), server: { endpoint: '', reachable: false }, @@ -60,8 +60,43 @@ describe('renderVersionText', () => { } const text = renderVersionText(report) - expect(text).toContain('WARNING: This build is a release candidate') - expect(text).toContain('install the stable channel') + expect(text).toContain('WARNING: This build is a rc release') + expect(text).toContain('install or wait for the stable channel') + }) + + it('appends warning when channel is alpha', () => { + const report: VersionReport = { + client: baseClient({ channel: 'alpha' }), + server: { endpoint: '', reachable: false }, + compat: { ...compatible(), status: 'unknown', detail: 'server probe skipped' }, + } + const text = renderVersionText(report) + + expect(text).toContain('WARNING: This build is a alpha release') + expect(text).toContain('install or wait for the stable channel') + }) + + it('appends warning when channel is edge', () => { + const report: VersionReport = { + client: baseClient({ channel: 'edge' }), + server: { endpoint: '', reachable: false }, + compat: { ...compatible(), status: 'unknown', detail: 'server probe skipped' }, + } + const text = renderVersionText(report) + + expect(text).toContain('WARNING: This build is a edge release') + expect(text).toContain('install or wait for the stable channel') + }) + + it('does not append warning when channel is stable', () => { + const report: VersionReport = { + client: baseClient({ channel: 'stable' }), + server: { endpoint: '', reachable: false }, + compat: { ...compatible(), status: 'unknown', detail: 'server probe skipped' }, + } + const text = renderVersionText(report) + + expect(text).not.toContain('WARNING:') }) it('shows "(skipped …)" when server.endpoint is empty', () => { @@ -105,7 +140,7 @@ describe('renderVersionText', () => { // RC warning) ran, yet the output is byte-clean. expect(plain).not.toMatch(ANSI_RE) expect(plain).toContain('Compatibility: incompatible') - expect(plain).toContain('WARNING: This build is a release candidate') + expect(plain).toContain('WARNING: This build is a rc release') }) describe('with picocolors stubbed to always emit ANSI', () => { @@ -147,8 +182,8 @@ describe('renderVersionText', () => { const colored = render(report, { color: true }) expect(colored).toMatch(ANSI_RE) expect(colored).toContain('Compatibility: incompatible') - // RC warning lines also routed through yellow. - expect(colored).toContain('release candidate') + // prerelease warning lines also routed through yellow. + expect(colored).toContain('WARNING: This build is a rc release') }) }) diff --git a/cli/src/version/render.ts b/cli/src/version/render.ts index ffedc8c5c07..fa8ee721202 100644 --- a/cli/src/version/render.ts +++ b/cli/src/version/render.ts @@ -1,10 +1,13 @@ +import type { Channel } from './info' import type { VersionReport } from './probe' import { colorScheme } from '@/sys/io/color' -const RC_WARNING_LINES = [ - 'WARNING: This build is a release candidate. It is in beta test, not stable,', - ' and may have bugs. For production use, install the stable channel.', -] as const +function prereleaseWarning(channel: Channel): readonly string[] { + return [ + `WARNING: This build is a ${channel} release. It is not stable`, + ' and may have bugs. For production use, install or wait for the stable channel.', + ] +} export type RenderOptions = { readonly color?: boolean @@ -49,9 +52,9 @@ export function renderVersionText(report: VersionReport, opts: RenderOptions = { const verdictText = `Compatibility: ${COMPAT_LABEL[compat.status]} — ${compat.detail}` lines.push(compat.status === 'unsupported' ? c.yellow(verdictText) : verdictText) - if (client.channel === 'rc') { + if (client.channel !== 'stable') { lines.push('') - for (const line of RC_WARNING_LINES) + for (const line of prereleaseWarning(client.channel)) lines.push(c.yellow(line)) }