Sentry JavaScript SDK 版本发布全流程指南:从 Changelog 到 CI 自动发布与 Gitflow 分支同步
Sentry JavaScript SDK 版本发布全流程指南:从 Changelog 到 CI 自动发布与 Gitflow 分支同步
本文以 Sentry JavaScript SDK(sentry-javascript)官方发布流程文档为骨架,系统讲解该仓库从日常开发到正式发布一个 SDK 版本的完整操作路径:如何在 develop 分支上生成并整理 Changelog、如何以 prepare-release/VERSION 分支触发自动发布、如何针对历史大版本与 alpha/beta 预发布版本手动执行 Release 工作流,以及发布后 master 回同步 develop 的 Gitflow 机制。读完本文,你将掌握该仓库(以及采用了类似 Craft 发布体系的 Sentry 系列仓库)的版本号决策、Changelog 撰写规范、CI 自动发布触发条件与手动发布兜底方案,能够独立完成一次标准的 SDK 版本发布。
背景:sentry-javascript 的发布体系概览
sentry-javascript 是一个包含 @sentry/browser、@sentry/node、@sentry/nextjs 等数十个 npm 包与 CDN 产物的大型 monorepo(仓库根目录下的 package.json 声明了所有工作区脚本)。版本发布并非手工逐包打包上传,而是围绕 Craft(Sentry 自研的开源发布工具链)与 GitHub Actions 构建的一套半自动流水线:
- 日常开发、功能与 Bug 修复的 PR 统一合入
develop分支; - 发布时把
develop合并到master,由 .github/workflows/auto-release.yml 自动准备发布; - 针对历史大版本分支(如
v8)或预发布版本(如9.7.0-alpha),通过 .github/workflows/release.yml 手动触发发布; - 发布完成后,.github/workflows/gitflow-sync-develop.yml 自动创建
master -> develop的同步 PR,保证两个分支的版本信息一致。
本文主体依据官方文档 docs/publishing-a-release.md 展开,并补充了仓库内工作流文件、scripts/generate-changelog.ts、.craft.yml 等源码证据,帮助你理解每一步背后的实现原理。
注意:文档开篇明确说明,这些步骤仅对 Sentry 员工在准备和发布新 SDK 版本时适用("These steps are only relevant to Sentry employees")。因此本文面向的是该仓库的维护者/发布者角色;外部贡献者只需了解流程,无权触发发布。
发布前的准备:理解 Gitflow 分支模型
要正确执行发布流程,必须先理解仓库采用的 Gitflow 分支模型,详见 docs/gitflow.md:
- 所有日常工作发生在
develop分支上,功能、修复类 PR 都合入develop; - 准备发布时,将
develop合并进master,在master上发布,随后再把master合并回develop; master上的内容可视为 SDK 的上一次已发布状态;禁止直接向master合入(紧急 Bugfix 发布除外)。
一个关键约束是:在发布进行期间,可以往 develop 合入任何内容,唯独不能修改 package.json 文件。因为发布过程中 Craft 会在 master 上更新各包的 package.json(版本号),如果 develop 也改了这些文件,master -> develop 的 Gitflow 同步 PR 就会产生合并冲突。
如果发布后同步 PR 仍然出现合并冲突,docs/gitflow.md 给出的解决方案是:关闭自动化 PR → 在 master 之上新建分支(如 manual-develop-sync)→ 用 merge commit 把 develop 合并进来并解决冲突 → 再向 develop 提 PR 并同样以 merge commit 合并。
主线发布流程:prepare-release 自动发布(8 步)
以下是从 docs/publishing-a-release.md 第一节整理出的主线发布步骤,适用于在 develop 上发布的当前大版本:
Step 1:在 develop 分支运行 yarn changelog,确定要发布的版本号
yarn changelog
该命令实际执行的是 tsx ./scripts/get-commit-list.ts(见根目录 package.json)。脚本通过 git log --format="- %s" 拉取提交列表,定位到最近一条 meta(changelog) 提交作为上一次发布点,取出其后的所有新提交;过滤掉 Merge pull request、Merge branch 与 release: 类提交后按字母序排序,并把 PR 编号 #123 自动替换为指向对应 PR 的链接(见 scripts/get-commit-list.ts)。
版本号遵循 semver 语义化版本规范,决策原则是:
- 包含新功能(feature)→ 递增 minor 版本,例如
8.2.0; - 仅包含 Bug 修复 → 递增 patch 版本,例如
8.1.1; - 含破坏性变更 → 递增 major 版本。
Step 2:基于 develop 创建发布准备分支
git checkout develop
git checkout -b prepare-release/VERSION
# 例如:git checkout -b prepare-release/8.1.0
分支名必须严格遵循 prepare-release/<版本号> 的格式,因为自动发布工作流正是靠解析这个分支名来提取版本号的(见下文 Step 6 的源码解析)。
Step 3:更新 CHANGELOG.md,为下一个版本号新增条目
在 Changelog 中为将要发布的版本添加一个章节,并列出自上次发布以来的所有变更(详细规范见本文"Changelog 撰写规范"一节)。
Step 4:提交 PR
PR 标题固定为:
meta(changelog): Update changelog for VERSION
(例如 meta(changelog): Update changelog for 8.1.0),目标分支为 master。
Step 5:⚠️ 谨慎操作 —— 合入方式必须是 "Merge Commit"
合并 prepare-release 分支到 master 的 PR 必须使用 Merge Commit(合并提交)方式合入,而不是 Squash and Merge。这是为了让 prepare-release/8.1.0 分支上的所有提交(含 changelog 提交本身)都原样保留在 master 的历史中,从而被 auto-release 工作流正确识别。
Step 6:PR 合并后自动触发 Auto Prepare Release
PR 合入 master 后,.github/workflows/auto-release.yml 随即被触发。该工作流在 pull_request 事件类型为 closed 且分支为 master 时启动,核心逻辑如下:
- 使用 Sentry Release Bot 的 GitHub App token 检出代码(
fetch-depth: 0); - 用正则
^prepare-release\/(\d+\.\d+\.\d+)(?:-(alpha|beta|rc)\.\d+)?$匹配 head 分支名,从中提取版本号(该正则可以识别prepare-release/8.1.0,也能识别带-alpha.1、-beta.1、-rc.1后缀的预发布版本号); - 在
github.event.pull_request.merged == true且版本号非空的前提下,调用getsentry/craftaction(v2.30.1)执行发布准备,参数为version: <提取的版本号>、merge_target: master、craft_config_from_merge_target: true。
换言之,只要合入 master 的分支名符合 prepare-release/<版本> 模式,版本号就会被自动解析并交给 Craft 准备发布。
Step 7:在 Sentry 的发布跟踪仓库出现新 issue
发布准备开始后,会自动在 getsentry/publish 仓库中创建一个新 issue,用于跟踪本次发布的 CI 状态与审批进度(issue 中会附带 CI 检查运行的链接)。这属于 Sentry 内部基础设施,外部贡献者无法访问。
Step 8:等待 CI 通过并打上 accepted 标签
- 等待 issue 中链接的 CI 检查全部运行成功(包括各包的构建、测试与 tarball 产物检查);
- 在 issue 上设置
accepted标签,批准本次发布; - 发布完成后,
master -> develop的自动同步会被触发(详见本文"发布后的 Gitflow 同步"一节)。
历史大版本与预发布(alpha / beta)版本的发布流程
主线流程只覆盖在 develop 上发布当前大版本。如果需要为上一个主版本分支(例如 v8)或预发布版本分支(例如 9.7.0-alpha)发布补丁或快照版本,则走手动流程:
Step 1:在对应分支上运行 yarn changelog 确定版本
在旧分支(如 v8)或预发布分支(如 9.7.0-alpha)上运行 yarn changelog,依据 semver 确定要发布的版本(例如补丁 8.45.1,或预发布 9.7.0-alpha.1)。
Step 2:从该分支创建 changelog 分支
# 从 v8 分支创建
git checkout v8
git checkout -b changelog-8.45.1
# 或从预发布分支创建
git checkout 9.7.0-alpha
git checkout -b changelog-9.7.0-alpha.1
Step 3:更新 CHANGELOG.md,新增对应版本条目(规范同主线流程)。
Step 4:提交 PR
PR 标题仍为 meta(changelog): Update changelog for VERSION,但目标分支是对应的旧大版本分支或预发布分支(如 v8、9.7.0-alpha),而非 master。
Step 5:⚠️ 合入方式不同 —— "Squash and Merge"
与主线流程相反,针对旧分支的 changelog PR 应使用 Squash and Merge,因为该分支上的提交已存在于历史中,无需保留合并提交。
Step 6:手动触发 Prepare Release 工作流
PR 合入后,打开 .github/workflows/release.yml(名为 "Action: Prepare Release")的 workflow_dispatch 界面,填写三个输入项:
| 输入项 | 含义 | 示例 |
|---|---|---|
version |
要发布的版本号(或填 auto) |
8.45.1、9.7.0-alpha.1 |
force |
即使存在 release-blocker 也强制发布(可选) | 留空 |
merge_target |
要合入的目标分支,默认 master |
v8、9.7.0-alpha |
工作流声明了 workflow_dispatch 手动触发事件,三个输入均非必填,其中 merge_target 默认值为 master。该工作流同样通过 getsentry/craft action 执行发布,并把 version、force、merge_target 原样传给 Craft(见 .github/workflows/release.yml)。Craft 会根据 .craft.yml 中声明的 targets 逐个发布(详见下文)。
Step 7:运行发布工作流
点击 "Run workflow" 后,由 Craft 完成版本 bump、打包、发布 npm 包、上传 CDN bundle、创建 GitHub Release 与更新 Release Registry 等全部动作。
图片
docs/assets/run-release-workflow.png展示了 Release 工作流界面中填写major branch、version、major branch to merge into三个字段的示例截图,可在仓库中查看:docs/assets/run-release-workflow.png。图示对应手动工作流中的三个输入:要发布的大版本分支、要发布的版本号、要合并回的大版本分支。
Changelog 撰写规范
Changelog 是发布流程的"输入原料",其格式直接决定发布说明的呈现质量。官方文档的规范如下。
生成与搬运
# 基础生成(git 提交列表)
yarn changelog
# 最佳实践:格式化生成(推荐)
yarn generate-changelog
yarn generate-changelog 执行 scripts/generate-changelog.ts,它解析 CHANGELOG.md 中的 ## Unreleased 章节,将其中的已有条目与新提交合并、去重(按 PR 编号)、自动分类并排序,最后输出格式化后的 changelog 文本,可直接复制粘贴进新版本章节。脚本的分类逻辑(determineEntryType)如下:
- 条目首行包含
**feat或**fix→ 归入Important Changes; - 以
chore、ref、test、meta开头的提交 → 归入Internal Changes; - 其余 → 归入
Other Changes。
在 Changelog 中新增版本章节
- 运行上述任一命令并复制全部输出;
- 在 Changelog 中创建以版本号命名的章节(
## <版本号>,例如## 9.28.0); - 粘贴复制的日志内容。
章节组织规则
- Important Changes(重要变更):如果存在重要功能或修复,在
### Important Changes小标题下列出,并附上简要说明段落。例如文档示例中feat(node)条目解释了为何更新 span 名称与 op 以匹配 OpenTelemetry 约定。 - Other Changes(其他变更):使用
### Other Changes小标题收纳其余面向用户的变更。 - Internal Changes(内部变更):纯内部改动(如无用户可见影响的
ref重构、测试、chore等)放入<details>折叠块中,<summary>文本为 "Internal Changes"。- 例外:如果
ref、chore等标记的提交实际包含面向用户的变更,则应放在主 changelog 正文,而非内部变更区。
- 例外:如果
- 条目排序:所有条目按字母序排列。
- 外部贡献者致谢:如果本次发布包含外部贡献者的 PR,在提交列表下方加入一行:
Work in this release contributed by <外部贡献者GitHub用户名列表>. Thank you for your contributions!
注意语法细节:只有一个外部 PR 时用单数 contribution(去掉末尾的 s);三个及以上时使用牛津逗号(Oxford comma),例如 @alice, @bob, and @carol。
外部贡献者行的自动化来源
仓库内置了 .github/workflows/external-contributors.yml(名为 "CI: Mention external contributors"):每当非 COLLABORATOR/MEMBER/OWNER 的外部贡献者 PR 合入 develop 后,该工作流会调用 dev-packages/external-contributor-gh-action 自动把贡献者用户名追加到 CHANGELOG.md 的 ## Unreleased 章节,并创建一个标题为 chore: Add external contributor to CHANGELOG.md 的 PR。发布者在整理 changelog 时可以安全地把这行内容剪切到新版本章节中(不过官方文档也提醒:做一次人工 sanity check 永远不嫌多)。
Changelog 条目示例(来自官方文档)
## 9.28.0
### Important Changes
- **feat(nestjs): Stop creating spans for `TracingInterceptor` ([#16501](https://github.com/getsentry/sentry-javascript/pull/16501))**
With this change we stop creating spans for `TracingInterceptor` as this interceptor only serves as an internal helper and adds noise for the user.
- **feat(node): Update vercel ai spans as per new conventions ([#16497](https://github.com/getsentry/sentry-javascript/pull/16497))**
This feature ships updates to the span names and ops to better match OpenTelemetry. This should make them more easily accessible to the new agents module view we are building.
### Other Changes
- fix(sveltekit): Export `vercelAIIntegration` from `@sentry/node` ([#16496](https://github.com/getsentry/sentry-javascript/pull/16496))
<details>
<summary> <strong>Internal Changes</strong> </summary>
- ref(node): Split up incoming & outgoing http handling ([#17358](https://github.com/getsentry/sentry-javascript/pull/17358))
- test(node): Enable additionalDependencies in integration runner ([#17361](https://github.com/getsentry/sentry-javascript/pull/17361))
</details>
Work in this release was contributed by @agrattan0820. Thank you for your contribution!
当前仓库的 CHANGELOG.md 顶部即维护着一个 ## Unreleased 章节,其中已经包含 Work in this release was contributed by ... 的致谢行,这正是上述自动化机制的实时产物。
发布背后的 Craft 流水线:.craft.yml 解读
无论是自动发布还是手动发布,真正的发布动作都由 Craft 执行,其配置位于仓库根目录的 .craft.yml。理解这个文件就能知道一次发布会产出什么。关键字段:
minVersion: '0.23.1':要求最低 Craft 版本;changelog.policy: simple:changelog 策略为 simple;preReleaseCommand: bash scripts/craft-pre-release.sh:在发布前执行 scripts/craft-pre-release.sh,该脚本调用yarn install --frozen-lockfile并通过 scripts/bump-version.js 在所有工作区包中统一 bump 版本号(不创建 git tag 或 commit);targets:发布目标列表,按依赖顺序排列,例如:- npm 目标:按依赖层级依次发布
@sentry/core→@sentry/browser-utils→@sentry/browser/@sentry/node→ 框架包(@sentry/nextjs、@sentry/nuxt等),每个目标通过includeNames正则匹配 tarball 产物(如/^sentry-core-\d.*\.tgz$/),确保@sentry/core先于依赖它的包发布; - aws-lambda-layer:构建并发布 AWS Lambda Layer;
- gcs:把浏览器 CDN bundle 上传到 GCS bucket
sentry-js-sdk的/{{version}}/路径,并设置一年缓存(cacheControl: 'public, max-age=31536000'); - github:创建 GitHub Release;
- registry:更新 Sentry Release Registry 中各 SDK 的版本与(浏览器包的)sha384 checksum。
- npm 目标:按依赖层级依次发布
这也是 docs/new-sdk-release-checklist.md 中所说的"首次发布新 SDK 需在 craft.yml 中为 npm 与 registry 添加新目标"的落点。
发布后的 Gitflow 同步机制
发布完成并不代表流程结束。文档 Step 9 提到"发布完成后会自动触发 master -> develop 的同步"。该行为由 .github/workflows/gitflow-sync-develop.yml 实现:
- 触发条件:
push到master分支,且路径变更涉及 .version.json(Craft 发布时会由 scripts/bump-version.js 更新该文件);也支持手动workflow_dispatch; - 动作:自动创建标题为
[Gitflow] Merge master into develop的 PR,打上Dev: Gitflow标签,然后自动审批(auto-approve)并启用 automerge 以 merge commit 方式合并。
这保证了 develop 能尽快拿到 master 上的版本号更新,避免下一次 prepare-release 分支合入 master 时出现版本文件冲突。如果该同步 PR 因 package.json 冲突而失败,按 docs/gitflow.md 的手动合并方案处理即可。
首次发布新 SDK 的补充检查清单
官方文档在发布流程入口处明确要求:如果这是某个新 SDK 的首次发布,必须先阅读 docs/new-sdk-release-checklist.md。该清单覆盖了发布前的工程准备(包导出模块、单元测试、构建产物、tarball 内容、README.md 与 LICENSE、CI 配置)、发布中的 craft.yml 配置(移除 private: true、设置 publishConfig.access: public、添加 npm 与 registry target),以及发布后的 NPM 与 Release Registry 核验。首次发布者应将其作为发布流程的前置检查项。
常见注意事项与最佳实践小结
- 分支名决定自动发布的版本号:
prepare-release/<VERSION>必须严格匹配 .github/workflows/auto-release.yml 中的正则(支持alpha/beta/rc预发布后缀),否则版本解析失败、不会触发 Craft。 - 合入方式因场景而异:面向
master的prepare-releasePR 用 Merge Commit;面向旧大版本分支/预发布分支的 changelog PR 用 Squash and Merge,切勿混淆。 - 发布期间冻结
package.json变更:发布窗口内不要向develop合入任何package.json改动,否则会破坏master -> develop的自动同步。 - Changelog 保持规范:重要变更进
### Important Changes、其余用户可见变更进### Other Changes、纯内部改动进<details>折叠块、条目按字母序排列、外部贡献者行注意单复数与牛津逗号。 - 预发布版本:alpha/beta/rc 快照可通过
prepare-release/<VERSION>(自动)或 Release 工作流手动指定9.7.0-alpha.1这类带预发布后缀的版本号发布,最终发布的 npm 版本、CDN 路径与 GitHub Release 均由.craft.yml中声明的 targets 决定。
以上流程在仓库中的实现载体(.github/workflows/auto-release.yml、.github/workflows/release.yml、.github/workflows/gitflow-sync-develop.yml、.craft.yml、scripts/generate-changelog.ts)均为开源可见,维护者可以据此排查问题或扩展新的发布目标。官方文档同时指出,该流程已被封装为 Claude Code / Cursor 中的 /release skill,可自动化执行上述步骤,但本文所述的手动步骤依然是理解与排查发布问题的基础。