release:tag 先检查版本号与 CHANGELOG,发布后从 CHANGELOG 自动建 GitHub Release;发布步骤可重跑;配好 npm trusted publishing 后自动走 OIDC。测试检查两个模型包都精确钉住版本

This commit is contained in:
cv-cat committed 2026-10-07 00:25:14 +08:00
1 parent 2493b08b4b
commit fbad1a1c8d
6 files changed
+86 -28

No files matched your search

+1
View File
@@ -68,6 +68,7 @@ catbus/
├── scripts/
│ ├── golden/ # 调用上游 Python 生成对拍数据
│ ├── smoke.mjs # CI 冒烟测试
│ ├── release-notes.mjs # 从 CHANGELOG 生成 GitHub Release 的说明
│ └── fetch-*-models.mjs # 取回模型
├── tests/ # vitest;golden/<p>/ 放对拍数据,e2e/ 放在线测试
└── references/ # 上游仓库的只读副本,不进版本控制
+1 -1
View File
@@ -249,7 +249,7 @@ npm run test:e2e -- -t '^x ' # X 的平台 id 太短,-t x 会连 xhs、
### 4.1 CI 做了什么
[.github/workflows/ci.yml](workflows/ci.yml) 在推送到 `master`、提交 PR 时触发;推送 `v*` tag 时,[release.yml](workflows/release.yml) 也会先调用它跑完整 CI,再发布 CI 里打好、测过的同一份 tarball。
[.github/workflows/ci.yml](workflows/ci.yml) 在推送到 `master`、提交 PR 时触发;推送 `v*` tag 时,[release.yml](workflows/release.yml) 也会先调用它跑完整 CI,再发布 CI 里打好、测过的同一份 tarball,并从 CHANGELOG 生成 GitHub Release(发版步骤见 [AGENTS.md 7.2](../AGENTS.md#72-打包与分发))。
| job | 环境 | 步骤 |
|---|---|---|
+43 -21
View File
@@ -1,7 +1,8 @@
name: release
# 推送 v* tag 发布。先跑完整 CI(含全部目标系统的冒烟),再发布 CI 里打好、测过的同一份 tarball。
# 推送 v* tag 发布。先跑完整 CI(含全部目标系统的冒烟),再发布 CI 里打好、测过的同一份 tarball,最后建 GitHub Release。
# 发布顺序:@cv-cat/catbus-assets-jd、@cv-cat/catbus-assets-ocr(该版本还没发布时)→ catbus-cli(AGENTS 7.2)。
# 每一步发布前都先查这个版本是否已经在 npm 上,失败后重跑这个 job 不会重复发布。
on:
push:
tags: ['v*']
@@ -11,14 +12,30 @@ permissions:
id-token: write
jobs:
# 不用等 CI 跑完就能发现的问题,先查
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: tag 与版本号一致
run: |
version=$(node -p "require('./package.json').version")
test "v$version" = "$GITHUB_REF_NAME" || { echo "tag $GITHUB_REF_NAME 与 package.json 的 $version 不一致"; exit 1; }
- name: CHANGELOG 有这个版本
run: node scripts/release-notes.mjs "${GITHUB_REF_NAME#v}" > /dev/null
ci:
uses: ./.github/workflows/ci.yml
publish:
needs: ci
needs: [check, ci]
runs-on: ubuntu-latest
permissions:
contents: write # 建 GitHub Release
id-token: write # npm trusted publishing(OIDC)与 provenance
env:
# 用 NPM_TOKEN 发布;在 npm 上配好 trusted publishing 后可以删掉这个 secret,走 OIDC。
# 在 npm 上给三个包配好 trusted publishing 后,npm 优先用 OIDC,用不了才退回这个 token;
# 走 OIDC 成功发布过一次后,删掉这一行和仓库的 NPM_TOKEN secret。
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# npm 只给公开仓库生成 provenance:仓库公开时带 --provenance,私有时不带
PROVENANCE: ${{ !github.event.repository.private && '--provenance' || '' }}
@@ -28,29 +45,34 @@ jobs:
with:
node-version: 24
registry-url: https://registry.npmjs.org
# trusted publishing 需要 npm 11.5.1 以上
- run: npm install -g npm@latest
- name: tag 与版本号一致
run: |
version=$(node -p "require('./package.json').version")
test "v$version" = "$GITHUB_REF_NAME" || { echo "tag $GITHUB_REF_NAME 与 package.json 的 $version 不一致"; exit 1; }
- uses: actions/download-artifact@v8
with:
name: packages
- name: publish @cv-cat/catbus-assets-jd
- name: publish
run: |
version=$(node -p "require('./packages/assets-jd/package.json').version")
if npm view "@cv-cat/catbus-assets-jd@$version" version >/dev/null 2>&1; then
echo "@cv-cat/catbus-assets-jd@$version 已发布,跳过"
else
npm publish "./cv-cat-catbus-assets-jd-$version.tgz" --access public $PROVENANCE
fi
- name: publish @cv-cat/catbus-assets-ocr
# $1 是 package.json 所在目录;tarball 名与 npm pack 一致:@scope/name → scope-name-<版本>.tgz
publish() {
name=$(node -p "require('./$1/package.json').name")
version=$(node -p "require('./$1/package.json').version")
if npm view "$name@$version" version >/dev/null 2>&1; then
echo "$name@$version 已发布,跳过"
else
npm publish "./$(echo "$name" | sed 's#^@##; s#/#-#')-$version.tgz" --access public $PROVENANCE
fi
}
publish packages/assets-jd
publish packages/assets-ocr
publish .
- name: GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
version=$(node -p "require('./packages/assets-ocr/package.json').version")
if npm view "@cv-cat/catbus-assets-ocr@$version" version >/dev/null 2>&1; then
echo "@cv-cat/catbus-assets-ocr@$version 已发布,跳过"
version=${GITHUB_REF_NAME#v}
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
echo "Release $GITHUB_REF_NAME 已存在,跳过"
else
npm publish "./cv-cat-catbus-assets-ocr-$version.tgz" --access public $PROVENANCE
node scripts/release-notes.mjs "$version" > notes.md
gh release create "$GITHUB_REF_NAME" --verify-tag --title "catbus $version" --notes-file notes.md
fi
- name: publish catbus-cli
run: npm publish ./catbus-cli-*.tgz --access public $PROVENANCE
+6 -3
View File
@@ -754,9 +754,12 @@ stdout 只输出结果。日志、提示、进度、二维码一律输出到 std
- darwin-arm64、darwin-x64;
- linux-x64、linux-arm64,glibc 和 musl 都要支持。
- CI 在全部目标系统上跑冒烟测试,musl 用 Alpine。**任何一个目标系统缺预编译包的依赖都不能用。**
- 发布:推送 `v*` tag 触发 `.github/workflows/release.yml`,先跑完整 CI,再发布 CI 里测过的同一份 tarball。
- 顺序:先发 assets-jd、assets-ocr(该版本还没发布时),再发 `catbus-cli`。
- 需要仓库 secret `NPM_TOKEN`(有发布权限的 npm token);在 npm 上配好 trusted publishing 后可以改用 OIDC。
- 发布:
1. 改 `package.json` 的版本号。模型变了时同时改 `packages/assets-*/package.json` 的版本,并把主包里钉住的依赖改成同一个版本(测试会检查)。
2. 在 `CHANGELOG.md` 写好 `## [<版本>] - <日期>` 一节。
3. 推送 `v<版本>` tag,触发 `.github/workflows/release.yml`:先检查 tag 与版本号一致、CHANGELOG 里有这个版本;跑完整 CI;发布 CI 里测过的同一份 tarball;最后用 `scripts/release-notes.mjs` 从 CHANGELOG 生成 GitHub Release。
- 顺序:先发 assets-jd、assets-ocr,再发 `catbus-cli`。已经在 npm 上的版本跳过,失败后重跑不会重复发布。
- 认证:npm 上给三个包配了 trusted publishing(GitHub Actions,`cv-cat/catbus`,`release.yml`,允许 `npm publish`)时走 OIDC,否则用仓库 secret `NPM_TOKEN`。trusted publishing 配好后两天内要成功发布一次,否则失效。
- 仓库公开时发布带 `--provenance`,私有时不带(npm 只给公开仓库生成 provenance),由 release.yml 按仓库可见性自动判断。
- **Docker 镜像**(可选):`Dockerfile` 走与 npm 发布相同的路径,先打出三个包,再在 `node:<版本>-bookworm-slim` 里全局安装这三个 tarball;`CATBUS_HOME=/data`(卷),工作目录 `/work`;默认以 root 运行(挂进来的目录都能写),Linux 上可以 `--user "$(id -u):$(id -g)"` 配合挂自己的数据目录。`compose.yaml` 提供 `catbus`(一次性命令)和 `live-listen`(长时间监听直播)两个服务。CI 的 `.github/workflows/docker.yml` 在 x64 与 arm64 上构建并跑 `version` / `doctor`,不推送到任何镜像仓库。
- 以后要提供 SDK 时,通过 `package.json` 的 `exports` 暴露,现在不做。
+30
View File
@@ -0,0 +1,30 @@
// 从 CHANGELOG.md 取出某个版本的说明,作为 GitHub Release 的正文写到 stdout:开头是安装命令,相对链接换成仓库里的绝对地址。
// 用法:node scripts/release-notes.mjs <版本号>。CHANGELOG 里没有这个版本时退出码 1,release.yml 在发布前用它检查。
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
const BLOB = 'https://github.com/cv-cat/catbus/blob/master/'
const version = process.argv[2]
if (!version) {
console.error('用法:node scripts/release-notes.mjs <版本号>')
process.exit(2)
}
const changelog = readFileSync(fileURLToPath(new URL('../CHANGELOG.md', import.meta.url)), 'utf8').replace(/\r\n/g, '\n')
const section = changelog.split(/^## /m).find((s) => s.startsWith(`[${version}]`))
if (!section) {
console.error(`CHANGELOG.md 里没有 ## [${version}],先写好这个版本的更新日志再打 tag`)
process.exit(1)
}
const body = section
.split('\n')
.slice(1)
.filter((line) => !/^\[[^\]]+\]: /.test(line))
.join('\n')
.replace(/^### /gm, '## ')
.replace(/\]\((?!https?:|#)([^)]+)\)/g, (_, path) => `](${BLOB}${path})`)
.trim()
process.stdout.write(`\`\`\`bash\nnpm i -g catbus-cli@${version}\n\`\`\`\n\n${body}\n\n完整的更新日志见 [CHANGELOG.md](${BLOB}CHANGELOG.md)。\n`)
+5 -3
View File
@@ -170,10 +170,12 @@ describe('docs/capabilities.md', () => {
})
describe('package.json', () => {
it('精确钉住 @cv-cat/catbus-assets-jd 的版本(AGENTS 7.2)', () => {
it('精确钉住两个模型包的版本(AGENTS 7.2)', () => {
const read = (p: string) => JSON.parse(readFileSync(new URL(p, import.meta.url), 'utf8'))
const main = read('../package.json')
const assets = read('../packages/assets-jd/package.json')
expect(main.dependencies[assets.name]).toBe(assets.version)
for (const dir of ['assets-jd', 'assets-ocr']) {
const assets = read(`../packages/${dir}/package.json`)
expect(main.dependencies[assets.name], assets.name).toBe(assets.version)
}
})
})