changelog-automation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseChangelog Automation
变更日志自动化
Patterns and tools for automating changelog generation, release notes, and version management following industry standards.
遵循行业标准的变更日志生成、发布说明和版本管理的模式与工具。
When to Use This Skill
适用场景
- Setting up automated changelog generation
- Implementing Conventional Commits
- Creating release note workflows
- Standardizing commit message formats
- Generating GitHub/GitLab release notes
- Managing semantic versioning
- 设置自动化变更日志生成
- 实施Conventional Commits规范
- 创建发布说明工作流
- 标准化提交消息格式
- 生成GitHub/GitLab发布说明
- 管理语义化版本控制
Core Concepts
核心概念
1. Keep a Changelog Format
1. Keep a Changelog格式
markdown
undefinedmarkdown
undefinedChangelog
Changelog
All notable changes to this project will be 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 will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[Unreleased]
[Unreleased]
Added
Added
- New feature X
- New feature X
[1.2.0] - 2024-01-15
[1.2.0] - 2024-01-15
Added
Added
- User profile avatars
- Dark mode support
- User profile avatars
- Dark mode support
Changed
Changed
- Improved loading performance by 40%
- Improved loading performance by 40%
Deprecated
Deprecated
- Old authentication API (use v2)
- Old authentication API (use v2)
Removed
Removed
- Legacy payment gateway
- Legacy payment gateway
Fixed
Fixed
- Login timeout issue (#123)
- Login timeout issue (#123)
Security
Security
- Updated dependencies for CVE-2024-1234
undefined- Updated dependencies for CVE-2024-1234
undefined2. Conventional Commits
2. Conventional Commits规范
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]| Type | Description | Changelog Section |
|---|---|---|
| New feature | Added |
| Bug fix | Fixed |
| Documentation | (usually excluded) |
| Formatting | (usually excluded) |
| Code restructure | Changed |
| Performance | Changed |
| Tests | (usually excluded) |
| Maintenance | (usually excluded) |
| CI changes | (usually excluded) |
| Build system | (usually excluded) |
| Revert commit | Removed |
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]| 类型 | 描述 | 变更日志章节 |
|---|---|---|
| 新功能 | Added |
| 修复Bug | Fixed |
| 文档更新 | (通常不包含) |
| 代码格式调整 | (通常不包含) |
| 代码重构 | Changed |
| 性能优化 | Changed |
| 测试相关 | (通常不包含) |
| 维护任务 | (通常不包含) |
| CI流程变更 | (通常不包含) |
| 构建系统变更 | (通常不包含) |
| 回滚提交 | Removed |
3. Semantic Versioning
3. 语义化版本控制(Semantic Versioning)
MAJOR.MINOR.PATCH
MAJOR: Breaking changes (feat! or BREAKING CHANGE)
MINOR: New features (feat)
PATCH: Bug fixes (fix)MAJOR.MINOR.PATCH
MAJOR: Breaking changes (feat! or BREAKING CHANGE)
MINOR: New features (feat)
PATCH: Bug fixes (fix)Implementation
实现方法
Method 1: Conventional Changelog (Node.js)
方法1:Conventional Changelog(Node.js)
bash
undefinedbash
undefinedInstall tools
Install tools
npm install -D @commitlint/cli @commitlint/config-conventional
npm install -D husky
npm install -D standard-version
npm install -D @commitlint/cli @commitlint/config-conventional
npm install -D husky
npm install -D standard-version
or
or
npm install -D semantic-release
npm install -D semantic-release
Setup commitlint
Setup commitlint
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'ci',
'build',
'revert',
],
],
'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']],
'subject-max-length': [2, 'always', 72],
},
};
EOF
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'ci',
'build',
'revert',
],
],
'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']],
'subject-max-length': [2, 'always', 72],
},
};
EOF
Setup husky
Setup husky
npx husky init
echo "npx --no -- commitlint --edit $1" > .husky/commit-msg
undefinednpx husky init
echo "npx --no -- commitlint --edit $1" > .husky/commit-msg
undefinedMethod 2: standard-version Configuration
方法2:standard-version配置
javascript
// .versionrc.js
module.exports = {
types: [
{ type: "feat", section: "Features" },
{ type: "fix", section: "Bug Fixes" },
{ type: "perf", section: "Performance Improvements" },
{ type: "revert", section: "Reverts" },
{ type: "docs", section: "Documentation", hidden: true },
{ type: "style", section: "Styles", hidden: true },
{ type: "chore", section: "Miscellaneous", hidden: true },
{ type: "refactor", section: "Code Refactoring", hidden: true },
{ type: "test", section: "Tests", hidden: true },
{ type: "build", section: "Build System", hidden: true },
{ type: "ci", section: "CI/CD", hidden: true },
],
commitUrlFormat: "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}",
compareUrlFormat:
"{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}",
issueUrlFormat: "{{host}}/{{owner}}/{{repository}}/issues/{{id}}",
userUrlFormat: "{{host}}/{{user}}",
releaseCommitMessageFormat: "chore(release): {{currentTag}}",
scripts: {
prebump: 'echo "Running prebump"',
postbump: 'echo "Running postbump"',
prechangelog: 'echo "Running prechangelog"',
postchangelog: 'echo "Running postchangelog"',
},
};json
// package.json scripts
{
"scripts": {
"release": "standard-version",
"release:minor": "standard-version --release-as minor",
"release:major": "standard-version --release-as major",
"release:patch": "standard-version --release-as patch",
"release:dry": "standard-version --dry-run"
}
}javascript
// .versionrc.js
module.exports = {
types: [
{ type: "feat", section: "Features" },
{ type: "fix", section: "Bug Fixes" },
{ type: "perf", section: "Performance Improvements" },
{ type: "revert", section: "Reverts" },
{ type: "docs", section: "Documentation", hidden: true },
{ type: "style", section: "Styles", hidden: true },
{ type: "chore", section: "Miscellaneous", hidden: true },
{ type: "refactor", section: "Code Refactoring", hidden: true },
{ type: "test", section: "Tests", hidden: true },
{ type: "build", section: "Build System", hidden: true },
{ type: "ci", section: "CI/CD", hidden: true },
],
commitUrlFormat: "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}",
compareUrlFormat:
"{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}",
issueUrlFormat: "{{host}}/{{owner}}/{{repository}}/issues/{{id}}",
userUrlFormat: "{{host}}/{{user}}",
releaseCommitMessageFormat: "chore(release): {{currentTag}}",
scripts: {
prebump: 'echo "Running prebump"',
postbump: 'echo "Running postbump"',
prechangelog: 'echo "Running prechangelog"',
postchangelog: 'echo "Running postchangelog"',
},
};json
// package.json scripts
{
"scripts": {
"release": "standard-version",
"release:minor": "standard-version --release-as minor",
"release:major": "standard-version --release-as major",
"release:patch": "standard-version --release-as patch",
"release:dry": "standard-version --dry-run"
}
}Method 3: semantic-release (Full Automation)
方法3:semantic-release(全自动化)
javascript
// release.config.js
module.exports = {
branches: [
"main",
{ name: "beta", prerelease: true },
{ name: "alpha", prerelease: true },
],
plugins: [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
changelogFile: "CHANGELOG.md",
},
],
[
"@semantic-release/npm",
{
npmPublish: true,
},
],
[
"@semantic-release/github",
{
assets: ["dist/**/*.js", "dist/**/*.css"],
},
],
[
"@semantic-release/git",
{
assets: ["CHANGELOG.md", "package.json"],
message:
"chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}",
},
],
],
};javascript
// release.config.js
module.exports = {
branches: [
"main",
{ name: "beta", prerelease: true },
{ name: "alpha", prerelease: true },
],
plugins: [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
changelogFile: "CHANGELOG.md",
},
],
[
"@semantic-release/npm",
{
npmPublish: true,
},
],
[
"@semantic-release/github",
{
assets: ["dist/**/*.js", "dist/**/*.css"],
},
],
[
"@semantic-release/git",
{
assets: ["CHANGELOG.md", "package.json"],
message:
"chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}",
},
],
],
};Method 4: GitHub Actions Workflow
方法4:GitHub Actions工作流
yaml
undefinedyaml
undefined.github/workflows/release.yml
.github/workflows/release.yml
name: Release
on:
push:
branches: [main]
workflow_dispatch:
inputs:
release_type:
description: "Release type"
required: true
default: "patch"
type: choice
options:
- patch
- minor
- major
permissions:
contents: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Run semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-releaseAlternative: manual release with standard-version
manual-release:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Bump version and generate changelog
run: npx standard-version --release-as ${{ inputs.release_type }}
- name: Push changes
run: git push --follow-tags origin main
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.version.outputs.tag }}
body_path: RELEASE_NOTES.md
generate_release_notes: trueundefinedname: Release
on:
push:
branches: [main]
workflow_dispatch:
inputs:
release_type:
description: "Release type"
required: true
default: "patch"
type: choice
options:
- patch
- minor
- major
permissions:
contents: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Run semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-releaseAlternative: manual release with standard-version
manual-release:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Bump version and generate changelog
run: npx standard-version --release-as ${{ inputs.release_type }}
- name: Push changes
run: git push --follow-tags origin main
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.version.outputs.tag }}
body_path: RELEASE_NOTES.md
generate_release_notes: trueundefinedMethod 5: git-cliff (Rust-based, Fast)
方法5:git-cliff(基于Rust,速度快)
toml
undefinedtoml
undefinedcliff.toml
cliff.toml
[changelog]
header = """
[changelog]
header = """
Changelog
Changelog
All notable changes to this project will be documented in this file.
"""
body = """
{% if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} {% else %}
## [Unreleased] {% endif %}
{% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} - {% if commit.scope %}{{ commit.scope }}: {% endif %}
{{ commit.message | upper_first }}
{% if commit.github.pr_number %} ([#{{ commit.github.pr_number }}](https://github.com/owner/repo/pull/{{ commit.github.pr_number }})){% endif %}
{% endfor %} {% endfor %} """ footer = """ {% for release in releases -%} {% if release.version -%} {% if release.previous.version -%} [{{ release.version | trim_start_matches(pat="v") }}]:
https://github.com/owner/repo/compare/{{ release.previous.version }}...{{ release.version }} {% endif -%} {% else -%} [unreleased]: https://github.com/owner/repo/compare/{{ release.previous.version }}...HEAD {% endif -%} {% endfor %} """ trim = true
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} {% else %}
## [Unreleased] {% endif %}
{% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} - {% if commit.scope %}{{ commit.scope }}: {% endif %}
{{ commit.message | upper_first }}
{% if commit.github.pr_number %} ([#{{ commit.github.pr_number }}](https://github.com/owner/repo/pull/{{ commit.github.pr_number }})){% endif %}
{% endfor %} {% endfor %} """ footer = """ {% for release in releases -%} {% if release.version -%} {% if release.previous.version -%} [{{ release.version | trim_start_matches(pat="v") }}]:
https://github.com/owner/repo/compare/{{ release.previous.version }}...{{ release.version }} {% endif -%} {% else -%} [unreleased]: https://github.com/owner/repo/compare/{{ release.previous.version }}...HEAD {% endif -%} {% endfor %} """ trim = true
[git]
conventional_commits = true
filter_unconventional = true
split_commits = false
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^doc", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactoring" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore\(release\)", skip = true },
{ message = "^chore", group = "Miscellaneous" },
]
filter_commits = false
tag_pattern = "v[0-9]*"
skip_tags = ""
ignore_tags = ""
topo_order = false
sort_commits = "oldest"
[github]
owner = "owner"
repo = "repo"
```bashAll notable changes to this project will be documented in this file.
"""
body = """
{% if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} {% else %}
## [Unreleased] {% endif %}
{% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} - {% if commit.scope %}{{ commit.scope }}: {% endif %}
{{ commit.message | upper_first }}
{% if commit.github.pr_number %} ([#{{ commit.github.pr_number }}](https://github.com/owner/repo/pull/{{ commit.github.pr_number }})){% endif %}
{% endfor %} {% endfor %} """ footer = """ {% for release in releases -%} {% if release.version -%} {% if release.previous.version -%} [{{ release.version | trim_start_matches(pat="v") }}]:
https://github.com/owner/repo/compare/{{ release.previous.version }}...{{ release.version }} {% endif -%} {% else -%} [unreleased]: https://github.com/owner/repo/compare/{{ release.previous.version }}...HEAD {% endif -%} {% endfor %} """ trim = true
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} {% else %}
## [Unreleased] {% endif %}
{% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} - {% if commit.scope %}{{ commit.scope }}: {% endif %}
{{ commit.message | upper_first }}
{% if commit.github.pr_number %} ([#{{ commit.github.pr_number }}](https://github.com/owner/repo/pull/{{ commit.github.pr_number }})){% endif %}
{% endfor %} {% endfor %} """ footer = """ {% for release in releases -%} {% if release.version -%} {% if release.previous.version -%} [{{ release.version | trim_start_matches(pat="v") }}]:
https://github.com/owner/repo/compare/{{ release.previous.version }}...{{ release.version }} {% endif -%} {% else -%} [unreleased]: https://github.com/owner/repo/compare/{{ release.previous.version }}...HEAD {% endif -%} {% endfor %} """ trim = true
[git]
conventional_commits = true
filter_unconventional = true
split_commits = false
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^doc", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactoring" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore\(release\)", skip = true },
{ message = "^chore", group = "Miscellaneous" },
]
filter_commits = false
tag_pattern = "v[0-9]*"
skip_tags = ""
ignore_tags = ""
topo_order = false
sort_commits = "oldest"
[github]
owner = "owner"
repo = "repo"
```bashGenerate changelog
Generate changelog
git cliff -o CHANGELOG.md
git cliff -o CHANGELOG.md
Generate for specific range
Generate for specific range
git cliff v1.0.0..v2.0.0 -o RELEASE_NOTES.md
git cliff v1.0.0..v2.0.0 -o RELEASE_NOTES.md
Preview without writing
Preview without writing
git cliff --unreleased --dry-run
undefinedgit cliff --unreleased --dry-run
undefinedMethod 6: Python (commitizen)
方法6:Python(commitizen)
toml
undefinedtoml
undefinedpyproject.toml
pyproject.toml
[tool.commitizen]
name = "cz_conventional_commits"
version = "1.0.0"
version_files = [
"pyproject.toml:version",
"src/init.py:version",
]
tag_format = "v$version"
update_changelog_on_bump = true
changelog_incremental = true
changelog_start_rev = "v0.1.0"
[tool.commitizen.customize]
message_template = "{{change_type}}{% if scope %}({{scope}}){% endif %}: {{message}}"
schema = "<type>(<scope>): <subject>"
schema_pattern = "^(feat|fix|docs|style|refactor|perf|test|chore)(\(\w+\))?:\s.*"
bump_pattern = "^(feat|fix|perf|refactor)"
bump_map = {"feat" = "MINOR", "fix" = "PATCH", "perf" = "PATCH", "refactor" = "PATCH"}
```bash[tool.commitizen]
name = "cz_conventional_commits"
version = "1.0.0"
version_files = [
"pyproject.toml:version",
"src/init.py:version",
]
tag_format = "v$version"
update_changelog_on_bump = true
changelog_incremental = true
changelog_start_rev = "v0.1.0"
[tool.commitizen.customize]
message_template = "{{change_type}}{% if scope %}({{scope}}){% endif %}: {{message}}"
schema = "<type>(<scope>): <subject>"
schema_pattern = "^(feat|fix|docs|style|refactor|perf|test|chore)(\(\w+\))?:\s.*"
bump_pattern = "^(feat|fix|perf|refactor)"
bump_map = {"feat" = "MINOR", "fix" = "PATCH", "perf" = "PATCH", "refactor" = "PATCH"}
```bashInstall
Install
pip install commitizen
pip install commitizen
Create commit interactively
Create commit interactively
cz commit
cz commit
Bump version and update changelog
Bump version and update changelog
cz bump --changelog
cz bump --changelog
Check commits
Check commits
cz check --rev-range HEAD~5..HEAD
undefinedcz check --rev-range HEAD~5..HEAD
undefinedRelease Notes Templates
发布说明模板
GitHub Release Template
GitHub发布模板
markdown
undefinedmarkdown
undefinedWhat's Changed
What's Changed
🚀 Features
🚀 Features
{{ range .Features }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
{{ range .Features }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
🐛 Bug Fixes
🐛 Bug Fixes
{{ range .Fixes }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
{{ range .Fixes }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
📚 Documentation
📚 Documentation
{{ range .Docs }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
{{ range .Docs }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
🔧 Maintenance
🔧 Maintenance
{{ range .Chores }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
{{ range .Chores }}
- {{ .Title }} by @{{ .Author }} in #{{ .PR }} {{ end }}
New Contributors
New Contributors
{{ range .NewContributors }}
- @{{ .Username }} made their first contribution in #{{ .PR }} {{ end }}
Full Changelog: https://github.com/owner/repo/compare/v{{ .Previous }}...v{{ .Current }}
undefined{{ range .NewContributors }}
- @{{ .Username }} made their first contribution in #{{ .PR }} {{ end }}
Full Changelog: https://github.com/owner/repo/compare/v{{ .Previous }}...v{{ .Current }}
undefinedInternal Release Notes
内部发布说明
markdown
undefinedmarkdown
undefinedRelease v2.1.0 - January 15, 2024
Release v2.1.0 - January 15, 2024
Summary
Summary
This release introduces dark mode support and improves checkout performance
by 40%. It also includes important security updates.
This release introduces dark mode support and improves checkout performance
by 40%. It also includes important security updates.
Highlights
Highlights
🌙 Dark Mode
🌙 Dark Mode
Users can now switch to dark mode from settings. The preference is
automatically saved and synced across devices.
Users can now switch to dark mode from settings. The preference is
automatically saved and synced across devices.
⚡ Performance
⚡ Performance
- Checkout flow is 40% faster
- Reduced bundle size by 15%
- Checkout flow is 40% faster
- Reduced bundle size by 15%
Breaking Changes
Breaking Changes
None in this release.
None in this release.
Upgrade Guide
Upgrade Guide
No special steps required. Standard deployment process applies.
No special steps required. Standard deployment process applies.
Known Issues
Known Issues
- Dark mode may flicker on initial load (fix scheduled for v2.1.1)
- Dark mode may flicker on initial load (fix scheduled for v2.1.1)
Dependencies Updated
Dependencies Updated
| Package | From | To | Reason |
|---|---|---|---|
| react | 18.2.0 | 18.3.0 | Performance improvements |
| lodash | 4.17.20 | 4.17.21 | Security patch |
undefined| Package | From | To | Reason |
|---|---|---|---|
| react | 18.2.0 | 18.3.0 | Performance improvements |
| lodash | 4.17.20 | 4.17.21 | Security patch |
undefinedCommit Message Examples
提交消息示例
bash
undefinedbash
undefinedFeature with scope
Feature with scope
feat(auth): add OAuth2 support for Google login
feat(auth): add OAuth2 support for Google login
Bug fix with issue reference
Bug fix with issue reference
fix(checkout): resolve race condition in payment processing
Closes #123
fix(checkout): resolve race condition in payment processing
Closes #123
Breaking change
Breaking change
feat(api)!: change user endpoint response format
BREAKING CHANGE: The user endpoint now returns instead of .
Migration guide: Update all API consumers to use the new field name.
userIdidfeat(api)!: change user endpoint response format
BREAKING CHANGE: The user endpoint now returns instead of .
Migration guide: Update all API consumers to use the new field name.
userIdidMultiple paragraphs
Multiple paragraphs
fix(database): handle connection timeouts gracefully
Previously, connection timeouts would cause the entire request to fail
without retry. This change implements exponential backoff with up to
3 retries before failing.
The timeout threshold has been increased from 5s to 10s based on p99
latency analysis.
Fixes #456
Reviewed-by: @alice
undefinedfix(database): handle connection timeouts gracefully
Previously, connection timeouts would cause the entire request to fail
without retry. This change implements exponential backoff with up to
3 retries before failing.
The timeout threshold has been increased from 5s to 10s based on p99
latency analysis.
Fixes #456
Reviewed-by: @alice
undefinedBest Practices
最佳实践
Do's
建议做法
- Follow Conventional Commits - Enables automation
- Write clear messages - Future you will thank you
- Reference issues - Link commits to tickets
- Use scopes consistently - Define team conventions
- Automate releases - Reduce manual errors
- 遵循Conventional Commits规范 - 支持自动化流程
- 编写清晰的提交消息 - 方便未来回溯
- 关联问题工单 - 将提交与任务关联
- 一致使用作用域 - 定义团队规范
- 自动化发布流程 - 减少人为错误
Don'ts
避免做法
- Don't mix changes - One logical change per commit
- Don't skip validation - Use commitlint
- Don't manual edit - Generated changelogs only
- Don't forget breaking changes - Mark with or footer
! - Don't ignore CI - Validate commits in pipeline
- 不要混合变更 - 每次提交只包含一个逻辑变更
- 不要跳过验证 - 使用commitlint进行校验
- 不要手动编辑 - 仅使用自动生成的变更日志
- 不要遗漏破坏性变更 - 使用或脚注标记
! - 不要忽略CI校验 - 在流水线中验证提交