首页
/ Ant Design 发版工作流实战:从 Release PR 到 npm publish 的完整操作手册

Ant Design 发版工作流实战:从 Release PR 到 npm publish 的完整操作手册

2026-09-06 17:07:52作者:段琳惟

Ant Design 的版本发布并非简单的“改个版本号 + npm publish”:它的发布准备是一个仅更新 changelog 与 package.json 的普通 PR,而真正的 npm 包发布被刻意推迟到 PR 合并之后,并依赖 prepublishOnly / postpublish 钩子自动完成 CI 检查、产物下载、Git tag 推送与下游通知。本文基于仓库中的发版 skill 文档(.agents/skills/version-release/SKILL.md)与对应的发布脚本源码,梳理出一条可直接照做的发版操作路径:读完你可以独立完成 release PR 的分支判断、发布文件更新、提交前校验,以及在 PR 合并后安全地执行 npm publish

发版流程的定位与边界

Ant Design 的发版工作流明确分为两个阶段,且职责边界清晰:

  1. 准备 release PR:在 changelog 已准备好的前提下,更新 package.json 并提交一个指向 master 的发布准备 PR;
  2. 正式发布:在 release PR 合并之后,执行 npm publish

需要特别注意的边界是:changelog 内容的收集、筛选与改写不在此流程的职责范围内。发版 skill 文档中明确要求:如果 changelog 尚未准备好,应先切换到 changelog-collect 相关流程,而不是在发版过程中临时生成 changelog 文案。这保证了发版操作者只处理“发布准备”这一窄而确定的任务。

分支选择规则

发版的第一原则是分清代码来源分支与 PR 目标分支:

  • 新特性代码来自 feature 分支(通过 auto merge 合入 master),但 release PR 始终向 master 提交
  • 无论是 patch 还是 minor 发布,release PR 的 base 分支都是 master
  • 维护分支发版(如 5.x、4.x 的长期支持)则沿用已有稳定分支,例如 5.x-stable4.x-stable

这一约定在下游 workflow 中也有体现:tag 触发的发布通知工作流 release-dingtalk.yml 中,branch 配置正是 master, 5.x-stable, 4.x-stabletag 过滤为 6*, 5*, 4*,与“主干 + 稳定维护分支”的发版模型完全对应。

发布类型:Patch 与 Minor 的判断标准

除非用户明确要求其它流程,常规发版只处理两类:

类型 代码来源 版本变化 使用场景
Patch master 上的 bugfix x.y.z -> x.y.(z+1) Bug 修复、稳定性发布
Minor feature 分支合入的新特性 x.y.z -> x.(y+1).0 特性批量发布

判断口径:如果改动里明显包含未发布的新特性,优先判断为 minor;否则默认按 patch 处理。 以当前仓库 package.json 为例,version 字段为 6.6.2,若本次合并的仅是 bugfix,目标版本就是 6.6.3;若包含 feature 分支合入的新特性,则应升到 6.7.0

Release PR 准备流程

第 1 步:确认目标分支与当前版本

开始前至少要检查以下四项信息,对应命令为:

git branch -vv
git rev-parse --abbrev-ref HEAD
cat package.json
git tag --list | grep -v -E '(experimental|alpha|resource)' | sort -V | tail -20

逐条确认:

  • 当前要发布的是哪条分支;
  • package.json 里的当前版本号(例如当前的 6.6.2);
  • 最近一次有效 release tag(排除 experimentalalpharesource 等预发布/资源类 tag);
  • 下一个版本应该升 patch 还是 minor。

第 2 步:确认 changelog 已经准备好

发版流程默认把 changelog 视为前置输入,而不是当前步骤的输出。开始 release PR 前需确认:

  • CHANGELOG.en-US.md 已经有目标版本条目;
  • CHANGELOG.zh-CN.md 已经有对应的中文条目;
  • changelog 文案已经过筛选与格式整理。

如果这些内容还不存在,先走 changelog-collect 流程,不要在发版 skill 中临时生成。

第 3 步:更新发布文件

发布准备通常只应检查并更新这三个文件

  • CHANGELOG.en-US.md
  • CHANGELOG.zh-CN.md
  • package.json

对这三个文件有硬性要求:

  1. 中英文 changelog 必须已经存在且内容对齐;
  2. 新增 section 标题必须与目标版本完全一致,例如 ## 6.6.3
  3. 必须有日期行,且日期应接近当前发布日期,格式为反引号包裹的 2026-03-31 形式;
  4. package.json 中的版本号必须与 changelog 中的版本一致。

除非明确要求,否则不要额外引入别的 release 元数据文件——发版 PR 保持最小 diff。

