Changelog Generator
更新日志生成器
When invoked, analyze git history and generate/update the changelog:
Get commits since last tag
Get commits since last tag
git log $(git describe --tags --abbrev=0 2>/dev/null || echo "")..HEAD --pretty=format:"%h %s" --no-merges
git log $(git describe --tags --abbrev=0 2>/dev/null || echo "")..HEAD --pretty=format:"%h %s" --no-merges
Get all tags for reference
Get all tags for reference
git tag --sort=-version:refname | head -10
git tag --sort=-version:refname | head -10
Changelog Format (Keep a Changelog)
更新日志格式(Keep a Changelog)
- Changes in existing functionality
- Changes in existing functionality
- Soon-to-be removed features
- Soon-to-be removed features
[1.1.0] - 2024-01-26
[1.1.0] - 2024-01-26
- New skill for state management
- New skill with Zod + Conform integration
- New skill for Shopify apps
- New skill for state management
- New skill with Zod + Conform integration
- New skill for Shopify apps
- Updated agent with new skills
- Updated agent with security-hardening skill
- Updated agent with new skills
- Updated agent with security-hardening skill
[1.0.4] - 2024-01-20
[1.0.4] - 2024-01-20
Conventional Commits Mapping
Conventional Commits映射
Map commit prefixes to changelog categories:
| Commit Prefix | Changelog Category |
|---|
| Added |
| Fixed |
| Changed (Documentation) |
| Changed (Formatting) |
| Changed |
| Changed (Performance) |
| (Usually omitted) |
| Changed (Build system) |
| (Usually omitted) |
| (Usually omitted) |
| Removed or Fixed |
| / | Security |
| Deprecated |
| / | Removed |
将提交前缀映射到更新日志分类:
| 提交前缀 | 更新日志分类 |
|---|
| Added |
| Fixed |
| Changed (文档) |
| Changed (格式) |
| Changed |
| Changed (性能) |
| (通常省略) |
| Changed (构建系统) |
| (通常省略) |
| (通常省略) |
| Removed 或 Fixed |
| / | Security |
| Deprecated |
| / | Removed |
Step 1: Analyze Git History
步骤1:分析Git历史
Get commits since last release
Get commits since last release
git log v1.0.4..HEAD --pretty=format:"%H|%s|%an|%ad" --date=short
git log v1.0.4..HEAD --pretty=format:"%H|%s|%an|%ad" --date=short
Or since a specific date
Or since a specific date
git log --since="2024-01-01" --pretty=format:"%H|%s|%an|%ad" --date=short
git log --since="2024-01-01" --pretty=format:"%H|%s|%an|%ad" --date=short
Step 2: Categorize Changes
步骤2:变更分类
Parse each commit message and categorize:
typescript
interface ChangeEntry {
category: 'Added' | 'Changed' | 'Deprecated' | 'Removed' | 'Fixed' | 'Security';
description: string;
commit: string;
scope?: string;
breaking?: boolean;
}
function categorizeCommit(message: string): ChangeEntry | null {
const conventionalRegex = /^(\w+)(?:\(([^)]+)\))?(!)?:\s*(.+)$/;
const match = message.match(conventionalRegex);
if (!match) return null;
const [, type, scope, breaking, description] = match;
const categoryMap: Record<string, ChangeEntry['category']> = {
feat: 'Added',
fix: 'Fixed',
docs: 'Changed',
style: 'Changed',
refactor: 'Changed',
perf: 'Changed',
security: 'Security',
deprecate: 'Deprecated',
remove: 'Removed',
};
return {
category: categoryMap[type] || 'Changed',
description,
scope,
breaking: !!breaking,
};
}
解析每条提交信息并分类:
typescript
interface ChangeEntry {
category: 'Added' | 'Changed' | 'Deprecated' | 'Removed' | 'Fixed' | 'Security';
description: string;
commit: string;
scope?: string;
breaking?: boolean;
}
function categorizeCommit(message: string): ChangeEntry | null {
const conventionalRegex = /^(\w+)(?:\(([^)]+)\))?(!)?:\s*(.+)$/;
const match = message.match(conventionalRegex);
if (!match) return null;
const [, type, scope, breaking, description] = match;
const categoryMap: Record<string, ChangeEntry['category']> = {
feat: 'Added',
fix: 'Fixed',
docs: 'Changed',
style: 'Changed',
refactor: 'Changed',
perf: 'Changed',
security: 'Security',
deprecate: 'Deprecated',
remove: 'Removed',
};
return {
category: categoryMap[type] || 'Changed',
description,
scope,
breaking: !!breaking,
};
}
Step 3: Generate Markdown
步骤3:生成Markdown
typescript
function generateChangelog(entries: ChangeEntry[], version: string, date: string): string {
const grouped = groupBy(entries, 'category');
const order = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'];
let output = `## [${version}] - ${date}\n\n`;
for (const category of order) {
if (grouped[category]?.length) {
output += `### ${category}\n`;
for (const entry of grouped[category]) {
const scope = entry.scope ? `**${entry.scope}:** ` : '';
const breaking = entry.breaking ? '⚠️ BREAKING: ' : '';
output += `- ${breaking}${scope}${entry.description}\n`;
}
output += '\n';
}
}
return output;
}
typescript
function generateChangelog(entries: ChangeEntry[], version: string, date: string): string {
const grouped = groupBy(entries, 'category');
const order = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'];
let output = `## [${version}] - ${date}\n\n`;
for (const category of order) {
if (grouped[category]?.length) {
output += `### ${category}\n`;
for (const entry of grouped[category]) {
const scope = entry.scope ? `**${entry.scope}:** ` : '';
const breaking = entry.breaking ? '⚠️ BREAKING: ' : '';
output += `- ${breaking}${scope}${entry.description}\n`;
}
output += '\n';
}
}
return output;
}
Version Determination
版本判定
Based on changes, suggest version bump:
| Change Type | Version Bump | Example |
|---|
| Breaking changes () | MAJOR | 1.0.0 → 2.0.0 |
| New features () | MINOR | 1.0.0 → 1.1.0 |
| Bug fixes () | PATCH | 1.0.0 → 1.0.1 |
| Other changes | PATCH | 1.0.0 → 1.0.1 |
typescript
function suggestVersionBump(entries: ChangeEntry[], currentVersion: string): string {
const [major, minor, patch] = currentVersion.split('.').map(Number);
if (entries.some(e => e.breaking)) {
return `${major + 1}.0.0`;
}
if (entries.some(e => e.category === 'Added')) {
return `${major}.${minor + 1}.0`;
}
return `${major}.${minor}.${patch + 1}`;
}
根据变更内容建议版本号升级规则:
| 变更类型 | 版本升级幅度 | 示例 |
|---|
| 破坏性变更 () | 主版本(MAJOR) | 1.0.0 → 2.0.0 |
| 新功能 () | 次版本(MINOR) | 1.0.0 → 1.1.0 |
| 漏洞修复 () | 补丁版本(PATCH) | 1.0.0 → 1.0.1 |
| 其他变更 | 补丁版本(PATCH) | 1.0.0 → 1.0.1 |
typescript
function suggestVersionBump(entries: ChangeEntry[], currentVersion: string): string {
const [major, minor, patch] = currentVersion.split('.').map(Number);
if (entries.some(e => e.breaking)) {
return `${major + 1}.0.0`;
}
if (entries.some(e => e.category === 'Added')) {
return `${major}.${minor + 1}.0`;
}
return `${major}.${minor}.${patch + 1}`;
}
Workflow Integration
工作流集成
Pre-release Workflow
预发布工作流
1. Generate changelog for unreleased changes
1. Generate changelog for unreleased changes
git log $(git describe --tags --abbrev=0)..HEAD --oneline
git log $(git describe --tags --abbrev=0)..HEAD --oneline
2. Update CHANGELOG.md with new version section
2. Update CHANGELOG.md with new version section
3. Commit changelog
3. Commit changelog
git add CHANGELOG.md
git commit -m "docs: update changelog for v1.2.0"
git add CHANGELOG.md
git commit -m "docs: update changelog for v1.2.0"
4. Create version tag
4. Create version tag
git tag -a v1.2.0 -m "Release v1.2.0"
git tag -a v1.2.0 -m "Release v1.2.0"
5. Push with tags
5. Push with tags
GitHub Release Integration
GitHub发布集成
Generate release notes for GitHub:
Extract latest version section from CHANGELOG.md
Extract latest version section from CHANGELOG.md
sed -n '/^## [1.2.0]/,/^## [/p' CHANGELOG.md | head -n -1
sed -n '/^## [1.2.0]/,/^## [/p' CHANGELOG.md | head -n -1
Create GitHub release
Create GitHub release
gh release create v1.2.0 --title "v1.2.0" --notes-file release-notes.md
gh release create v1.2.0 --title "v1.2.0" --notes-file release-notes.md
Markdown (Default)
Markdown(默认)
Standard Keep a Changelog format as shown above.
上文展示的标准Keep a Changelog格式。
json
{
"version": "1.1.0",
"date": "2024-01-26",
"changes": {
"added": [
"New `zustand-state` skill for state management",
"New `form-validation` skill with Zod + Conform integration"
],
"changed": [
"Updated `shopify-developer` agent with new skills"
],
"fixed": [],
"security": []
}
}
json
{
"version": "1.1.0",
"date": "2024-01-26",
"changes": {
"added": [
"New `zustand-state` skill for state management",
"New `form-validation` skill with Zod + Conform integration"
],
"changed": [
"Updated `shopify-developer` agent with new skills"
],
"fixed": [],
"security": []
}
}
Release Notes (Simplified)
简化版发布说明
Release v1.1.0
Release v1.1.0
- 🎉 3 new skills added for better Shopify development
- 🎉 3 new skills added for better Shopify development
- zustand-state: State management with Zustand
- form-validation: Form validation with Zod + Conform
- security-hardening: Security best practices
- zustand-state: State management with Zustand
- form-validation: Form validation with Zod + Conform
- security-hardening: Security best practices
- Updated agents with new skill integrations
- Updated agents with new skill integrations
- ✅ Write changelogs for humans, not machines
- ✅ Use present tense ("Add feature" not "Added feature")
- ✅ Group changes by type (Added, Changed, Fixed, etc.)
- ✅ Include links to issues/PRs when relevant
- ✅ Highlight breaking changes prominently
- ✅ Keep entries concise but descriptive
- ✅ 面向人类而非机器编写更新日志
- ✅ 使用现在时(如"Add feature"而非"Added feature")
- ✅ 按类型分组变更(新增、变更、修复等)
- ✅ 相关场景下添加issue/PR链接
- ✅ 突出展示破坏性变更
- ✅ 保持条目简洁且描述清晰
- ❌ Include every single commit (filter noise)
- ❌ Use technical jargon without explanation
- ❌ Forget to update [Unreleased] section
- ❌ Mix different versions in one section
- ❌ Skip security-related changes
- ❌ 包含所有提交记录(过滤无效信息)
- ❌ 使用未解释的技术术语
- ❌ 忘记更新[Unreleased]部分
- ❌ 在同一个章节混合不同版本的内容
- ❌ 遗漏安全相关变更
View commits since last tag
View commits since last tag
git log $(git describe --tags --abbrev=0)..HEAD --oneline
git log $(git describe --tags --abbrev=0)..HEAD --oneline
View commits between two tags
View commits between two tags
git log v1.0.0..v1.1.0 --oneline
git log v1.0.0..v1.1.0 --oneline
Get commit count by type
Get commit count by type
git log --oneline | grep -E "^[a-f0-9]+ (feat|fix|docs):" | wc -l
git log --oneline | grep -E "^[a-f0-9]+ (feat|fix|docs):" | wc -l
List all contributors since last release
List all contributors since last release
git log $(git describe --tags --abbrev=0)..HEAD --format="%an" | sort -u
git log $(git describe --tags --abbrev=0)..HEAD --format="%an" | sort -u
Generate commit list with dates
Generate commit list with dates
git log --since="2024-01-01" --pretty=format:"- %s (%ad)" --date=short
git log --since="2024-01-01" --pretty=format:"- %s (%ad)" --date=short
/changelog # Generate for unreleased changes
/changelog 1.2.0 # Generate for specific version
/changelog --since=v1.0.0 # Changes since specific tag
/changelog --format=json # Output as JSON
/changelog # 生成未发布变更的更新日志
/changelog 1.2.0 # 生成指定版本的更新日志
/changelog --since=v1.0.0 # 生成指定标签之后的变更日志
/changelog --format=json # 输出JSON格式的结果