release:tag 先检查版本号与 CHANGELOG,发布后从 CHANGELOG 自动建 GitHub Release;发布步骤可重跑;配好 npm trusted publishing 后自动走 OIDC。测试检查两个模型包都精确钉住版本
This commit is contained in:
1 parent
2493b08b4b
commit
fbad1a1c8d
6 files changed
+86
-28
No files matched your search
@@ -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
@@ -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 | 环境 | 步骤 |
|
||||
|---|---|---|
|
||||
|
||||
@@ -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
|
||||
@@ -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` 暴露,现在不做。
|
||||
|
||||
@@ -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`)
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user