编写 Remix 仓库 Change Files:.changes 发布说明约定与完整工作流
【免费下载链接】remixThe fully-stacked web framework项目地址: https://gitcode.com/GitHub_Trending/re/remix
导读
本文围绕 Remix 仓库的make-changes技能规范(.agents/skills/make-changes/SKILL.md),完整讲解在packages/*/.changes目录下编写与维护发布说明(release notes)的命名约定、bump 规则、内容规范与校验流程。读完本文,你将掌握如何为新增功能、破坏性变更、弃用和缺陷修复正确编写 change file,如何在 0.x 与 1.x+ 版本策略下选择 bump 类型,以及如何用pnpm changes:preview、pnpm changes:validate、pnpm changes:version三条命令驱动变更校验、CHANGELOG 生成与版本提交。
make-changes 技能定位
make-changes是仓库内面向 Agent 与开发者的技能(skill),其 frontmatter 明确声明了适用场景:当用户请求发布说明、变更记录、缺失的 changelog 条目、预发布(prerelease)说明,或需要更新现有未发布变更记录时,都应调用该技能。技能的完整定义位于 .agents/skills/make-changes/SKILL.md,与之配套的 Agent 配置见 .agents/skills/make-changes/agents/openai.yaml。
该技能的核心目标是用统一约定管理每个包未发布的变更,使remix及其全部@remix-run/*子包的 CHANGELOG 可以由脚本自动、确定性地生成。从仓库根目录的 package.json 可以看到三条配套脚本:
pnpm changes:preview→ 运行 scripts/changes-preview.ts,预览渲染后的 changelog 输出与发布列表;pnpm changes:validate→ 运行 scripts/changes-validate.ts,校验全部 change file 与 CHANGELOG 完整性;pnpm changes:version→ 运行 scripts/changes-version.ts,真正更新版本号、生成 CHANGELOG 并创建发布提交。
完整工作流
按技能规范,编写一份 change file 的标准流程如下:
- 读取目标包的
package.json、已存在的.changes/目录,以及相关的 PR diff 或 commit 范围,确定变更的上下文与影响面。 - 检查是否已存在针对同一工作的未发布 change file;若存在,直接就地更新而不是新建重复条目,避免同一变更在 CHANGELOG 中出现两次。
- 根据包的当前版本与对用户的影响面,选择 bump 类型(major / minor / patch)。
- 若
packages/<package>/.changes/目录尚不存在,按需创建。 - 编写面向用户的发布说明,描述已交付的行为、API、导出、迁移或升级工作。
- 运行
pnpm changes:preview验证渲染后的 changelog 输出是否符合预期。 - 若本次任务同时改动了代码、包元数据、文档或发布工具,再运行 lint 或更广泛的校验(例如
pnpm changes:validate)。
其中第 2 步是防止重复的关键:change file 是"未发布变更"的暂存区,同一逻辑变更不应同时存在两份说明,脚本在发布时会把变更折叠进 CHANGELOG 并删除暂存文件(见 scripts/changes-version.ts 的deleteChangeFiles逻辑)。
Bump 规则:0.x 与 1.x+ 的版本语义
0.x 包的约定
- 新功能与破坏性变更一律使用
minor,缺陷修复使用patch; - 除非被明确指示,否则不得对 0.x 包使用
major; - 0.x 下破坏性变更说明必须以
BREAKING CHANGE:开头。
这一约定并非只是口头规范,校验脚本中实现了对应强制逻辑。scripts/utils/changes.ts 会检查:
- 对 1.x+ 包,若内容检测到
BREAKING CHANGE:前缀而 bump 不是major,则报错并提示重命名为major.<slug>.md; - 对 0.x 包(且当前版本非预发布),若含破坏性前缀而 bump 不是
minor,同样报错并提示重命名为minor.<slug>.md。
前缀检测由hasBreakingChangePrefix实现(scripts/utils/changes.ts):忽略首部空白与*/_加粗标记后,以小写方式匹配breaking change:开头。
1.x+ 包
按标准 semver 处理:破坏性变更走major,新功能走minor,缺陷修复走patch。
其他版本规则
- 破坏性变更的判定基准是相对
main分支,而非同一 PR 内的早期 commit; - 在
remix的预发布模式下,bump 类型主要决定 changelog 的分类(Major/Minor/Patch Changes 分组),实际版本号由预发布计数器推进,而不是由 bump 类型决定。这一点在 scripts/utils/changes.ts 的getNextVersion中实现:当包配置了prereleaseChannel且当前版本已处于同一通道时,仅调用 semver 的prerelease递增计数器,不再应用 bump 类型。
文件放置与命名
命名模板
- 通用命名:
packages/<package>/.changes/[major|minor|patch].short-description.md; - slug(描述段)要求简短、具体、稳定;
- 当仓库对该类说明已有确定性的命名模式时,复用既有名称,保证同类条目命名可预期;
- 全新包的首次发布,优先使用
minor.initial-release.md; remix包导出变更:更新packages/remix/.changes/minor.remix.update-exports.md这一固定文件,而不是发明一次性文件名(对应规范"Remix-Specific Rules"一节);- 当
packages/remix/.changes镜像某个被再导出包的 change file 时,命名格式为packages/remix/.changes/[major|minor|patch].<package>.short-description.md,其中<package>去掉@remix-run/作用域前缀。
文件名解析与强制校验
脚本对文件名的解析逻辑位于 scripts/utils/changes.ts:文件必须以.md结尾,且文件名开头必须是major.、minor.或patch.前缀加非空描述;否则直接报错(预发布模式下例外,bump 类型不影响版本号,因此允许任意文件名,此时统一按patch归类)。.changes目录下仅README.md与config.json被跳过不参与解析。
目录与依赖关系
.changes目录按包组织,位于每个包的packages/<package>/.changes/下。发布工具链在 scripts/utils/changes.ts 中还会计算"直接变更包"的传递依赖,凡是依赖了被变更包的包也会被纳入本次发布(dependency-triggered release),并自动为其生成依赖升级(dependency bump)的 changelog 条目。
说明内容编写规范
写什么
- 记录用户可见的行为、公开 API 变更、导出、迁移或升级工作;
- 内部重构如果没有体现为真实的 API 或行为变化,不要写发布说明;
- 每条说明必须自包含:读者仅凭该条说明即可理解交付的行为,链接用于补充上下文而不是替代解释;
- 当变更关联公开 issue、PR、RFC、decision doc、spec 或外部缺陷报告时,在说明中附上简短引用。优先引用真正解决了该 issue/功能的 PR(issue 可以从 PR 反查到),同仓库引用使用行内形式如
(see #1234),外部仓库、spec 或报告使用完整 URL; - 明确指出受影响的 API、路由约定、包、入口、运行时、浏览器或工具版本,帮助用户判断该说明是否适用于自己。
不同类型变更的写法
- 缺陷修复:描述用户可见的症状或失败场景,而不是只描述实现层的修复;
- 破坏性变更:同时给出旧行为、新行为与迁移路径;
- 弃用:如果存在替代 API,必须提及。
格式约束
- 不要手动对
.changes/*.md中的散文做硬换行,每个段落或列表项保持单行源码,由渲染后的 changelog 自然换行; - 扁平列表仅在有助于清晰表达时使用,短段落通常更合适;
- 除非被明确要求,不要编辑历史
CHANGELOG.md条目,仅允许诸如修复坏链、错别字或明显无效引用这类窄范围修正。
脚本侧的格式校验
scripts/utils/changes.ts 对内容实施硬性校验:
- change file 不能为空;
- 第一行不能以
-或*开头的列表项开始——CHANGELOG 渲染时会自动为每条说明加 bullet(formatChangelogEntry会把首行转为- xxx),手写 bullet 会导致重复; - 标题级别只能是 4、5、6 级(
####/#####/######),禁止 1-3 级或 7 级以上标题,因为 change file 最终嵌套在已占用 1-3 级标题的 changelog 内部。
包归属:谁该写 change file
规范的"Package Ownership"一节给出清晰的职责划分:
- 手动 change file 应加到"拥有被变更 API、行为或实现"的那个包;
- 若另一包通过再导出(re-export)暴露了新增、删除、重命名或变更的公开 API,且用户可通过该再导出入口消费这些 API,则再导出包也要写 change file;
- 不要为仅通过依赖升级"间接观察到变更"的包手动添加 change file——发布脚本已包含传递依赖方,并会为其生成依赖升级条目;
- 底层包的缺陷修复,通常只给拥有该修复的包写 change file;仅当再导出包自身的 changelog 需要直接点名该行为(而不仅仅因为修复的依赖可达)时,才额外写再导出包条目。
Remix 特有的约束
packages/remix/src/*的再导出文件是生成产物,除非任务明确要求生成输出,否则不要手工编辑;- 当
packages/remix/package.json新增或改变公开导出时,记录到固定的minor.remix.update-exports.md,不要发明一次性文件名; - 如果变更通过
remix/...暴露了其他包的新 API,说明要描述被暴露的remix/...入口,而不仅是底层 workspace 包名。
粒度层级:包级说明与 remix 汇总说明
规范的"Detail Levels"一节区分了两级说明的写作深度:
- 包级 change file 是事实来源(source of truth)。子包说明需包含用户理解变更所需的具体 API、行为、运行时或工具细节;当新 API、迁移、破坏性变更或用法模式改变能借助 before/after 示例讲清楚时,务必包含;同时附上有用的 PR、issue、RFC、decision、spec 或外部报告链接,优先引用能提供完整脉络的实现 PR。
packages/remix/.changes的条目则要像面向remix用户的"伞式发布摘要":比底层包说明更简短,聚焦于暴露出来的remix/...入口或发布级影响。- 不要把一个子包说明中的详细示例、迁移散文或实现背景复制进
remix说明,除非伞式包自身行为发生了变化; - 当
remix说明汇总子包变更时,链接到底层 changelog、release、PR 或其他可持久追踪的细节来源,方便读者下钻; - 发布工具已自动为发布的包 tag 添加依赖升级链接,因此不要在
remixchange file 中手工重建依赖升级列表。
命令行验证:preview、validate、version
pnpm changes:preview(预览)
scripts/changes-preview.ts 首先调用parseAllChangeFiles做全量解析与校验,失败则以红色错误信息退出(exit 1);成功且存在变更时,依次打印:
- 有变更的包列表,格式为
包名: 当前版本 → 下一版本 (bump 类型); - 每个包对应的 CHANGELOG 渲染预览;
- 生成的提交信息;
- 后续应执行的
pnpm changes:version提示。
若所有包都无待发布变更,则打印No packages have changes to release.并正常退出。
pnpm changes:validate(校验)
scripts/changes-validate.ts 做两件事:
- 遍历全部包目录,检查是否存在
CHANGELOG.md,缺失则报错; - 调用
parseAllChangeFiles校验所有 change file 的命名、内容格式、bump 规则与预发布配置一致性。
任一环节出错都会以 exit code 1 退出,适合接入 CI 前置检查。
pnpm changes:version(落地版本)
scripts/changes-version.ts 在通过全量校验后,按发布列表逐个包执行:
- 更新
package.json的version字段; - 在
CHANGELOG.md中插入新版本条目(插入到第一个##版本条目之前,无版本条目时追加到末尾); - 删除
.changes/下所有待发布 md change file(空目录一并移除); - 默认执行
git add .并创建提交信息形如Release+- 包名: 当前版本 -> 下一版本的提交;传--no-commit参数时只更新文件不提交,并打印供人工审阅与手动git commit的指引。
预发布(prerelease)模式细节
预发布相关的配置与校验逻辑集中在 scripts/utils/changes.ts 与 scripts/utils/changes.ts:
- 每个包可在
.changes/config.json中声明prereleaseChannel(非空字符串)与可选的prereleaseStart(非负整数,且要求必须同时声明prereleaseChannel); - 当版本预发布标识与通道不一致(如版本是 alpha 但配置为 beta)、配置声明了通道但版本是稳定版且无 change file、或版本是预发布但未配置通道且无 change file 时,均会报错,要求通过添加 change file 完成通道迁移或转正(graduation);
- 从稳定版进入预发布模式必须包含一个
major.前缀的 change file(scripts/utils/changes.ts); - 预发布模式下,渲染的 changelog 把所有条目归入单一的
Pre-release Changes分组,而不是按 Major/Minor/Patch 分节(scripts/utils/changes.ts 与 scripts/utils/changes.ts)。
这套机制与 decisions/002-branching-and-releasing.md 描述的发布策略相呼应:main分支持续可发布,子包破坏性变更在future分支积累并提前发布 major,最终合并回main再切remix主版本,change file 体系正是这条发布流水线的入口。
变更说明的效果:CHANGELOG 渲染规则
scripts/utils/changes.ts 定义了 changelog 的渲染规则:
- 同包多条说明按 bump 类型分组为
### Major Changes、### Minor Changes、### Patch Changes三节,空节跳过; - 节内排序把破坏性变更置顶,其余按文件名(slug)字母序排列;
- 每条说明自动加 bullet:单行直接变
- 内容,多行时首行加 bullet、后续行缩进两格; - 依赖升级产生的条目统一渲染为
- Bumped \@remix-run/*` dependencies:` 加带 tag 链接的列表;若包已有 patch 变更则并入现有 Patch Changes 节,否则单独生成一节。
仓库内包的 CHANGELOG.md(如 packages/remix/CHANGELOG.md)正是这些渲染规则的产物,其中预发布版本条目使用### Pre-release Changes分组,与生成逻辑完全一致,可作为编写 change file 时的参照样例。
结束前自检清单
规范"Before Finishing"一节给出了收尾自查项,也是每次提交前的最终把关:
- 是否先检查了既有的未发布
.changes文件(避免重复)? - 说明是否描述用户可见的变更,而不是实现细节?
- 是否运行过
pnpm changes:preview,且渲染出的 changelog 条目符合预期?
小结
make-changes把"写发布说明"这件看似自由发挥的事,固化为一套命名可解析、内容可校验、渲染可预览、落地可自动化的工程流程:文件名前缀决定 bump 分类,BREAKING CHANGE:前缀与版本段强制绑定,内容格式由脚本兜底校验,remix伞包与子包各司其职,预发布通道由config.json驱动。对仓库维护者与 Agent 而言,只要遵循本文梳理的命名、内容与命令三部曲,就能为任意@remix-run/*包或remix本身稳定地产出高质量、可发布的变更记录。
【免费下载链接】remixThe fully-stacked web framework项目地址: https://gitcode.com/GitHub_Trending/re/remix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考