关于 setup-semantic-release
为 Node.js 仓库配置发布流水线的技能,组合 Conventional Commits、commitlint、Husky 和 semantic-release。涵盖提交校验、版本管理、变更日志、GitHub 发布及 Actions 工作流,并检查是否已有冲突的发布配置。
主要功能
- 01配置 Conventional Commits 校验
- 02设置 Husky 提交钩子
- 03自动管理语义化版本
- 04生成并提交变更日志
- 05创建 GitHub Actions 发布工作流
- 06检查冲突的发布工具配置
适用场景
- 01为 Node.js 仓库添加自动发布
- 02在提交前拒绝格式错误的提交主题
- 03根据提交生成变更日志
- 04配置 GitHub Actions 发布自动化
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ antjanus/ skillbox --skill setup-semantic-release安装后在 Claude Code 中输入/setup-semantic-release确认已加载。
附带文件references/EVAL.mdreferences/REFERENCE.md
详细介绍
设置 Semantic Release 和 Conventional Commits
概述
配置端到端的自动版本管理:Conventional Commits → commitlint → husky → semantic-release。版本号、CHANGELOG.md、Git 标签和 GitHub 发布均根据提交消息生成,因此人工需要填写的唯一发布信息就是提交主题。在编写提交时强制执行格式,其余流程便可自动完成。
如果仓库已有 .releaserc*、使用了其他发布工具(changesets、release-it、standard-version),或没有 package.json,请停止并说明情况——在现有发布流水线之上再叠加一条,会产生重复标签和重复的变更日志条目。
前置条件:package.json、GitHub 远程仓库、Node ≥22.14——或 24.x 系列中的 ≥24.10(这是 semantic-release@^25 的最低引擎版本要求;该版本不再支持 Node 20/21/23;@commitlint/*@^21 需要 ≥22.12)——以及 GitHub Actions。
设置工作流
阶段 1:安装
npm install --save-dev \
@commitlint/cli@^21.0.0 @commitlint/config-conventional@^21.0.0 \
semantic-release@^25.0.0 @semantic-release/changelog@^6.0.0 \
@semantic-release/git@^10.0.0 husky@^9.0.0
| 软件包 | 用途 |
|---|---|
@commitlint/cli + config-conventional | 根据 Conventional Commits 规则验证提交消息 |
semantic-release | 自动处理版本升级、变更日志和发布 |
@semantic-release/changelog | 生成/更新 CHANGELOG.md |
@semantic-release/git | 将发布产物提交回仓库 |
husky | 管理 Git 钩子 |
检查:上面列出的每个软件包都出现在 devDependencies 中,并且 npm install 以 0 退出。
阶段 2:Commitlint
创建 commitlint.config.js——当 package.json 不包含 "type": "module" 时,使用 module.exports = {...},而不是 export default:
export default {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert',
]],
'subject-case': [2, 'always', 'lower-case'],
'header-max-length': [2, 'always', 100],
'body-max-line-length': [0], // disable — conflicts with semantic-release notes
},
};
检查:根目录存在 commitlint.config.js,且其模块语法与 package.json 中的 "type" 相匹配。
阶段 3:Semantic-release
创建 .releaserc.json。插件顺序就是执行顺序,且 branches 必须指定仓库实际使用的默认分支:
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" }],
["@semantic-release/git", {
"assets": ["CHANGELOG.md", "package.json", "package-lock.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}],
"@semantic-release/github"
]
}
预发布版本和多分支配置请参阅 references/REFERENCE.md。
检查:根目录存在 .releaserc.json,branches 指定默认分支,且插件顺序为 analyzer → notes-generator → changelog → git → github。
阶段 4:Husky 钩子
npx husky init # creates .husky/, adds "prepare": "husky"
echo 'npx --no -- commitlint --edit $1' > .husky/commit-msg # validate every commit message
根据项目自身的 package.json 脚本选择提交前检查,无需询问——按顺序采用第一个匹配项:存在 lint 和 test → npm run lint && npm test;否则选 test;再否则选 lint;最后选 build。
echo 'npm run lint && npm test' > .husky/pre-commit # substitute the matched command
如果这些脚本都不存在,运行 rm .husky/pre-commit——钩子运行不存在的脚本会导致每次提交都失败,而空钩子则会掩盖实际上没有任何检查这一事实。
确认 package.json 脚本中已添加 "prepare": "husky";如果 husky init 没有添加,就手动补上。它会在每次 npm install 时重新安装钩子;没有它,新克隆的仓库提交时将完全没有验证。
检查:.husky/commit-msg 包含 commitlint 命令,.husky/pre-commit 已设置或删除,并且 package.json 脚本中包含 "prepare": "husky"。
阶段 5:初始 CHANGELOG
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Semantic-release 会将每次发布的内容添加到此标题上方。
检查:根目录存在 CHANGELOG.md。
阶段 6:CI 工作流
创建 .github/workflows/release.yml:
name: Release
on:
push:
branches: [main]
permissions:
contents: write
issues: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # required — semantic-release needs full history
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- run: npm ci
- run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # drop unless you added @semantic-release/npm
Actions 会自动提供 GITHUB_TOKEN。如果默认分支不是 main,请同时更新此处和 .releaserc.json 中的 branches。
检查:存在 .github/workflows/release.yml,其中的 branches 与 .releaserc.json 相匹配,并且只有在插件列表中包含 @semantic-release/npm 时才设置 NPM_TOKEN。
快速参考
提交类型 → 发布版本:
| 提交 | 发布版本 |
|---|---|
feat: … | 次要版本 |
fix: … | 补丁版本 |
feat!: … 或 BREAKING CHANGE: 页脚 | 主要版本 |
docs style refactor perf test build ci chore revert | 无 |
创建: commitlint.config.js · .releaserc.json · .husky/commit-msg · .husky/pre-commit(或删除)· CHANGELOG.md · .github/workflows/release.yml,以及 package.json 中的 devDependencies 和 prepare 脚本。
冒烟测试: echo "feat: test" | npx commitlint 以状态码 0 退出;echo "bad" | npx commitlint 以非零状态码退出。
示例
✅ 可以顺利触发发布的主题——类型前缀、可选范围、小写:
feat(auth): add OAuth login # minor bump
fix(api): handle null response # patch bump
feat!: drop the v1 endpoints # major bump
❌ 会被拒绝,或会发布功能却不生成任何版本的主题:
updated auth stuff # no type prefix — commitlint rejects the commit
feat: Add OAuth login # capitalized — the subject-case rule rejects it
chore: add OAuth login # accepted, but chore never releases; the feature ships unversioned
✅ 在页脚声明破坏性变更,以便生成的说明解释该变更:
feat(api): add pagination
Adds offset/limit to all list endpoints.
BREAKING CHANGE: removed `page` in favor of `offset`
✅ commitlint.config.js 语法与包的模块系统匹配:
// package.json has no "type": "module"
module.exports = { extends: ['@commitlint/config-conventional'] };
❌ 同一个包中的同一个文件——commitlint 在加载配置时抛出错误,导致每次提交都会在任何规则运行前失败:
export default { extends: ['@commitlint/config-conventional'] };
注意事项
- 显式的
plugins数组会替换默认项,而不是扩展默认项。 semantic-release 的默认列表包含@semantic-release/npm;Phase 3 配置省略了它,因此不会向 npm 发布任何内容。如果包需要发布,请在"@semantic-release/github"前添加"@semantic-release/npm"——否则请从工作流中移除NPM_TOKEN,因为它不会发挥作用。(文档) @semantic-release/changelog必须位于@semantic-release/git之前。 如果顺序颠倒,git 插件会提交尚未写入的CHANGELOG.md。body-max-line-length: [0]是有意设置的,并非疏忽。 semantic-release 会将完整的发布说明写入它自己的发布提交正文,这会超出默认的 100 字符限制,导致发布提交无法通过自身的钩子检查。subject-case: lower-case会拒绝首字母大写的主题。feat: Add feature会失败;feat: add feature会通过。这是最常见的“但我的消息看起来没问题”式拒绝。- CI 中必须设置
fetch-depth: 0。 Actions 默认会浅克隆,导致 semantic-release 无法获取标签历史记录——并因ENOGITHEAD或EGITNOBRANCH而失败。 - 在 git 插件的
message中加入[skip ci]可避免无限循环。 发布提交会进入发布分支,否则会再次触发工作流。 - 让
commitlint.config.js与包的模块系统匹配——参见最后一组示例;不匹配会导致每次提交都在任何规则运行前失败。
深入参考
预发布分支配置和故障排查(husky 钩子未运行、重复的变更日志条目、CI 循环、ENOGITHEAD)位于 references/REFERENCE.md 中——当某个阶段的 Check 行失败时再加载,不要预先加载。
参考资料
Conventional Commits · SemVer · semantic-release · commitlint · Husky。当设置跨越多个时段时,可与 track-session 搭配使用。