oss-changelog
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseChangelog and versioning
Changelog 与版本管理
Keep in the convention it declares, Keep a Changelog 2.0.0 where the project has none yet, decide the Semantic Versioning bump a set of merged changes forces, write the release entry from the merged work, and run a deprecation window before an API is removed. The sentences themselves follow ; this skill decides what goes in and what version it ships under. Publishing the tagged release, the workflow that builds and uploads it, belongs to .
CHANGELOG.mdoss-writingoss-publishWrite changelog entries as changes rather than as a description of the current state. That is the exception already carves out from its ban on diff-anchored documentation, and a changelog is the artifact it carves it out for.
oss-writing按照 声明的约定维护它;如果项目尚无 Changelog,则采用 Keep a Changelog 2.0.0;判断一组已合并的变更强制要求的 Semantic Versioning bump;根据已合并的工作编写 release 条目;并在移除 API 之前执行 deprecation window。句子本身遵循 ;本 skill 决定写什么内容以及以哪个版本发布。发布带 tag 的 release、构建并上传它的工作流,属于 。
CHANGELOG.mdoss-writingoss-publish将 Changelog 条目写成变更,而不是对当前状态的描述。这是 从其禁止以 diff 为锚点的文档规则中明确保留的例外,而 Changelog 正是该例外所针对的产物。
oss-writingThree terms this skill keeps apart
本 skill 区分的三个术语
A changelog section is one version's entry inside . A forge release body is the text field attached to a tag on GitHub or GitLab. Release notes are what a reader calls either one, so this file uses the first two and R-CHG-04 governs how the second derives from the first.
CHANGELOG.mdChangelog section 是 中某个版本的条目。Forge release body 是附加在 GitHub 或 GitLab 某个 tag 上的文本字段。读者会把这两者中的任意一种称为 release notes,因此本文档使用前两个术语,并由 R-CHG-04 规定第二个术语应如何从第一个术语派生。
CHANGELOG.mdScope
范围
The CHG rules belong here: R-CHG-01 changelog format, R-CHG-02 semantic bumps, R-CHG-03 one version, R-CHG-04 release body, R-CHG-05 deprecation window, R-CHG-06 vulnerability entries, and R-CHG-07 major version in package identity.
When exists at the repository root, read the group addressed to this skill and work from that. Each failing rule there carries the audit's evidence and that rule's text verbatim, so reading as well adds nothing. Where the file is absent, work from the request as usual.
oss-audit-report.mdCheck:STANDARD.mdThis skill owns the changelog and versioning rules above. It does not own the sentences: once an entry's content is decided, phrasing it in plain, active prose free of marketing language is 's rule, R-DOC-05. It does not own publishing: building the tagged artifact, authenticating to a registry, and gating the release behind approval are 's R-PUB rules. Do not draft commit or pull request prose, or write a publish workflow, from this skill; note that the project needs it and hand the work to the owning skill.
oss-writingoss-publishCHG 规则归此处处理:R-CHG-01 Changelog 格式、R-CHG-02 semantic bump、R-CHG-03 单个版本、R-CHG-04 release body、R-CHG-05 deprecation window、R-CHG-06 vulnerability 条目,以及 R-CHG-07 package identity 中的 major version。
如果 repository 根目录中存在 ,请读取其中面向本 skill 的规则组,并据此开展工作。该文件中每条未通过的规则都附有审计证据,以及该规则的 原文,因此再读取 不会提供额外信息。如果该文件不存在,则照常根据请求处理。
oss-audit-report.mdCheck:STANDARD.md本 skill 负责上述 Changelog 和版本管理规则,但不负责具体句子:一旦确定条目的内容,应按照 的 R-DOC-05 规则,以平实、主动且不含营销语言的 prose 进行表述。本 skill 也不负责发布:构建带 tag 的产物、认证 registry,以及在 approval 之后 gate release,均属于 的 R-PUB 规则。不要使用本 skill 起草 commit 或 pull request 文案,也不要编写 publish workflow;只需指出项目需要这些内容,并将工作移交给对应的 skill。
oss-writingoss-publishProcess
流程
Step 1: Identify the release unit and its manifests
Step 1:确定 release unit 及其 manifest
A release unit is one product versioned as a whole, together with every file that states its version. Find them all before deciding anything, because Step 7 has to set the same number in each. Identify the unit's declared public API as well: library symbols, CLI behavior, configuration, network protocols, file formats, or another documented contract. That declaration is what Step 5 measures a change against.
Do not bump unrelated packages merely because they share a repository. A single product spread across several manifests must update all manifests that describe that product; independently versioned packages need separate release units and changelog sections or files.
Then read the ecosystem file for what this release unit ships. Where the version is stated, how the version syntax deviates from SemVer, whether the major version lives in the package name, and what withdrawing a release means all differ by ecosystem, and each file answers those four for one of them. Route on what the unit publishes, not on every manifest present: a Go module with a documentation is a Go release unit, and npm has nothing to say about its version.
package.json| What the release unit ships | Read |
|---|---|
| an npm package | references/ecosystems/npm.md |
| a Python distribution on PyPI | references/ecosystems/pypi.md |
| a gem on RubyGems | references/ecosystems/rubygems.md |
| a crate on crates.io | references/ecosystems/crates.md |
| a Go module | references/ecosystems/go-modules.md |
| a PHP package on Packagist | references/ecosystems/packagist.md |
| a package on nuget.org | references/ecosystems/nuget.md |
| an artifact on Maven Central | references/ecosystems/maven-central.md |
| a package on Hex | references/ecosystems/hex.md |
| a package on pub.dev | references/ecosystems/pubdev.md |
| a container image pushed to a registry | references/ecosystems/containers.md |
A release unit that ships to two of these, such as a module and an image, reads both files and satisfies both. A repository that publishes nothing still has a tag and a changelog, so Step 5 through Step 9 apply unchanged and no file above is needed.
Release unit 是一个作为整体进行版本管理的产品版本,以及所有标明该版本的文件。在作出任何决定之前先找出全部文件,因为 Step 7 必须在每个文件中设置相同的版本号。还应确定该 unit 声明的 public API,例如 library symbols、CLI behavior、configuration、network protocols、file formats 或其他已记录的 contract。Step 5 会以此声明为基准衡量变更。
不要仅仅因为多个 package 位于同一 repository,就提升无关 package 的版本。一个由多个 manifest 描述的单一产品,必须更新描述该产品的所有 manifest;独立版本化的 package 需要独立的 release unit,以及独立的 Changelog section 或文件。
然后读取该 release unit 所发布 ecosystem 的文件。版本记录在哪里、version syntax 在哪些方面偏离 SemVer、major version 是否包含在 package name 中,以及撤回 release 分别意味着什么,都因 ecosystem 而异;每个文件会分别回答其中四个问题。应根据该 unit 实际发布的内容进行路由,而不是依据 repository 中存在的所有 manifest:如果一个 Go module 带有用于文档的 ,它仍是 Go release unit,npm 的规则与它的版本无关。
package.json| Release unit 发布的内容 | 阅读 |
|---|---|
| npm package | references/ecosystems/npm.md |
| PyPI 上的 Python distribution | references/ecosystems/pypi.md |
| RubyGems 上的 gem | references/ecosystems/rubygems.md |
| crates.io 上的 crate | references/ecosystems/crates.md |
| Go module | references/ecosystems/go-modules.md |
| Packagist 上的 PHP package | references/ecosystems/packagist.md |
| nuget.org 上的 package | references/ecosystems/nuget.md |
| Maven Central 上的 artifact | references/ecosystems/maven-central.md |
| Hex 上的 package | references/ecosystems/hex.md |
| pub.dev 上的 package | references/ecosystems/pubdev.md |
| 推送到 registry 的 container image | references/ecosystems/containers.md |
如果一个 release unit 会发布到上述两个环境,例如同时发布 module 和 image,则应读取两个文件并同时满足两者。即使 repository 不发布任何内容,也仍然会有 tag 和 Changelog,因此 Step 5 至 Step 9 保持不变,也不需要上述任何文件。
Step 2: Read the changelog that already exists
Step 2:读取已有的 Changelog
Find and read its preamble before writing anything. A changelog that already exists is a file the project's users read, and it lands in one of three states.
CHANGELOG.mdThere is no changelog. Write one from the structure in Step 6. Backfill only the releases the repository can establish from its own tags, and stop there rather than reconstructing entries from commit history, which produces a list of commits wearing a changelog's headings.
There is a changelog and it declares Keep a Changelog 2.0.0. Add the entry under and change nothing else. Not the preamble, not the heading style of older releases, not the category names they used.
## [Unreleased]There is a changelog and it declares a different convention, or an earlier version of this one. Follow what the file declares and leave its pin alone. The convention it names is what its readers and any tooling reading it expect, and a version bump is a change to the file's contract that happens to arrive inside somebody's bug-fix release. Where migrating would genuinely help, propose it to the maintainer as its own piece of work, with what would change; do not perform it while adding an entry.
找到 ,并在写入任何内容前阅读其前言。Changelog 是项目用户会阅读的文件,因此它可能处于以下三种状态之一。
CHANGELOG.md没有 Changelog。按照 Step 6 的结构新建一个。只回填 repository 能够根据自身 tags 确认的 release,并在此停止,不要根据 commit history 重建条目;否则只会得到一份套着 Changelog 标题的 commit 列表。
存在 Changelog,并声明采用 Keep a Changelog 2.0.0。在 下添加条目,不做任何其他修改。不要修改前言、旧 release 的 heading style,也不要修改它们使用的 category 名称。
## [Unreleased]存在 Changelog,但声明采用其他 convention 或本 convention 的较早版本。遵循文件自身的声明,不要修改其 pin。文件所声明的 convention 正是其读者和读取该文件的 tooling 所预期的约定,而 convention 版本的升级属于文件 contract 的变化,不应恰好混入某个 bug-fix release。如果迁移确实有助于项目,应将迁移作为一项独立工作向 maintainer 提议,并说明会发生哪些变化;不要在添加条目的同时执行迁移。
Step 3: Read the merged work since the last tag
Step 3:读取上一个 tag 之后已合并的工作
List the commits that landed after the newest tag:
bash
git log --oneline "$(git describe --tags --abbrev=0)"..HEADgit describe --abbrev=0--tagsOn GitHub, add the merged pull requests, which carry the discussion a commit subject leaves out:
bash
gh pr list --state merged --search "merged:>=<date of that tag>"That call needs installed and authenticated. Where it is not, the log alone is enough to work from.
gh列出最新 tag 之后合入的 commits:
bash
git log --oneline "$(git describe --tags --abbrev=0)"..HEADgit describe --abbrev=0--tags在 GitHub 上,还应加入已合并的 pull requests,因为它们包含 commit subject 中缺失的讨论信息:
bash
gh pr list --state merged --search "merged:>=<date of that tag>"该命令要求已安装并认证 。如果未安装,仅使用 log 也足以开展后续工作。
ghStep 4: Classify each change as user-visible or not
Step 4:将每项变更分类为用户可见或不可见
A changelog section names what changed for a user, not the pull requests that produced it. Read the merged work rather than the commit messages verbatim: a commit message addresses another contributor reading , a changelog entry addresses a user deciding whether to upgrade. Fold multiple commits that implement one user-visible change into one entry; do not list each commit as its own line.
git logDrop anything with no user-visible effect: a refactor, a test added for existing behavior, a CI config change, a dependency bump with no behavior change. If a version contains no notable change, keep the required version entry and say that it contains internal maintenance only instead of inventing category bullets.
One kind of dependency bump is the exception. A bump that resolves a publicly known vulnerability in the shipped code or in a run-time dependency reached users, so it belongs under Security, and the entry names an identifier from the published advisory. Where the project ships a built artifact, its build toolchain counts as run-time: a compromised bundler or code generator injects into what users install. A development-only bump stays out, as does a build-only bump in a project that ships only its source. R-CHG-06 is the check.
Changelog section 描述的是对用户而言发生了什么变化,而不是哪些 pull requests 产生了这些变化。阅读已合并的工作,不要逐字照搬 commit message:commit message 是写给阅读 的其他贡献者看的,而 Changelog 条目是写给决定是否升级的用户看的。将实现同一项用户可见变更的多个 commits 合并为一个条目,不要把每个 commit 分别列成一行。
git log删除所有没有用户可见影响的内容,例如 refactor、为既有行为新增的 test、CI config 变更,以及不会改变行为的 dependency bump。如果某个 version 没有任何值得注意的变更,仍要保留必需的 version 条目,并说明该版本仅包含内部维护,不要编造 category 条目。
dependency bump 存在一种例外。修复了已发布代码或用户实际使用的 runtime dependency 中公开已知 vulnerability 的 bump 已经影响用户,因此应归入 Security,并在条目中注明 published advisory 中的 identifier。如果项目发布构建产物,其 build toolchain 也算作 runtime:被入侵的 bundler 或 code generator 可能会向用户安装的内容注入代码。仅用于开发的 bump 不应列入;只发布源码的项目中,仅影响构建的 bump 也不应列入。R-CHG-06 是对应的检查规则。
Step 5: Decide the semver bump
Step 5:决定 SemVer bump
A normal version is , with optional prerelease and build metadata. For a stable or later release, increment MAJOR for an incompatible public API change, MINOR for a backward-compatible addition or deprecation, and PATCH for backward-compatible fixes.
MAJOR.MINOR.PATCH1.0.0Major version zero has different upstream semantics: is initial development and SemVer permits anything to change. This standard uses MINOR for an incompatible change and PATCH for a backward-compatible fix so pre-1.0 versions still communicate risk. Do not force a project to declare stability by changing to ; that decision defines the public API and belongs to the maintainer.
0.y.z0.y.z1.0.0Source: Semantic Versioning 2.0.0.
The test that survives both cases people get wrong: will something that worked, unmodified, on the previous version keep working, unmodified, on the new one? If no, the change is backward incompatible and forces MAJOR, regardless of what kind of change produced it.
A bug fix is not automatically a PATCH. Determine whether the old behavior belonged to the declared public API and whether restoring the intended contract breaks realistic callers. SemVer explicitly calls for judgment when a widely used accidental behavior conflicts with the intended API. If the correction is incompatible with the public API, use MAJOR after 1.0.0; otherwise use PATCH. Do not assume that undocumented behavior is harmless or that every documented bug is a permanent contract.
A new required config value is the second case. The instinct is that adding something is growth, so it should be MINOR. But a config value with no default, one the project now refuses to start without, breaks every existing deployment the moment they upgrade without editing their config. Apply the test: a config file that worked, unmodified, on the previous version no longer starts the previous version. That forces MAJOR. A new config value with a default that preserves the old behavior is backward compatible and stays MINOR.
Under this standard reserves MINOR for an incompatible change, so a compatible addition takes PATCH alongside a compatible fix. That is what keeps a MINOR bump before 1.0.0 meaning "this may break you".
0.y.zTen changes and the bump each forces:
| Change | Stable | | What decides it |
|---|---|---|---|
| New optional argument with a default | MINOR | PATCH | Every existing call still compiles and behaves as before |
| New config key with a default preserving the old behavior | MINOR | PATCH | An unedited config file still starts |
| New required config key with no default, and startup fails without it | MAJOR | MINOR | An unedited config file no longer starts |
| Fix restoring documented behavior, breaking an undocumented workaround | PATCH | PATCH | The workaround was never in the declared API |
| Fix to a crash, no interface change | PATCH | PATCH | Nothing in the declared API moved |
| Deprecation notice added, old path still works | MINOR | PATCH | A deprecation is an addition until the removal lands |
| Public method removed after its deprecation window | MAJOR | MINOR | The window makes the removal expected, not compatible |
| Error message text changed, not documented as an interface | PATCH | PATCH | Message text is outside the declared API until a project declares it in |
| Minimum runtime version raised | MAJOR | MINOR | A runtime the project supported yesterday no longer runs it |
| Development-only dependency bump | no release | no release | Nothing a user installs changed |
Two rows turn on what the project declared rather than on the shape of the change. Where an undocumented behavior is widely relied on, SemVer calls for judgment, and a fix that breaks realistic callers is incompatible whatever the documentation said. Where a project documents its error messages as an interface, for example because a test suite or a log parser matches them, changing one is a public API change. Run the test above against the declaration from Step 1 rather than reading the row alone.
R-CHG-02 checks the bump rule.
普通 version 采用 格式,并可包含可选的 prerelease 和 build metadata。对于 或更高版本的稳定 release,不兼容的 public API 变更递增 MAJOR,向后兼容的新增或弃用递增 MINOR,向后兼容的修复递增 PATCH。
MAJOR.MINOR.PATCH1.0.0Major version 为零时具有不同的上游语义: 表示仍处于初始开发阶段,SemVer 允许其中发生任何变更。本标准使用 MINOR 表示不兼容变更,使用 PATCH 表示向后兼容的修复,从而让 1.0.0 之前的版本仍能传达风险。不要为了让项目宣告稳定,就强行将 改为 ;该决定涉及 public API 的定义,应由 maintainer 作出。
0.y.z0.y.z1.0.0有一种测试能够同时覆盖人们最容易判断错误的两种情况:在上一个 version 中无需修改即可正常工作的内容,在新 version 中是否仍能无需修改即可正常工作?如果不能,该变更就是向后不兼容的,无论它由何种类型的变更引起,都必须使用 MAJOR。
Bug fix 不一定是 PATCH。应判断旧行为是否属于已声明的 public API,以及恢复预期 contract 是否会破坏现实中的调用方。SemVer 明确指出,当广泛使用的偶然行为与预期 API 冲突时,需要人为判断。如果修复结果与 public API 不兼容,那么 1.0.0 之后应使用 MAJOR,否则使用 PATCH。不要假定未记录的行为无害,也不要假定每个已记录的 bug 都是永久 contract。
新增必需的 config value 是第二种需要特别判断的情况。直觉上,新增内容属于增长,因此应该使用 MINOR。但是,一个没有默认值、导致项目现在拒绝在没有它的情况下启动的 config value,会在用户升级后未编辑 config 的瞬间破坏所有既有 deployment。应用这个测试:上一个 version 中无需修改即可正常工作的 config file,在新 version 中不再能够启动。这会强制使用 MAJOR。新增带默认值且保持旧行为的 config value 属于向后兼容,继续使用 MINOR。
在 阶段,本标准保留 MINOR 用于不兼容变更,因此向后兼容的新增与向后兼容的修复一样使用 PATCH。这使 1.0.0 之前的 MINOR bump 始终表示“此升级可能破坏你”。
0.y.z以下十种变更及其对应的 bump:
| 变更 | 稳定版本 | | 判定依据 |
|---|---|---|---|
| 新增带默认值的可选参数 | MINOR | PATCH | 所有既有调用仍能编译,且行为保持不变 |
| 新增带默认值且保持旧行为的 config key | MINOR | PATCH | 未编辑的 config file 仍能正常启动 |
| 新增无默认值的必需 config key,缺少时启动失败 | MAJOR | MINOR | 未编辑的 config file 不再能够启动 |
| 修复后恢复已记录行为,但会破坏未记录的 workaround | PATCH | PATCH | workaround 从未属于已声明的 API |
| 修复 crash,且 interface 没有变化 | PATCH | PATCH | 已声明的 API 没有变化 |
| 添加 deprecation notice,旧路径仍然有效 | MINOR | PATCH | 在移除落地前,deprecation 属于新增内容 |
| deprecation window 结束后移除 public method | MAJOR | MINOR | window 使移除成为可预期行为,但它仍不兼容 |
| 修改 error message 文本,且未将其声明为 interface | PATCH | PATCH | 在项目正式声明之前,message 文本不属于已声明的 API |
| 提升最低 runtime version | MAJOR | MINOR | 项目昨天支持的 runtime 不再能够运行它 |
| 仅用于开发的 dependency bump | 不发版 | 不发版 | 用户安装的内容没有变化 |
其中两行取决于项目声明的内容,而不是变更的外在形式。如果某种未记录的行为被广泛依赖,SemVer 要求进行判断,而破坏现实调用方的修复无论文档如何描述都属于不兼容变更。如果项目明确将 error message 记录为 interface,例如 test suite 或 log parser 会匹配这些消息,那么修改消息就是 public API 变更。应使用上述测试对照 Step 1 中的声明进行判断,而不是只阅读表格行。
R-CHG-02 用于检查 bump 规则。
Step 6: Write or amend the changelog section
Step 6:编写或修订 Changelog section
This is what a new changelog is written from, and what an existing one is read against rather than rewritten to.
Open with and a two-sentence preamble that says all notable changes are recorded here, links to the pinned Keep a Changelog 2.0.0 convention, and names the project's versioning scheme. Do not claim Semantic Versioning until the project has declared the public API it covers.
# ChangelogNext comes , followed by released versions newest first in the form . Use the project's actual version syntax when it supports prereleases or another declared scheme. Mark a withdrawn release with ; never delete it. Group entries under the six standard category headings:
## [Unreleased]## [X.Y.Z] - YYYY-MM-DD[YANKED]- for new features
Added - for changes in existing functionality
Changed - for soon-to-be removed features
Deprecated - for now removed features
Removed - for any bug fixes
Fixed - in case of vulnerabilities
Security
Omit empty categories. Mark each incompatible change inside or with , name the affected public interface, and give the short migration step. Link to a migration guide when the steps would make the entry hard to scan. A release may start with a one- or two-sentence summary before its categories.
ChangedRemoved**Breaking:**Make every bracketed version heading a reference link. compares the newest tag with , each later version compares its tag with the preceding release, and the oldest version links to its tag. Use the repository's actual forge and tag format. Keep issue and pull request links useful and portable, and collect them as reference links rather than filling entries with bare forge numbers.
[Unreleased]HEADThis is the shape those rules produce. The headings, the category names, the marker, and the structure of the link block are copied as they stand; everything in angle brackets, every version, every date, and every entry comes from the repository:
**Breaking:**markdown
undefined这是新 Changelog 的编写依据,也是现有 Changelog 的对照依据,而不是将其重写的依据。
以 开头,并添加两句前言:说明这里记录了所有值得注意的变更,链接到固定版本的 Keep a Changelog 2.0.0 convention,并说明项目采用的版本方案。在项目声明其涵盖的 public API 之前,不要声称采用 Semantic Versioning。
# Changelog接下来是 ,然后按最新版本在前的方式列出已发布 version,格式为 。如果项目支持 prerelease 或采用其他已声明的方案,应使用项目实际采用的 version syntax。使用 标记已撤回的 release;绝不要删除它。条目应归入六个标准 category heading:
## [Unreleased]## [X.Y.Z] - YYYY-MM-DD[YANKED]- :新功能
Added - :现有功能发生变更
Changed - :即将移除的功能
Deprecated - :已经移除的功能
Removed - :bug fix
Fixed - :vulnerability
Security
省略空 category。在 或 中标记不兼容变更时,应使用 ,指出受影响的 public interface,并给出简短的迁移步骤。如果迁移步骤会使条目难以快速浏览,应链接到 migration guide。某个 release 可以在 category 之前添加一两句话的摘要。
ChangedRemoved**Breaking:**每个带方括号的 version heading 都应做成 reference link。 比较最新 tag 与 ,之后的每个 version 将自己的 tag 与前一个 release 比较,最早的 version 则链接到自己的 tag。使用 repository 实际的 forge 和 tag format。让 issue 和 pull request 链接保持实用且可移植,并将其收集为 reference links,不要在条目正文中到处填写裸 forge 编号。
[Unreleased]HEAD以下就是这些规则生成的结构。Heading、category 名称、 标记和链接块结构均原样复制;尖括号中的所有内容、每个 version、每个 date 以及每个条目都来自 repository:
**Breaking:**markdown
undefinedChangelog
Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[Unreleased]
[Unreleased]
[2.0.0] - 2026-07-30
[2.0.0] - 2026-07-30
Added
Added
- accepts
--formatandjson, and defaults tocsv([#128])json
- accepts
--formatandjson, and defaults tocsv([#128])json
Changed
Changed
- Breaking: returns a result object rather than throwing on bad input. Wrap existing calls, or call
parse(), which keeps the old behavior.parseOrThrow()
- Breaking: returns a result object rather than throwing on bad input. Wrap existing calls, or call
parse(), which keeps the old behavior.parseOrThrow()
[1.4.0] - 2026-05-02
[1.4.0] - 2026-05-02
Fixed
Fixed
- no longer suppresses the exit status
--quiet
The oldest version links to its tag, because there is no earlier release to compare it against. Every later version compares its tag with the one below it, and `[Unreleased]` compares the newest tag with `HEAD`, so an empty `[Unreleased]` link resolves to an empty diff rather than to nothing.
The link labels are lowercase where the headings are not. Markdown matches a link label case-insensitively, so `[unreleased]` resolves `## [Unreleased]`; match whichever form the file already uses rather than changing it.
On GitLab the same three shapes are `/-/compare/v1.4.0...v2.0.0`, `/-/tags/v1.4.0`, and `/-/merge_requests/128`. Read the forge from the remote rather than assuming GitHub.
R-CHG-01 is the check for this structure.- no longer suppresses the exit status
--quiet
最早的 version 链接到自己的 tag,因为它没有更早的 release 可供比较。之后的每个 version 都将自己的 tag 与下方那个 version 比较,而 `[Unreleased]` 比较最新 tag 与 `HEAD`,因此即使 `[Unreleased]` 为空,其链接也会指向一个空 diff,而不是无处可指。
当 heading 不是小写形式时,link label 使用小写。Markdown 匹配 link label 时不区分大小写,因此 `[unreleased]` 可以解析到 `## [Unreleased]`;应匹配文件中已经使用的形式,不要修改它。
在 GitLab 上,对应的三种形式是 `/-/compare/v1.4.0...v2.0.0`、`/-/tags/v1.4.0` 和 `/-/merge_requests/128`。应从 remote 读取实际使用的 forge,不要默认是 GitHub。
R-CHG-01 是针对该结构的检查规则。Step 7: Set that version in every manifest
Step 7:在每个 manifest 中设置该版本
Write the version decided in Step 5 into every file Step 1 found, and into the changelog heading written in Step 6. R-CHG-03 checks that the release tag, the version sources for that release unit, and its newest changelog entry agree, so all three have to carry one number before the tag is pushed.
When earlier changelog versions have no tag, as in a project that released by commit alone, tag each version on the commit that shipped it. Use the release commit that set the manifest to that version where the project made one. Otherwise, use the last commit whose manifest still carries that version and whose changes the next version's section does not list. Check each commit with before pushing, and put the version-to-commit mapping in the report, because once a tag ruleset is in place a pushed tag cannot be moved.
git show <sha>:<manifest>将 Step 5 决定的 version 写入 Step 1 找到的每个文件,并写入 Step 6 中创建的 Changelog heading。R-CHG-03 会检查 release tag、该 release unit 的 version 来源以及最新 Changelog 条目是否一致,因此在推送 tag 之前,三者必须都使用同一个版本号。
如果较早的 Changelog version 没有 tag,例如项目仅通过 commit 发布,则应在实际发布该版本的 commit 上标记每个 version。如果项目有用于设置 manifest 版本的 release commit,应使用该 commit。否则,使用最后一个满足以下条件的 commit:其 manifest 仍带有该 version,并且下一个 version 的 Changelog section 未列出该 commit 所做的变更。推送之前,使用 检查每个 commit,并在报告中记录 version 与 commit 的映射关系;因为一旦启用 tag ruleset,已推送的 tag 就无法移动。
git show <sha>:<manifest>Step 8: Derive the forge release body from the changelog section
Step 8:从 Changelog section 派生 forge release body
Keep canonical. A forge-generated pull request list is useful raw material, not a finished changelog. Start the release body from the corresponding changelog section without retyping it. It may add a brief announcement, installation or verification details, migration links, contributor credit, and attached-asset context, but it must not omit or contradict notable changes. R-CHG-04 checks that relationship.
CHANGELOG.mdscripts/release-notes.mjssh
node skills/oss-changelog/scripts/release-notes.mjs v1.2.3
node skills/oss-changelog/scripts/release-notes.mjs docs/CHANGELOG.md 1.2.3It exits 2 when the version's section is absent or empty, which is what makes it usable inside a release job: the job fails rather than publishing a release with a blank body. Where writes a release workflow that creates the forge release, it copies this file to in the repository and calls it there, because the file has to exist on the runner. Run it against the tag about to be pushed before pushing it. Where the script is not installed, read the section out of the file directly; do not fall back to , which lists merged pull requests rather than what the project wrote.
oss-publish.github/scripts/release-notes.mjs--generate-notes始终以 为权威来源。Forge 自动生成的 pull request 列表可以作为有用的原始材料,但它不是完成的 Changelog。应直接从对应的 Changelog section 开始编写 release body,不要重新手动输入。Release body 可以增加简短的公告、安装或验证说明、迁移链接、贡献者致谢以及附件上下文,但不得遗漏或违背任何值得注意的变更。R-CHG-04 会检查二者之间的关系。
CHANGELOG.mdscripts/release-notes.mjssh
node skills/oss-changelog/scripts/release-notes.mjs v1.2.3
node skills/oss-changelog/scripts/release-notes.mjs docs/CHANGELOG.md 1.2.3如果指定 version 的 section 不存在或为空,该脚本会退出并返回状态码 2,因此可以在 release job 中使用:job 会直接失败,而不是发布一个正文为空的 release。如果 编写用于创建 forge release 的 release workflow,它会将该脚本复制到 repository 中的 ,并从该位置调用,因为 runner 上必须存在这个文件。推送 tag 之前,应针对即将推送的 tag 运行脚本。如果未安装该脚本,应直接从文件中读取对应 section;不要退回到使用 ,因为它列出的是已合并的 pull requests,而不是项目亲自编写的内容。
oss-publish.github/scripts/release-notes.mjs--generate-notesStep 9: Verify, then hand the tag over
Step 9:验证,然后移交 tag
Read each R-CHG rule's line in against the changelog, the manifests, and the proposed tag as they now stand, and fix what fails. Start the list again after each fix, because setting a version in one place can leave another disagreeing, and do not report done while any cited rule still fails.
Check:STANDARD.mdThen hand the tag and the publish workflow to , which owns building and uploading what the tag points at.
oss-publish使用当前状态下的 Changelog、manifest 和拟推送 tag,对照 中每条 R-CHG 规则的 行进行检查,并修复未通过项。每次修复后都应重新开始检查,因为在某个位置修改版本号后,其他位置仍可能不一致;只要引用的规则中还有任何一项未通过,就不能报告完成。
STANDARD.mdCheck:然后将 tag 和 publish workflow 移交给 ,由它负责构建并上传 tag 所指向的内容。
oss-publishDeprecation policy
弃用策略
Deprecate before removing. For a stable SemVer API, release at least one MINOR version where the old path still works before removing it in a later MAJOR version. During initial development, give users at least one earlier release before removal, then make the incompatible change in a later MINOR version. A longer published support policy takes precedence.
The deprecation notice names what is deprecated, its replacement or migration path, and the earliest removal version. Surface it through the interface users actually encounter: a runtime warning for a library, a diagnostic for a CLI or configuration parser, a compiler annotation where the ecosystem supports one, and documentation plus protocol signaling for a remote API. Avoid noisy warnings that fire where the user cannot act. R-CHG-05 checks both the release ordering and the interface-appropriate notice.
先弃用,再移除。对于稳定的 SemVer API,至少应发布一个 MINOR version,在其中旧路径仍然有效,然后才能在之后的 MAJOR version 中将其移除。在初始开发阶段,应至少先向用户提供一个包含旧路径的 release,再在之后的 MINOR version 中进行不兼容变更。如果项目已经发布了更长的支持策略,则以该策略为准。
Deprecation notice 应说明弃用了什么、替代方案或迁移路径,以及最早会在哪个 version 中移除。应通过用户实际接触到的 interface 提供通知:library 使用 runtime warning,CLI 或 configuration parser 使用 diagnostic,生态支持时使用 compiler annotation,remote API 则结合 documentation 与 protocol signaling。避免在用户无法采取行动的情况下反复发出噪声警告。R-CHG-05 会同时检查 release 顺序和与 interface 相匹配的 notice。