这一“版本号与 changelog 必须匹配”的规则在发布前会被脚本强制校验。scripts/check-version-md.ts 的逻辑(见 scripts/check-version-md.ts#L32-L63):

  • 先校验 package.jsonversion 是否符合 x.y.z 语义化格式,预发布版本(带 -alpha. / -beta. / -rc. 等后缀)会直接跳过检查;
  • CHANGELOG.en-US.md 中查找与当前版本完全匹配## {version} section,找不到即 exit(1) 报错 “No changelog found for the version to be released”;
  • 找到后,取该 section 的第一行作为日期行,要求它是反引号包裹的日期,且距离当前时间 ±2 天以内date.isBetween(dayjs().add(-2, 'day'), dayjs().add(2, 'day'))),否则报 “The date wrongly written”。

这解释了为什么 changelog 的日期行不能随便写旧日期——它会被脚本当成发布时效性校验的一部分。

第 4 步:提交前校验

至少运行:

npm run lint:changelog

必要时再运行:

npm run version

两条命令的实际行为可从 package.json 的 scripts 字段确认:

  • lint:changelog 对应 tsx scripts/generate-component-changelog.ts。从 scripts/generate-component-changelog.ts 源码看,它会解析中英文 changelog,把每个条目按组件名归类(如 InputGridMessage 等),并额外匹配 Global:MISC: 等杂项关键字;如果某一行既不属于任何组件、也不属于 misc 关键字,脚本会打印 🚨 Miss Component: ... 并抛出 Component changelog miss match! 错误(见 scripts/generate-component-changelog.ts#L228-L249)。这意味着 changelog 文案中组件名称的书写方式直接决定 lint 能否通过。
  • version 对应 tsx scripts/generate-version.ts,它只做一件事:把 package.json 的版本号写入 components/version/version.ts(生成 export default 'x.y.z';)。它只在需要刷新本地生成的版本文件、做校验时才运行——不要把无关的生成文件顺手带进 release PR,除非仓库本来就预期它们会被更新。

发布前还可以直接运行 tsx scripts/check-version-md.ts 来做上文提到的版本-changelog 一致性校验。

第 5 步:提交与 PR 规范

release 准备 PR 的标题通常形如:

  • docs: add changelog for 6.3.5
  • docs: release 6.3.5

硬性规范有四点:

  1. 如果 PR 标题里包含 releasechangelog,就必须带上版本号——这一点由 CI 强制。.github/workflows/verify-package-version.yml 在所有 PR 的 opened / edited / reopened / synchronize / ready_for_review 事件上触发,且仅当标题包含 changelogrelease 时生效(if: contains(...) 条件,见 verify-package-version.yml#L20),使用 actions-cool/verify-package-version 校验 title-include-content: docstitle-include-version: true,不通过会直接在 PR 上评论;
  2. PR 标题保持英文;
  3. 创建 PR 时必须使用仓库官方模板 PULL_REQUEST_TEMPLATE.md,其中 “📝 Change Log” 一节要求按 Keep a Changelog 的口径,分别填写中英文两栏 changelog 文案;
  4. 生成 PR body 时保留模板原有 section,简要说明本次发布范围即可——changelog 类 PR 的正文可以简洁,因为详细内容已经写在 changelog 文件里。

正式发布流程:PR 合并之后

这部分只在 release PR 已经合并、且明确要求“现在发布”时才执行。发布前必须逐项确认:

  1. 当前分支已经切到合并后的目标分支,通常是 master
  2. 工作区是干净的;
  3. 远端分支已同步到最新;
  4. package.json 中的版本号已经是目标发布版本;
  5. CHANGELOG.en-US.md 中存在该版本的 changelog 条目;
  6. CHANGELOG.zh-CN.md 中存在对应的中文条目。

执行发布命令

npm publish

package.json 中,prepublishOnly 指向 tsx ./scripts/pre-publish.tspostpublish 指向 tsx scripts/post-publish.ts(见 package.json#L71package.json#L76),因此一条 npm publish 背后实际串起了完整的自动化链。

prepublishOnly 阶段:pre-publish.ts 做了什么

scripts/pre-publish.ts 源码可以确认发布前的完整调用链:

  1. 仓库状态检查checkRepo(),实现在 scripts/check-repo.ts):
    • checkVersionscripts/check-repo.ts#L18-L44):查询 registry.npmmirror.comregistry.npmjs.org 两个注册表,若 package.json 中的版本已存在,立即报错 “Current version already exists. Forget update package.json?”——这是防止重复发版的最后一道闸;
    • checkBranch:正式版本必须位于 master 分支(-alpha. / -beta. / -rc. / -experimental. 版本跳过该检查);
    • checkCommit:git 工作区必须干净,有未提交文件直接退出;
    • checkRemote:远端必须是 ant-design/ant-design,防止在 fork 仓库上误发布;
    • checkToken:要求设置 GITHUB_ACCESS_TOKEN 环境变量。
  2. 同步远端:对当前分支执行 git pull + git push,确保本地与远程一致(scripts/pre-publish.ts#L109-L115)。
  3. 远程 CI 状态检查:通过 Octokit 查询目标 SHA 的 combined status,failure / pending / 非 success 一律 process.exit(1) 终止发布(scripts/pre-publish.ts#L130-L171)。除非显式设置 SKIP_CI_CHECK 环境变量,否则这一步不可绕过(脚本头部注释给出用法:SKIP_CI_CHECK=1 npm run prepublishOnly)。
  4. 清理与下载构建产物:先执行 clean,然后并发地从两个来源拉取与目标 SHA 对应的构建产物(scripts/pre-publish.ts#L177-L258):
    • GitHub:定位该 SHA 上成功的 ✅ test workflow run,下载名为 build artifacts 的 artifact 为 artifacts.zip
    • OSS:按 https://antd-visual-diff.oss-accelerate.aliyuncs.com/{sha}/oss-artifacts.zip 的地址下载。 两者通过 Promise.any 竞速,任一成功即可;全部失败则提示“请确认你当前 {sha} 位于 master 分支中”并退出。
  5. 产物自检:解压后依次运行 test:dekko(包结构检查)与 test:package-diff(包内容 diff 检查),通过后才发送“产物已经准备好了,快回来输入 npm 校验码了”的系统通知。

postpublish 阶段:tag 推送与 conch 版本

npm publish 成功后,postpublish 钩子执行 scripts/post-publish.ts

  1. 推送 Git taggit tag --no-sign {version} 并推送到远端(scripts/post-publish.ts#L35-L49)。--no-sign 是刻意的——即使本地配置了 tag.gpgSign,也保持轻量 tag,避免卡在签名编辑器上。这正是发版文档强调“不要在 publish 前手动创建或推送版本 tag”的原因:tag 完全由 postpublish 统一处理;
  2. 选择并更新 conch 版本:脚本从 npm 注册表拉取最近 30 个正式发布版本,结合 BUG_VERSIONS.json 过滤掉已知有缺陷的版本(标记 🚨),按“发布满 15 天、且与相邻版本间隔超过 3 天视为稳定”的启发式算法给出默认推荐,然后交互式地执行 npm dist-tag add antd@{conchVersion} conch-v6scripts/post-publish.ts#L163-L167)。

tag 触发下游工作流

tag 推送后,tag 创建事件(on: createref_type == 'tag')触发 release-dingtalk.yml,由 actions-cool/release-helper 基于 CHANGELOG.en-US.mdCHANGELOG.zh-CN.md 自动生成 GitHub Release,并向钉钉群推送发布通知。至此完成“npm publish → tag → GitHub Release + 群通知”的闭环。

不要做的事

以下几条是发版流程中的明确禁区:

  • 不要使用 npm run pubpackage.json#L75 中该脚本被显式定义为 echo 'Please use \npm publish` instead.',仓库已经用脚本本身提示应使用 npm publish`;
  • 不要在 publish 前手动创建或推送版本 tag:tag 由 postpublish 钩子统一推送,手动创建会破坏 tag 命名与推送时机的一致性;
  • changelog 或版本号缺失时不要直接发布check-repo.ts 会拦截重复版本,check-version-md.ts 会拦截版本与 changelog 不一致的情况,绕过校验直接发布只会把问题带到线上。

发版操作清单(Checklist)

按 skill 文档中“Agent 执行动作”一节整理的端到端清单:

  1. 检查当前分支、版本号和最近 tags(git branch -vvgit tag --list);
  2. 根据目标分支与发布目标判断 patch 还是 minor;
  3. 确认 changelog 已由 changelog-collect 或用户提前准备好(中英文条目对齐、section 标题与日期行合规);
  4. 更新 package.json 中的 version 字段;
  5. 运行 npm run lint:changelogtsx scripts/check-version-md.ts 校验;
  6. 用带版本号的 docs: 标题提交,按 PULL_REQUEST_TEMPLATE.md 以正确的 base 分支(masterx.x-stable)创建 PR;
  7. 只有在 PR 合并后、且明确要求时,才执行 npm publish——如果任务只是“准备 release PR”,创建 PR 后就应停止,不要继续执行发布。

适用前提与限制

  • 本文描述的是当前仓库(antd 6.x,package.json 版本 6.6.2)的实际发布机制;维护分支(如 5.x-stable4.x-stable)发版时分支规则略有不同,但“release PR + npm publish + postpublish 推 tag”的主干流程一致;
  • npm publish 需要 GITHUB_ACCESS_TOKEN 环境变量与可访问 ant-design 官方仓库的权限,SKIP_CI_CHECK 仅用于确需跳过远程 CI 检查的特殊场景;
  • 构建产物必须已由远端 CI 生成(GitHub artifact 或 OSS),本地 prepublishOnly 不会自行构建——这也是“产物必须来自合并后的 master SHA”这一前提的来源。
登录后查看全文
热门项目推荐
相关项目推荐