Carbon Design System 版本发布全流程解析:从 prerelease 到 stable 的时间驱动发布指南
【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon
本文以 IBM Carbon Design System 仓库(monorepo)中的 docs/release.md 为核心,系统讲解其时间驱动的版本发布模型:包括每两周一次的minor稳定版、提前数日发布的preminor/prerelease候选版,以及按需发布的patch安全与缺陷修复版。你将掌握完整的手动发布操作序列(Version Workflow → 打 tag → Release Workflow → npm dist-tag 提升)、v10 旧版本维护流程、手动 patch 发布方法,以及常见故障的排障手段;同时本文结合仓库内 .github/workflows/version.yml、.github/workflows/release.yml、actions/promote/index.js、lerna.json 等源码与配置,深入解释每个步骤背后的自动化原理。
发布模型概述:为什么是"时间驱动"
Carbon Design System 采用**时间驱动(time-based)**而非"攒够功能再发"的发布模型,规则非常简单:
- 每两周发布一个稳定的
minor版本,例如v11.2.0。完整的发布节奏记录在项目的 Release Radar 发布日历中。 - 每次
minor发布前几天,先发布一个 prerelease(预发布版)。这个版本提供了一个集成窗口(integration window),让产品团队在稳定版正式发布前,能够提前集成并验证这些改动。 patch版本按需发布,用于承载安全修复和缺陷修复,不遵循固定排期。
这一模型的核心价值在于:既保证了发布节奏的可预期性(每两周一次 minor),又通过 prerelease 给下游产品留出充分的测试缓冲,从而降低稳定版发布引入破坏性变更的风险。
发布团队:release lead 与 sidekick
每一周的发布由**发布团队(Release Team)**协调完成,团队由两名成员组成:
- Release lead(发布负责人):负责管理发布本身,包括测试(Testing)、发布(Publishing)、支持(Support)三大环节,并在适当时候指导 sidekick 理解并跑通整个发布流程。
- Release sidekick(发布搭档):如果是第一次进入发布团队,首要任务是学习如何运行发布流程;同时协助 lead 完成测试、发布、支持等各项工作。
两人配合共同保证发布流程的稳定执行,也起到知识传递的作用。
发布流程总览:四个检查点
一次完整的发布周期包含四个检查点:
| 检查点 | 说明 |
|---|---|
| Prerelease(预发布) | 发布一个预发布版,用于在稳定化之前测试发布候选 |
| Stable release(稳定发布) | 将 prerelease 提升为稳定版,通过 npm 包对外可用 |
| Post release(发布后) | 为最新稳定版提供支持,处理因提升到稳定版而产生的问题 |
| Previous release(旧版本发布) | 判断 v10 是否有新改动需要发布,如有则发布(v10 已于 2024-09-30 停止支持) |
下面按检查点逐一展开实际操作步骤,并标注每一步背后对应的自动化配置。
Prerelease 预发布流程
预发布发生在每个 sprint(迭代)的最后一个周一。此时发布团队需要执行以下操作:
- 手动触发 Version Workflow(对应仓库中的 .github/workflows/version.yml),让 Lerna 自动为所有包生成预发布版本号。该工作流通过
workflow_dispatch暴露了两个必填输入(见 .github/workflows/version.yml#L8-L23):type:发布类型,可选值为minor、preminor、prerelease,默认preminor;tag:本次发布对应的 tag 名称,例如v11.2.0-rc.0。
- 指定
preminor作为发布类型;如果是发布下一个 prerelease,则指定prerelease。 - 提供本次发布的 tag。例如上一个版本是
v11.1.0,那么本次预发布的 tag 就是v11.2.0-rc.0(可用仓库 tags 列表确认上一个版本的 tag)。 - 审查并批准该工作流自动生成的 Pull Request。该 PR 由
peter-evans/create-pull-request动作创建,分支名为release/<tag>,提交信息与标题均为chore(release): <tag>(见 .github/workflows/version.yml#L68-L82)。 - 等待 PR 被合并(文档中明确用 🛑 强调此步骤不可跳过)。
- 合并后,将上游最新代码拉取到本地:
git checkout maingit pull upstream main- 运行
git log查看最近的提交,验证最新提交就是 PR 的发布提交。发布提交的格式为:
chore(release): v11.2.0-rc.0如果不是该提交,说明 PR 尚未合并,等待合并后重新拉取。按q退出日志。
- 给发布提交打上注释 tag,并推送到
upstream:
git tag -a v11.2.0-rc.0 -m 'v11.2.0-rc.0'git push upstream v11.2.0-rc.0- 验证推送 tag 是否触发了Release Workflow的运行(见 .github/workflows/release.yml)。该工作流监听
v*格式的 tag 推送事件(!v10*被排除,v10 有独立的 v10-release.yml)。
源码解读:Version Workflow 如何生成版本号
从 .github/workflows/version.yml#L50-L61 可以看到,三种发布类型对应三条 Lerna 命令:
# preminor:从当前稳定版生成下一个 minor 的 RC 版本,如 v11.1.0 -> v11.2.0-rc.0 yarn lerna version preminor --no-git-tag-version --preid rc --yes # prerelease:在既有 RC 基础上递增,如 v11.2.0-rc.0 -> v11.2.0-rc.1 yarn lerna version prerelease --no-git-tag-version --preid rc --yes # minor:正式升版,如 v11.2.0-rc.0 -> v11.2.0 yarn lerna version minor --no-git-tag-version --no-push --yes关键点在于--preid rc:它把预发布标识符固定为rc,使 Lerna 生成的版本形如v11.2.0-rc.0。同时--no-git-tag-version与--no-push表示本阶段只修改包版本号、不创建 tag 也不推送,tag 由发布团队在 PR 合并后手动创建,从而保证"版本号变更"与"tag 标记"两个动作解耦。仓库根目录的 lerna.json 配置了"version": "independent"(每个包独立版本号)、"npmClient": "yarn",以及提交信息模板"chore(release): %s";它还通过ignoreChanges排除了actions/**、**/docs/**、**/e2e/**、**/*.md等目录,避免文档或测试改动误触发版本号变更。
再次发布下一个 prerelease
当一个 prerelease 发布后,如果需要发布后续的候选版(例如从v11.12.0-rc.0到v11.12.0-rc.1),重复上述 Prelease 步骤,但发布类型改为prerelease而不是preminor。
Stable release 稳定发布流程
稳定发布发生在最后一个周三,并在当天稍晚完成。它必须发生在 prerelease 已经过测试和验证之后。流程如下:
- 手动触发Version Workflow:
- 指定
minor作为发布类型; - 提供本次发布的 tag。例如上一个版本是
v11.1.0-rc.0,则本次 tag 为v11.1.0。
- 指定
- 审查并批准工作流自动生成的 PR。
- 🛑等待 PR 被合并。
- 合并后拉取上游最新代码:
git checkout maingit pull upstream main- 运行
git log验证最新提交是发布提交(格式如chore(release): v11.10.0),按q退出。 - 给发布提交打 tag 并推送:
git tag -a v11.2.0 -m 'v11.2.0'git push upstream v11.2.0- 验证推送是否触发了Release Workflow的运行。
Release Workflow 做了什么
推送v*tag 后,.github/workflows/release.yml 会被触发,它做四件关键的事:
- 构建与质量门禁:安装依赖、构建项目、构建 Storybook 并启动本地服务、运行 Playwright AVT(无障碍自动化测试,
--grep @avt)、执行yarn ci-check等,确保发布产物质量达标。 - 以
nextdist-tag 发布到 npm:执行yarn lerna publish from-package --dist-tag next --no-verify-access --yes(见 .github/workflows/release.yml#L68-L71)。注意发布是落到next标签上,而不是直接进latest。 - 自动提升到
latest:packages任务(needs: build)仅在 tag不包含-rc时执行(if: contains(github.ref_name, '-rc') == false),它调用仓库内置的 actions/promote 动作,把所有已变更包的 npm dist-tag 从next提升为latest。这正是文档中"自动将带新版本号的 Carbon 包提升到 latest"的实现来源。 - 创建 GitHub Release:通过
github.rest.repos.createRelease为当前 tag 创建 Release 记录,并默认标记为 prerelease。
Promote 动作的内部逻辑
actions/promote/index.js 的实现细节值得展开:
- 它递归遍历所有 workspace,跳过
private字段为 true 的包; - 存在一个 denylist:
carbon-components与@carbon/icons-vue不会被自动提升(见 actions/promote/index.js#L14),这与文档中"手动 patch 发布时不要对 carbon-components 执行 dist-tag 提升"的提醒完全对应; - 对每个包,它查询 npm registry 的
dist-tags.latest,若与当前版本不一致,就执行npm dist-tag add <name>@<version> latest(支持DRY_RUN参数,见 actions/promote/action.yml); - 完成后在 Actions summary 中输出每个包的 Previous / Latest 对比表。
发布后的收尾动作
Release Workflow 成功后,发布团队还需完成:
- 验证包已在 npm 上提升到
latest(例如检查@carbon/react)。 - 用 Carbon CLI 生成 changelog 并更新最新 Release 的说明。在 monorepo 根目录执行:
./packages/cli/bin/carbon-cli.js changelog v11.5.0..v11.6.0changelog命令位于 packages/cli/src/commands/changelog.js:它会先从 upstream 拉取最新 git 信息、获取 workspace 内所有包,然后按<range>(如v11.5.0..v11.6.0)解析起止 tag,为范围内每个包生成 changelog,并询问是否复制到剪贴板(可用-n/--noPrompt跳过交互)。 3.在 GitHub Release 页面上取消勾选 "this is a prerelease",将发布正式标记为稳定版。 4.在 Slack 中发布发布公告,渠道包括#carbon-announcements、#carbon-design-system、#carbon-react、#carbon-web-components。
文档还提供了一份可直接复用的 Slack 公告模板(Markdown 版与 Block Kit Builder 版),核心结构为:版本号链接 + 本次更新要点列表 + 引导用户查看 Release Radar + 反馈渠道 + 致谢。
更新 gatsby-theme-carbon 与 carbon-website
稳定版 Release Workflow 完成后,会自动触发deploy-packages工作流(通过repository_dispatch的deploy-packages事件,见 .github/workflows/release.yml#L102-L105),对应的 .github/workflows/deploy-packages.yml 会分别在design-language-website与gatsby-theme-carbon两个仓库中自动升级 Carbon 依赖并打开 PR。后续操作:
- 审查、批准并合并
gatsby-theme-carbon仓库中由该动作生成的 PR,确认本次发布没有破坏性变更。如果上一轮发布的 PR 尚未合并,已有 PR 会被自动更新。 - 在
gatsby-theme-carbon仓库运行release-it工作流,触发gatsby-theme-carbon自身的发布。 - 检查
gatsby-theme-carbon是否已发布、其版本是否基于最新 Carbon。 - 运行 Carbon 官网(carbon-website)仓库的 "Update Carbon and gatsby-theme-carbon deps" 工作流,自动打开更新依赖的 PR。
- 审查并批准该 PR。
Post release:发布后的支持与问题响应
发布后需要:
- 更新 Release Radar 发布日历页面,记录本次发布的实际情况。
- 密切监控 Slack 渠道与 GitHub issues:因为包从
next切到latest后,可能暴露此前未发现的破坏性变更。
针对不同的问题类型,文档给出了两条典型的处理策略:
- Hotfix(热修复):如果问题自包含、可以快速解决,走一次 patch 发布是最直接的解决方式;
- Revert to previous stable release(回滚到上一稳定版):如果问题无法快速修复、或修复时间不可控,回滚到上一个稳定版是更稳妥的选择。
Manual Patch Release:手动补丁发布
当需要做一次计划外的(off-cycle)补丁发布、修复上一个版本中意外引入的缺陷时,按以下步骤执行(这也是理解 Lerna 手动版本控制的最佳实操案例):
- 进入本地 monorepo,先同步最新状态:
git fetch upstream- 检出要打补丁的目标 tag(通常是最新发布 tag):
git checkout vX.Y.Z- 基于该 tag 创建新分支,分支名使用"目标发布版本号",即当前版本号递增
+0.0.1(补丁位):
git checkout -b release/vX.Y.Z- 把希望纳入补丁的提交(hotfix)cherry-pick 进来:
git cherry-pick ######运行
git log,验证最新提交依次是:tag 对应的发布提交 + cherry-pick 进来的提交,然后按q退出。用 Lerna 为自上次版本以来有变更的包统一升 patch 版本:
yarn lerna version patch --no-git-tag-version --no-push --yes- 检查变更文件,确认所有受影响的包版本都只增加了
+0.0.1(patch 位)。 - 运行
yarn install更新依赖锁。 - 确认此刻所有文件变更只涉及
package.json和yarn.lock,不应有其他文件被改动。 - 提交并推送:
git add -Agit commit -m 'chore(release): vX.Y.Z'git push --set-upstream origin release/vX.Y.Z- 用该分支创建 PR:
base分支设为main,标题为chore(release): vX.Y.Z,描述写明包含的 hotfix 提交。 - 关闭这个 PR(不合并),并在关闭时注明:这是手动发布,该 PR 仅用于在 GitHub 历史中记录发布,无需合并。
- 给发布提交打 tag 并推送到 upstream:
git tag -a vX.Y.Z -m 'vX.Y.Z'git push upstream refs/tags/vX.Y.Z- 验证推送触发了 Release 工作流并成功,且包以
nexttag 发布到 npm。 - 如果版本号正确,手动把受影响的包提升到
latest。注意:- 不要对
carbon-components包执行此操作(与 actions/promote/index.js 中的 denylist 一致); - 必须使用每个包各自生成的具体版本号,而不是 GitHub 上的发布 tag;
- 建议以
carbon-bot身份登录 npm CLI,避免鉴权问题。
- 不要对
- 对每个包执行(将
carbon-components-react替换为实际包名):
npm dist-tag add carbon-components-react@vX.Y.Z latest- 验证 npm 上包已提升到
latest。 - 在 monorepo 根目录用 Carbon CLI 生成 changelog 并更新 Release 说明:
./packages/cli/bin/carbon-cli.js changelog vA.B.C..vX.Y.Z值得一提的是,仓库还提供了对应的自动化补丁工作流.github/workflows/version-patch.yml:它接受tag、existing-tag以及最多 5 个待 cherry-pick 的提交 SHA(commit-1至commit-5),自动完成"检出既有 tag → 创建 release 分支 → cherry-pick →lerna version patch→ 提交 → 打 tag 并推送"的全过程,可以作为手动流程的参考实现。
Previous releases(v10):旧版本维护流程
从 2022 年 3 月 v11 首发,到2024 年 9 月 30 日,Carbon 一直对上一个主版本(v10)提供维护支持。v10 在此期间只在被请求时接收缺陷修复,以及关键安全更新。所有 v10 代码与资源已在 2024 年 9 月 30 日停止支持(End of Support)。
文档明确注明:以下 v10 发布流程相关内容仅出于留档(posterity)目的保留,应在下一个主版本发布时从文档中移除。本仓库中对应的自动化工作流 .github/workflows/v10-version.yml 与 .github/workflows/v10-release.yml 至今仍保留,供理解历史机制参考。
如何判断 v10 是否需要发布
- 打开仓库的 compare 页面;
- 在 "base" ref 下拉框的 "tags" 标签页中,选择最近的
v10.xtag; - 在 "compare" ref 下拉框中选择
v10分支; - 查看 diff:
- 如果 diff 为空,说明 v10 无需发布;
- 如果包含一串提交,说明需要发布新的
v10.x版本。
同时检查以v10为 base 的 PR 队列——可能存在已打开、等待合并、可纳入本次发布的 PR。
发布 v10 旧版本
- 进入本地 monorepo,检出 v10 分支并同步:
git checkout v10git pull upstream v10 --tags- 创建 release 分支:
git checkout -b release/vX.Y.Z- 安装依赖并确保工作区干净(
git status)。 - 运行 Lerna 为有变更的包升 patch 版本:
yarn lerna version patch \ --no-push \ --no-git-tag-version- 仔细核对版本增量:作为 patch 发布,不应包含破坏性变更(如
v10.14.0 → v11.0.0),也不应包含 minor 变更(如v10.59.1 → v10.60.0)。确认无误后按y继续。 - 快速校验:运行
yarn install --immutable确认所有版本已正确递增(有时需要手动更新根目录package.json)。 - 运行
yarn install,提交并推送:
git add -Agit commit -m 'chore(release): vX.Y.Z'git push --set-upstream origin release/vX.Y.Z- 创建 PR:
base分支设为v10,标题chore(release): vX.Y.Z。 - 🛑 等待 PR 合并后,拉取最新代码并验证最新提交是发布提交(如
chore(release): v10.59.1)。 - 打 tag 并推送:
git tag -a vX.Y.Z -m 'vX.Y.Z'git push upstream vX.Y.Z- 验证推送触发了 release 动作,且包以
v10-nexttag 发布到 npm(v10 使用独立的 v10-release.yml,其发布命令为yarn lerna publish from-package --dist-tag community --no-verify-access --yes,发布到communitydist-tag)。 - 在 monorepo 根目录生成 changelog:
./packages/cli/bin/carbon-cli.js changelog vA.B.C..vX.Y.Z为单个包发布新 major
某些情况下,monorepo 中单个包需要 major 版本升级,而不需要全仓库统一升 major。例如:eslint-config-carbon需要新 major,而其他包只升 patch,且仓库 tag 保持在当前 major(v11.x)不变。
操作方式为手动版本控制:
- 切到
main并git pull upstream main拉取最新; - 创建版本分支,如
git checkout -b release/v11.23.1; - 运行
yarn lerna version --no-git-tag-version --no-push; - 在交互式提示中为每个包选择合适的版本增量;如果某个包不需要变更版本,选择Custom Version并输入其现有版本号保持不变;
- 交互完成后运行
yarn install更新yarn.lock; - 提交
chore(release): v11.23.1,推送并打开 PR; - 合并后,从"🛑 等待 PR 被合并"这一步开始,走 Stable release 的后续流程:打 tag 并触发自动化发布工作流。
Troubleshooting:常见故障排障指南
Version 工作流成功但 PR 未创建
查看工作流日志——很可能是Lerna 没有检测到需要发布的变更。这种情况常发生在:自最近一个 tag 发布以来,main分支没有新增内容。合并一个 PR 后重新运行工作流(不要重跑上一次)即可解决。
Version 工作流失败
如果 Version 工作流失败且无法定位原因,只要你有仓库的 push 权限,就可以在本地按工作流文件中的命令手动执行:
- 在干净的工作区拉取
main最新代码并创建release/vX.Y.Z分支:
git checkout maingit pull upstream maingit checkout -b release/vX.Y.Zyarn installyarn build- 依次执行 version.yml 中的其余命令(
yarn build、yarn lerna ...、yarn install等)。 - 提交并推送到 PR,此时你与"Version 工作流成功"处于同一进度:
git add .git commit -m "chore(release): vX.Y.Z"git pushRelease 工作流失败
同理,只要有仓库 push 权限和 npm 发布权限,可以在本地复现:
- 拉取对应 tag:
git checkout vX.Y.Z; - 按 release.yml 中的命令顺序依次执行;
- 成功后,手动为对应 tag 创建 GitHub Release,并附上生成的 changelog。
收到 unpkg 链接失效的报告
这类问题通常是 unpkg 的默认行为导致的:https://unpkg.com/carbon-components/*会解析为latesttag 对应的版本。如果latesttag 被误打到了v11.x版本上,使用非版本化 unpkg 链接的用户就会解析到 v11 包——而 v11 包不再包含编译后的样式表,从而出现样式丢失。
修复方法是:把latesttag 重新指回v10.x:
npm dist-tag add carbon-components@10.X.Y latest建议以carbon-bot身份登录 npm CLI 以避免鉴权问题。同时应引导用户养成给包名追加版本号前缀的习惯,确保 unpkg 始终解析到最新的 v10 版本:
https://unpkg.com/carbon-components@10/css/carbon-components.min.css https://unpkg.com/carbon-components@10/scripts/carbon-components.min.js手动部署 v10 Storybook 时,v11 的 Storybook 被发布到了 v7-react 站点
原因是对应的部署工作流必须从v10分支运行:手动触发时,务必在分支下拉框中选择v10,而不是默认分支,否则产物会发布到错误的域名。
结语:一条贯穿"自动化 + 人工把关"的发布链路
纵观整个发布流程,Carbon 的发布体系呈现出清晰的"自动化为主、人工把关为辅"的设计:Version Workflow 负责批量生成版本号与 release PR,Release Workflow 负责构建、测试、以next发布并自动提升到latest,Promote 动作内置了包名 denylist 防止误提升,deploy-packages通过repository_dispatch联动下游网站仓库;而人工环节(审查 PR、验证发布提交、打 tag、更新 changelog、发公告)则构成了质量与合规的最后一道防线。理解这条链路,无论是为 Carbon 贡献代码、维护自己的 monorepo 发布体系,还是排查发布问题,都能做到心中有数、按图索骥。
【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考