semantic-release 是一个自动化版本管理和包发布工具,根据提交信息自动确定版本号、生成 CHANGELOG 并发布。
提交代码 → 分析提交 → 确定版本 → 生成 Notes → 更新 CHANGELOG → 发布 → Git 提交
↓ ↓ ↓ ↓ ↓ ↓ ↓
Git Push Analyze Calc Ver Generate Log Update Log Publish Commit| 概念 | 说明 |
|---|---|
| Commit Analyzer | 分析提交信息,确定版本号变化 |
| Release Notes Generator | 生成发布说明文档 |
| Changelog | 更新 CHANGELOG.md 文件 |
| NPM Plugin | 发布包到 npm registry |
| Git Plugin | 提交版本变更到 Git 仓库 |
| GitHub Plugin | 创建 GitHub Release |
pnpm add semantic-release -D# 核心插件
pnpm add @semantic-release/commit-analyzer -D
pnpm add @semantic-release/release-notes-generator -D
pnpm add @semantic-release/changelog -D
pnpm add @semantic-release/npm -D
pnpm add @semantic-release/git -D
pnpm add @semantic-release/github -Dmodule.exports = {
branches: ['main', { name: 'beta', prerelease: true }],
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
'@semantic-release/changelog',
'@semantic-release/npm',
'@semantic-release/github',
'@semantic-release/git'
]
}遵循 Conventional Commits 规范:
<type>(<scope>): <subject>
<body>
<footer>| 类型 | 版本变化 | 示例 |
|---|---|---|
feat | Minor (1.0.0 → 1.1.0) | feat: add login feature |
fix | Patch (1.0.0 → 1.0.1) | fix: resolve login bug |
feat! 或 BREAKING CHANGE | Major (1.0.0 → 2.0.0) | feat!: change API |
semantic-release 遵循 Semantic Versioning 规范:
MAJOR.MINOR.PATCH
MAJOR - 不兼容的 API 变更
MINOR - 向后兼容的新功能
PATCH - 向后兼容的问题修复// 版本计算示例
当前版本: 1.0.0
提交记录:
- feat: add feature A → 1.1.0 (Minor)
- fix: fix bug B → 1.1.1 (Patch)
- feat!: breaking change → 2.0.0 (Major)
最终版本: 2.0.0 (取最高级别变更)// 分支配置
branches: [
'main', // 正式版本: 1.0.0
{ name: 'beta', prerelease: true }, // 预发布: 1.0.0-beta.1
{ name: 'alpha', prerelease: true } // 预发布: 1.0.0-alpha.1
]分析提交信息,确定版本号:
{
plugins: [
['@semantic-release/commit-analyzer', {
preset: 'conventionalcommits',
releaseRules: [
{ type: 'feat', release: 'minor' },
{ type: 'fix', release: 'patch' },
{ type: 'perf', release: 'patch' },
{ breaking: true, release: 'major' }
]
}]
]
}| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
preset | String | angular | 提交信息规范预设 |
presetConfig | Object | {} | 预设配置 |
releaseRules | Array | [] | 自定义版本规则 |
parserOpts | Object | {} | 解析器选项 |
releaseRules: [
{ type: 'feat', release: 'minor' },
{ type: 'fix', release: 'patch' },
{ type: 'perf', release: 'patch' },
{ type: 'refactor', release: 'patch' },
{ type: 'docs', release: false }, // 不触发发布
{ type: 'style', release: false },
{ type: 'chore', release: false },
{ type: 'test', release: false },
{ breaking: true, release: 'major' } // 破坏性变更
]生成发布说明:
{
plugins: [
['@semantic-release/release-notes-generator', {
preset: 'conventionalcommits',
presetConfig: {
types: [
{ type: 'feat', section: 'Features' },
{ type: 'fix', section: 'Bug Fixes' },
{ type: 'perf', section: 'Performance' }
]
}
}]
]
}| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
preset | String | angular | 提交信息规范预设 |
presetConfig | Object | {} | 预设配置 |
writerOpts | Object | {} | 写入器选项 |
linkCompare | Boolean | true | 是否包含版本比较链接 |
linkReferences | Boolean | false | 是否链接提交引用 |
生成/更新 CHANGELOG.md:
pnpm add @semantic-release/changelog -D{
plugins: [
['@semantic-release/changelog', {
changelogFile: 'CHANGELOG.md',
changelogTitle: '# Changelog'
}]
]
}| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
changelogFile | String | 'CHANGELOG.md' | CHANGELOG 文件路径 |
changelogTitle | String | '# Changelog' | CHANGELOG 标题 |
发布到 npm:
{
plugins: [
['@semantic-release/npm', {
npmPublish: true,
tarballDir: 'dist'
}]
]
}| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npmPublish | Boolean | true | 是否发布到 npm |
tarballDir | String | '.' | tarball 文件存储目录 |
pkgRoot | String | '.' | package.json 所在目录 |
提交更改:
pnpm add @semantic-release/git -D{
plugins: [
['@semantic-release/git', {
assets: ['package.json', 'CHANGELOG.md', 'dist/**'],
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}'
}]
]
}| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
assets | Array | ['CHANGELOG.md', 'package.json'] | 要提交的文件列表 |
message | String | 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}' | 提交信息模板 |
| 变量 | 说明 |
|---|---|
${nextRelease.version} | 新版本号 |
${nextRelease.notes} | 发布说明 |
${nextRelease.gitTag} | Git 标签 |
${lastRelease.gitTag} | 上一个版本的 Git 标签 |
创建 GitHub Release:
{
plugins: [
['@semantic-release/github', {
assets: [
{ path: 'dist/*.tgz', label: 'Distribution' }
]
}]
]
}| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
assets | Array | [] | 要附加到 Release 的文件 |
successComment | Boolean/String | false | PR 成功后添加的评论 |
failTitle | Boolean/String | 'The automated release is failing 🚨' | 失败 Issue 标题 |
labels | Boolean/Array | false | 失败 Issue 标签 |
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: pnpm install
- run: pnpm build
- run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}release:
stage: deploy
script:
- pnpm install
- pnpm build
- npx semantic-release
only:
- main
variables:
GITLAB_TOKEN: $CI_JOB_TOKEN
NPM_TOKEN: $NPM_TOKEN// .releaserc.js
module.exports = {
branches: [
'main',
{ name: 'beta', prerelease: true },
{ name: 'alpha', prerelease: true }
],
plugins: [
[
'@semantic-release/commit-analyzer',
{
preset: 'conventionalcommits',
releaseRules: [
{ type: 'feat', release: 'minor' },
{ type: 'fix', release: 'patch' },
{ type: 'perf', release: 'patch' },
{ type: 'refactor', release: 'patch' },
{ type: 'docs', release: false },
{ type: 'style', release: false },
{ type: 'chore', release: false },
{ type: 'test', release: false }
]
}
],
[
'@semantic-release/release-notes-generator',
{
preset: 'conventionalcommits',
presetConfig: {
types: [
{ type: 'feat', section: '✨ Features' },
{ type: 'fix', section: '🐛 Bug Fixes' },
{ type: 'perf', section: '⚡ Performance' },
{ type: 'refactor', section: '♻️ Code Refactoring' }
]
}
}
],
[
'@semantic-release/changelog',
{
changelogFile: 'CHANGELOG.md'
}
],
'@semantic-release/npm',
[
'@semantic-release/git',
{
assets: ['package.json', 'CHANGELOG.md'],
message: 'chore(release): ${nextRelease.version} [skip ci]'
}
],
'@semantic-release/github'
]
}确保 package.json 中配置:
{
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/user/repo.git"
}
}# 模拟发布过程(不实际发布)
npx semantic-release --dry-run
# 指定分支
npx semantic-release --branch beta[skip ci] 避免循环触发可能原因:
release: falsebranches 配置中解决方案:
# 使用 dry-run 诊断
npx semantic-release --dry-run
# 检查提交信息
git log --oneline | grep -E '^(feat|fix|perf|refactor)'// 在提交信息中添加 [skip release] 或 [release skip]
git commit -m "feat: add feature [skip release]"// .releaserc.js
module.exports = {
branches: [
'main',
{ name: 'beta', prerelease: true },
{ name: 'alpha', prerelease: true }
]
}# 推送到预发布分支
git push origin HEAD:beta检查步骤:
--dry-run 验证配置回滚方案:
# 删除远程标签
git push --delete origin v1.0.0
# 使用 npm deprecate 标记版本
npm deprecate package-name@1.0.0 "This version has issues"// 使用 @semantic-release/exec 插件
module.exports = {
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
[
'@semantic-release/exec',
{
prepareCmd: 'echo ${nextRelease.version}'
}
]
]
}// 使用 @semantic-release/exec + lerna
module.exports = {
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
[
'@semantic-release/exec',
{
prepareCmd: 'lerna version ${nextRelease.version} --yes --no-git-tag-version',
publishCmd: 'lerna publish from-package --yes'
}
]
]
}# 启用详细日志
DEBUG=semantic-release:* npx semantic-release
# 特定插件调试
DEBUG=semantic-release:commit-analyzer npx semantic-release --dry-runError: ENOGHTOKEN - No GitHub token specified解决方案:
# GitHub Actions
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Error: ENONPMTOKEN - No npm token specified解决方案:
NPM_TOKENError: EINVALIDVERSION - Invalid version解决方案:
# 检查当前版本
cat package.json | grep version
# 确保版本号符合 SemVer
# 合法: 1.0.0, 1.0.0-beta.1
# 非法: v1.0.0, 1.0, 1.0.0.0Error: ENOPKG - No package.json found解决方案:
// 指定 package.json 路径
module.exports = {
plugins: [
['@semantic-release/npm', {
pkgRoot: './packages/core'
}]
]
}// 精简插件列表,只保留必要的
module.exports = {
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
'@semantic-release/npm',
'@semantic-release/git'
]
}semantic-release 默认按插件顺序执行,某些插件可以合并:
// 不推荐:多个插件分别配置
module.exports = {
plugins: [
['@semantic-release/changelog', { changelogFile: 'CHANGELOG.md' }],
'@semantic-release/npm',
'@semantic-release/git'
]
}
// 推荐:合并配置,减少 Git 操作
module.exports = {
plugins: [
'@semantic-release/changelog',
'@semantic-release/npm',
['@semantic-release/git', {
assets: ['package.json', 'package-lock.json', 'CHANGELOG.md']
}]
]
}| 特性 | semantic-release | standard-version | Changesets |
|---|---|---|---|
| 自动化程度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 学习曲线 | 中等 | 低 | 中等 |
| Monorepo 支持 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 手动控制 | 低 | 高 | 中 |
| CI/CD 集成 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 变更跟踪 | 提交级别 | 提交级别 | 变更集级别 |
| 适用场景 | 开源项目、自动发布 | 小型项目、手动控制 | Monorepo、多包管理 |