Skip to content

Commit 525412f

Browse files
committed
feat: win bl update exe file test
1 parent 75b056b commit 525412f

10 files changed

Lines changed: 177 additions & 67 deletions

File tree

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ on:
1818
- channel
1919
- stable
2020
channel:
21-
description: "Required when mode=channel. dist-tag / rolling manifest name (lowercase, digits, dashes). bailian-cli binary install verify: sync-release; knowledge-studio-cli / other tags: mcp, plugin, etc."
21+
description: "Required when mode=channel. npm dist-tag only (lowercase, digits, dashes), e.g. mcp / plugin / sync-release. bailian-cli binary CDN always overwrites sync-release.json; knowledge-studio-cli is npm-only."
2222
required: false
2323
type: string
2424

@@ -93,7 +93,7 @@ jobs:
9393
- name: Require channel input
9494
if: ${{ inputs.channel == '' }}
9595
run: |
96-
echo "::error::mode=channel requires the workflow input \"channel\" (bailian-cli install verify: sync-release; knowledge-studio-cli / others: e.g. mcp, plugin). Leave mode=stable if you do not need a dist-tag."
96+
echo "::error::mode=channel requires the workflow input \"channel\" (npm dist-tag, e.g. mcp / plugin / sync-release). Leave mode=stable if you do not need a dist-tag."
9797
exit 1
9898
9999
- uses: actions/checkout@v6

INSTALL.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash
99
```
1010

11-
可选:正式安装读 CDN 上的 `manifest.json`。预发 / channel 验证示例
11+
可选:正式安装读 CDN 上的 `manifest.json`。预发 / channel 验证一律读 `sync-release.json`(bailian-cli 的 channel 发版都会覆盖它)
1212

1313
```bash
1414
curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash -s -- --channel sync-release
@@ -19,10 +19,14 @@ curl -fsSL https://bailian.aliyun.com/cli/install.sh | bash -s -- --channel sync
1919
Windows PowerShell:
2020

2121
```powershell
22+
# 正式(manifest.json)
2223
irm https://bailian.aliyun.com/cli/install.ps1 | iex
24+
25+
# channel / 预发验证(sync-release.json)
26+
$env:BAILIAN_CHANNEL = 'sync-release'; irm 'https://bailian.aliyun.com/cli/install.ps1' | iex
2327
```
2428

25-
带参时先落盘再执行`irm | iex` 不便传参),或使用仓外静态资源文档中的预发入口。
29+
带其它参时先落盘再执行`irm | iex` 不便传参),或使用仓外静态资源文档中的预发入口。
2630

2731
二进制安装布局为 `versions/<ver>/` + `current` 指针;`bl update` 只切换指针并清理旧版本(保留当前与上一版)。更新进程退出后,下次执行 `bl` 即使用新版本(无需「重启应用」)。
2832

docs/agents/publish.md

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,36 @@ publish-stable.mjs / publish-channel.mjs ← 唯一发版入口
2626

2727
两种模式:
2828

29-
| 模式 | 用途 | 触发方式 |
30-
| ------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
31-
| channel | npm dist-tag + GitHub prerelease + 滚动 `channel-<name>` |mode=channel,channel 名。**`bailian-cli` 二进制安装验证**`sync-release``knowledge-studio-cli` 与 mcp/plugin 等仍按各自 dist-tag 名填写 |
32-
| stable | npm latest + GitHub Release `v<ver>`(含 install 脚本) |mode=stable,需 production environment 审批 |
29+
| 模式 | 用途 | 触发方式 |
30+
| ------- | --------------------------------------------------------------------------------------- | -------------------------------------------- |
31+
| channel | npm dist-tag +(仅 bailian-cli)二进制 + CDN **一律**覆盖 `sync-release.json` | mode=channel,channel **npm dist-tag** |
32+
| stable | npm latest + GitHub Release `v<ver>` + CDN **`manifest.json`**(及 `latest.json` 别名) | mode=stable,需 production environment 审批 |
3333

3434
可选 flag:`--skip-binary`(仅发 npm,紧急逃生)。
3535

36+
### CDN 滚动指针(bailian-cli)
37+
38+
| 发布模式 | CDN 指针 | 本机安装 / 更新 |
39+
| -------- | ---------------------------------- | ----------------------------------------------------------------- |
40+
| channel | 始终覆盖 `sync-release.json` | `BAILIAN_CHANNEL=sync-release` / `install --channel sync-release` |
41+
| stable | `manifest.json`(+ `latest.json`| 默认安装 / `bl update`(无 channel) |
42+
43+
workflow 的 `channel` 输入**只决定 npm dist-tag**(如 `mcp` / `plugin` / `sync-release`),**不再**生成 `release-test.json` 这类旁路文件。
44+
3645
### channel 发布
3746

38-
1. 在 GitHub 触发 Publish workflow,package 选目标包,mode 选 `channel`,channel 填名称:
39-
- **`bailian-cli` 二进制安装验证**:填 `sync-release`(更新 CDN `sync-release.json`;本机 `BAILIAN_CHANNEL=sync-release` / `install.sh --channel sync-release`)。填什么就写什么 `{channel}.json`;发 `release-test` **不会**更新 `sync-release.json`
40-
- **`knowledge-studio-cli`**:不要用 `sync-release`(那是 `bl` 安装脚本/CDN 约定);按 npm dist-tag 需要填 `mcp` / `plugin` 等即可,行为与改文档前一致
41-
- 其它 npm dist-tag(任一 package):填 `mcp` / `plugin`
42-
2. CI 自动:生成 `0.0.0-beta-<sha7>-<date>` → 临时 bump → 自检 → **npm 发到 dist-tag****Bun 编二进制并创建 GitHub prerelease + 滚动 `{channel}.json`** → 还原 package.json
47+
1. 在 GitHub 触发 Publish workflow,mode 选 `channel`,channel 填 npm dist-tag 名:
48+
- **`bailian-cli`**:npm 发到该 tag;二进制同时刷新 CDN `sync-release.json`(与 tag 名无关)。本机验证:`BAILIAN_CHANNEL=sync-release`
49+
- **`knowledge-studio-cli`**:仅 npm(自动跳过 binary,不碰 `sync-release.json`
50+
2. CI 自动:生成 `0.0.0-beta-<sha7>-<date>` → 临时 bump → 自检 → **npm 发到 dist-tag** →(bailian-cli)**Bun 编二进制 + GH prerelease + 覆盖 `sync-release.json`** → 还原 package.json
4351
3. 对应脚本:`tools/release/publish-channel.mjs`
4452

4553
### stable 发布
4654

4755
1. 确保当前 release tooling 覆盖的包(`tools/release/lib/packages.mjs`)已升到目标版本且一致;当前基础集合为 `packages/core` / `packages/runtime` / `packages/commands` / `packages/cli``knowledge-studio-cli` 发布会额外包含 `packages/kscli`
4856
2. 在 GitHub 触发 Publish workflow,package 选目标包集合,mode 选 `stable`
4957
3. 需要 production environment 审批人批准
50-
4. CI 自动:自检 → **npm 发到 latest****推送 git tag `v<ver>`****Bun 编二进制并创建/更新 GitHub Release** → 完成
58+
4. CI 自动:自检 → **npm 发到 latest****推送 git tag `v<ver>`****Bun 编二进制并创建/更新 GitHub Release**(bailian-cli)维护 CDN **`manifest.json`** 完成
5159
5. 如果所选发布集合的当前版本已全部存在于 npm,stable 发布会失败并提示先升级版本号;如果只有部分包已发布,CI 会继续补发缺失包
5260
6. 对应脚本:`tools/release/publish-stable.mjs`
5361

packages/core/src/install/cdn.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
* v<version>/<asset>.zip —— immutable per-version binaries + SHA256SUMS
88
* manifest.json —— stable install/update pointer (rolling-manifest shape)
99
* latest.json —— stable alias; same body as manifest.json
10-
* <channel>.json —— per-channel rolling manifests (betas / local verify)
10+
* sync-release.json —— official channel/verify rolling pointer (all bailian-cli
11+
* channel publishes overwrite this; npm dist-tag is separate)
12+
*
13+
* Legacy `{name}.json` files may still exist on CDN; install may resolve them, but
14+
* release tooling no longer creates per-dist-tag manifests.
1115
*
1216
* Override with `BAILIAN_CLI_CDN`.
1317
*/
@@ -29,7 +33,8 @@ export function getCliCdnBase(): string {
2933
/**
3034
* Rolling manifest URL at the CDN base root.
3135
* Stable (`latest` / `stable` / empty) → `manifest.json`.
32-
* Named channel → `{channel}.json` (e.g. sync-release for local verify).
36+
* Official verify line → `sync-release.json` (`channel=sync-release`).
37+
* Other names still map to `{channel}.json` for backward compatibility only.
3338
* All share the same rolling-manifest shape from binary-build.
3439
*/
3540
export function channelManifestUrl(channel = "latest"): string {

tools/release/lib/binary-build.mjs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@
77
* node tools/release/lib/binary-build.mjs --mode stable --host
88
*
99
* Manifests:
10-
* --mode stable → writes latest.json (rolling manifest of the implicit
11-
* "latest" channel; OSS prefix root only, not a GH asset)
12-
* --mode channel → writes <channel>.json
10+
* --mode stable → writes latest.json (fed into OSS manifest.json + latest.json)
11+
* --mode channel → always writes sync-release.json (npm --channel is dist-tag only)
1312
*/
1413
import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
1514
import { join, resolve } from "node:path";
1615
import { fileURLToPath } from "node:url";
1716
import { spawnSync } from "node:child_process";
1817
import { parseArgs } from "node:util";
1918
import { ROOT, readPackageJson, PACKAGES } from "./packages.mjs";
20-
import { channelManifestFileName, normalizeModeChannel } from "./binary-options.mjs";
19+
import {
20+
normalizeModeChannel,
21+
rollingManifestChannelId,
22+
rollingManifestFileName,
23+
} from "./binary-options.mjs";
2124
import { ensureZip, zipOne } from "./binary-zip.mjs";
2225

2326
const BINARY_COMPILE = fileURLToPath(new URL("./binary-compile.mjs", import.meta.url));
@@ -157,8 +160,9 @@ function writeChecksums(outdir, artifacts) {
157160
writeFileSync(join(outdir, "SHA256SUMS"), `${lines.join("\n")}\n`);
158161
}
159162

160-
/** Write the rolling channel manifest (`latest.json` / `<channel>.json`) with per-platform zip file + sha256. */
161-
function writeChannelManifest(outdir, version, artifacts, channel) {
163+
/** Write the rolling channel manifest (`latest.json` / `sync-release.json`) with per-platform zip + sha256. */
164+
function writeChannelManifest(outdir, version, artifacts, mode) {
165+
const channel = rollingManifestChannelId(mode);
162166
const assets = Object.fromEntries(
163167
artifacts.map((item) => [
164168
`${item.os}-${item.arch}`,
@@ -176,7 +180,7 @@ function writeChannelManifest(outdir, version, artifacts, channel) {
176180
releasedAt: new Date().toISOString(),
177181
assets,
178182
};
179-
const name = channelManifestFileName(channel);
183+
const name = rollingManifestFileName(mode);
180184
writeJson(join(outdir, name), manifest);
181185
return name;
182186
}
@@ -222,9 +226,7 @@ export function buildBinaryArtifacts(rawOptions = {}) {
222226
writeChecksums(outdir, artifacts);
223227

224228
const extras = ["SHA256SUMS"];
225-
extras.push(
226-
writeChannelManifest(outdir, version, artifacts, mode === "channel" ? channel : "latest"),
227-
);
229+
extras.push(writeChannelManifest(outdir, version, artifacts, mode));
228230

229231
log(`\nBuilt ${artifacts.length} zip(s):`);
230232
for (const item of artifacts) {

tools/release/lib/binary-options.mjs

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
/**
22
* Shared mode / channel / manifest naming for binary-build and binary-release.
33
*
4-
* Every mode writes a rolling channel manifest: stable writes `latest.json`
5-
* (uploaded to the OSS prefix root only, never attached to the GitHub Release),
6-
* channel writes `<channel>.json` (attached to the rolling `channel-<name>`
7-
* GitHub Release and uploaded to the OSS prefix root).
4+
* Rolling CDN pointers (bailian-cli binary):
5+
* - stable → build writes `latest.json`; OSS maintains `manifest.json` (+ `latest.json`)
6+
* - channel → always `sync-release.json` on OSS / GH rolling release `channel-sync-release`
7+
*
8+
* The workflow `--channel` value remains the npm dist-tag (and versioned GH release notes).
9+
* It does not choose the CDN rolling filename.
810
*/
911
import { assertChannel } from "./validate.mjs";
1012

13+
/** Official bailian-cli channel/verify rolling manifest name on CDN. */
14+
export const SYNC_RELEASE_CHANNEL = "sync-release";
15+
16+
/** Stable build-local rolling manifest (fed into maintainReleaseManifest). */
17+
export const STABLE_ROLLING_CHANNEL = "latest";
18+
1119
/**
1220
* @param {string} mode
1321
* @param {string | null | undefined} channel
@@ -28,8 +36,40 @@ export function normalizeModeChannel(mode = "stable", channel = null) {
2836
return { mode: "stable", channel: null };
2937
}
3038

31-
/** Rolling-manifest basename: `latest.json` for stable, `<channel>.json` otherwise. */
39+
/**
40+
* Rolling-manifest basename for a logical channel id inside a build artifact.
41+
* Prefer {@link rollingManifestFileName} for mode-aware naming.
42+
*/
3243
export function channelManifestFileName(channel) {
3344
if (!channel) throw new Error("channelManifestFileName requires a channel name");
3445
return `${channel}.json`;
3546
}
47+
48+
/**
49+
* Rolling manifest basename written by binary-build / uploaded to OSS root.
50+
* - stable → `latest.json`
51+
* - channel → always `sync-release.json` (ignores npm dist-tag name)
52+
*
53+
* @param {"stable" | "channel"} mode
54+
* @returns {string}
55+
*/
56+
export function rollingManifestFileName(mode) {
57+
if (mode === "stable") return channelManifestFileName(STABLE_ROLLING_CHANNEL);
58+
if (mode === "channel") return channelManifestFileName(SYNC_RELEASE_CHANNEL);
59+
throw new Error(`rollingManifestFileName: unknown mode ${mode}`);
60+
}
61+
62+
/** Channel id embedded in the rolling manifest JSON body. */
63+
export function rollingManifestChannelId(mode) {
64+
if (mode === "stable") return STABLE_ROLLING_CHANNEL;
65+
if (mode === "channel") return SYNC_RELEASE_CHANNEL;
66+
throw new Error(`rollingManifestChannelId: unknown mode ${mode}`);
67+
}
68+
69+
/** GitHub rolling prerelease tag that holds only the CDN channel pointer. */
70+
export function rollingChannelReleaseTag(mode) {
71+
if (mode !== "channel") {
72+
throw new Error("rollingChannelReleaseTag is only valid for mode=channel");
73+
}
74+
return `channel-${SYNC_RELEASE_CHANNEL}`;
75+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import assert from "node:assert/strict";
2+
import { describe, it } from "node:test";
3+
import {
4+
channelManifestFileName,
5+
normalizeModeChannel,
6+
rollingChannelReleaseTag,
7+
rollingManifestChannelId,
8+
rollingManifestFileName,
9+
STABLE_ROLLING_CHANNEL,
10+
SYNC_RELEASE_CHANNEL,
11+
} from "./binary-options.mjs";
12+
13+
describe("rolling CDN manifest naming", () => {
14+
it("keeps sync-release and latest constants", () => {
15+
assert.equal(SYNC_RELEASE_CHANNEL, "sync-release");
16+
assert.equal(STABLE_ROLLING_CHANNEL, "latest");
17+
});
18+
19+
it("channel mode always rolls sync-release.json regardless of npm dist-tag", () => {
20+
const { mode, channel } = normalizeModeChannel("channel", "mcp");
21+
assert.equal(mode, "channel");
22+
assert.equal(channel, "mcp");
23+
assert.equal(rollingManifestFileName(mode), "sync-release.json");
24+
assert.equal(rollingManifestChannelId(mode), "sync-release");
25+
assert.equal(rollingChannelReleaseTag(mode), "channel-sync-release");
26+
});
27+
28+
it("stable mode rolls latest.json for maintainReleaseManifest input", () => {
29+
const { mode, channel } = normalizeModeChannel("stable", null);
30+
assert.equal(mode, "stable");
31+
assert.equal(channel, null);
32+
assert.equal(rollingManifestFileName(mode), "latest.json");
33+
assert.equal(rollingManifestChannelId(mode), "latest");
34+
});
35+
36+
it("channelManifestFileName still formats arbitrary names for helpers", () => {
37+
assert.equal(channelManifestFileName("release-test"), "release-test.json");
38+
assert.equal(channelManifestFileName(SYNC_RELEASE_CHANNEL), "sync-release.json");
39+
});
40+
});

0 commit comments

Comments
 (0)