forked from Gitlink/gitlink-cli
414 lines
11 KiB
Markdown
414 lines
11 KiB
Markdown
# Workflow: Release Notes 生成
|
||
|
||
> **前置条件:** 先阅读 [`../../gitlink-shared/SKILL.md`](../../../gitlink-shared/SKILL.md) 了解认证、全局参数和安全规则。
|
||
> **AI Agent 工作流**:此工作流专为 AI Agent 设计,用于自动生成版本发布说明。
|
||
|
||
AI Agent 从提交历史、Issue 和 PR 数据自动生成结构化的 Release Notes,确保发布文档的完整性和准确性。
|
||
|
||
## 工作流概述
|
||
|
||
Release Notes 生成工作流自动收集版本间的所有变更信息,整理成结构化的发布说明,包含新功能、Bug 修复、破坏性变更等重要信息。
|
||
|
||
## 适用场景
|
||
|
||
- **版本发布**:为每个新版本生成发布说明
|
||
- **变更追踪**:追踪版本间的具体变更
|
||
- **用户沟通**:向用户清晰传达版本更新内容
|
||
- **历史记录**:维护项目变更历史
|
||
|
||
## 工作流步骤
|
||
|
||
### 步骤 1:确定版本范围
|
||
|
||
```bash
|
||
# 获取最新标签
|
||
LATEST_TAG=$(gitlink-cli release +list --format json | \
|
||
jq -r '.data.releases[0].tag_name')
|
||
|
||
# 确定新版本号
|
||
NEW_TAG="v1.2.0"
|
||
|
||
# 或者获取两个标签之间的差异
|
||
BASE_TAG="v1.1.0"
|
||
HEAD_TAG="v1.2.0"
|
||
```
|
||
|
||
### 步骤 2:获取提交历史
|
||
|
||
```bash
|
||
# 获取版本间的提交比较
|
||
gitlink-cli api GET /:owner/:repo/compare/$BASE_TAG...$HEAD_TAG --format json
|
||
|
||
# 提取提交信息
|
||
COMMITS=$(gitlink-cli api GET /:owner/:repo/compare/$BASE_TAG...$HEAD_TAG --format json | \
|
||
jq '.data.commits[] |
|
||
{message: .commit.message,
|
||
author: .commit.author.name,
|
||
date: .commit.author.date,
|
||
sha: .sha}')
|
||
```
|
||
|
||
### 步骤 3:获取已关闭的 Issue
|
||
|
||
```bash
|
||
# 获取已关闭的 Issue
|
||
CLOSED_ISSUES=$(gitlink-cli issue +list --state closed --format json | \
|
||
jq '.data.issues[] |
|
||
select(.closed_at >= "'$START_DATE'") |
|
||
{id: .id,
|
||
subject: .subject,
|
||
labels: [.issue_tags[].name],
|
||
closed_at: .closed_at}')
|
||
```
|
||
|
||
### 步骤 4:获取合并的 PR
|
||
|
||
```bash
|
||
# 获取已合并的 PR
|
||
MERGED_PRS=$(gitlink-cli pr +list --state merged --format json | \
|
||
jq '.data.prs[] |
|
||
select(.merged_at >= "'$START_DATE'") |
|
||
{id: .id,
|
||
title: .title,
|
||
number: .number,
|
||
author: .author.login,
|
||
merged_at: .merged_at}')
|
||
```
|
||
|
||
### 步骤 5:分类和整理变更
|
||
|
||
```bash
|
||
# 按变更类型分类
|
||
FEATURES=()
|
||
BUG_FIXES=()
|
||
ENHANCEMENTS=()
|
||
BREAKING_CHANGES=()
|
||
|
||
# 分析 Issue 标签分类
|
||
while read -r issue; do
|
||
SUBJECT=$(echo "$issue" | jq -r '.subject')
|
||
LABELS=$(echo "$issue" | jq -r '.labels[]')
|
||
|
||
if echo "$LABELS" | grep -q "feature"; then
|
||
FEATURES+=("$SUBJECT")
|
||
elif echo "$LABELS" | grep -q "bug"; then
|
||
BUG_FIXES+=("$SUBJECT")
|
||
elif echo "$LABELS" | grep -q "enhancement"; then
|
||
ENHANCEMENTS+=("$SUBJECT")
|
||
fi
|
||
done <<< "$CLOSED_ISSUES"
|
||
|
||
# 分析提交信息
|
||
while read -r commit; do
|
||
MESSAGE=$(echo "$commit" | jq -r '.message')
|
||
|
||
if echo "$MESSAGE" | grep -iq "BREAKING"; then
|
||
BREAKING_CHANGES+=("$MESSAGE")
|
||
fi
|
||
done <<< "$COMMITS"
|
||
```
|
||
|
||
### 步骤 6:生成 Release Notes
|
||
|
||
```bash
|
||
# 生成结构化的 Release Notes
|
||
RELEASE_NOTES="# 🚀 Release Notes for $NEW_TAG
|
||
|
||
## 📝 What's Changed
|
||
|
||
### ✨ New Features
|
||
$(for feature in "${FEATURES[@]}"; do
|
||
echo "- $feature"
|
||
done)
|
||
|
||
### 🐛 Bug Fixes
|
||
$(for fix in "${BUG_FIXES[@]}"; do
|
||
echo "- $fix"
|
||
done)
|
||
|
||
### 🔧 Enhancements
|
||
$(for enhancement in "${ENHANCEMENTS[@]}"; do
|
||
echo "- $enhancement"
|
||
done)
|
||
|
||
### ⚠️ Breaking Changes
|
||
$(for breaking in "${BREAKING_CHANGES[@]}"; do
|
||
echo "- $breaking"
|
||
done)"
|
||
|
||
# 创建 Release
|
||
gitlink-cli release +create --tag $NEW_TAG --name "$NEW_TAG" --body "$RELEASE_NOTES"
|
||
```
|
||
|
||
## AI Agent 集成示例
|
||
|
||
Claude Code 等 AI Agent 可以深度集成此工作流:
|
||
|
||
```python
|
||
# AI Agent 生成 Release Notes
|
||
def generate_release_notes(owner, repo, new_version):
|
||
"""AI Agent 自动生成发布说明"""
|
||
|
||
# 1. 获取版本信息
|
||
prev_version = get_latest_release(owner, repo)
|
||
commits = compare_revisions(owner, repo, prev_version, new_version)
|
||
issues = get_closed_issues(owner, repo, since=prev_version)
|
||
prs = get_merged_prs(owner, repo, since=prev_version)
|
||
|
||
# 2. AI 分析变更
|
||
changes = analyze_changes(commits, issues, prs)
|
||
|
||
# 3. 生成发布说明
|
||
release_notes = format_release_notes(new_version, changes, prev_version)
|
||
|
||
# 4. 创建 Release
|
||
create_release(owner, repo, new_version, release_notes)
|
||
|
||
return release_notes
|
||
|
||
def analyze_changes(commits, issues, prs):
|
||
"""AI 智能分析变更内容"""
|
||
|
||
changes = {
|
||
'features': [],
|
||
'bug_fixes': [],
|
||
'enhancements': [],
|
||
'breaking_changes': [],
|
||
'contributors': set(),
|
||
'performance_improvements': [],
|
||
'security_fixes': []
|
||
}
|
||
|
||
# 分析 Issue
|
||
for issue in issues:
|
||
labels = [label['name'] for label in issue.get('issue_tags', [])]
|
||
subject = issue['subject']
|
||
|
||
if 'feature' in labels:
|
||
changes['features'].append(format_issue_reference(issue))
|
||
elif 'bug' in labels:
|
||
changes['bug_fixes'].append(format_issue_reference(issue))
|
||
elif 'enhancement' in labels:
|
||
changes['enhancements'].append(format_issue_reference(issue))
|
||
elif 'security' in labels:
|
||
changes['security_fixes'].append(format_issue_reference(issue))
|
||
|
||
# 分析提交信息
|
||
for commit in commits:
|
||
message = commit['commit']['message']
|
||
|
||
# 使用 AI 分析提交消息
|
||
analysis = analyze_commit_message(message)
|
||
|
||
if analysis.get('breaking_change'):
|
||
changes['breaking_changes'].append(message)
|
||
elif analysis.get('performance'):
|
||
changes['performance_improvements'].append(message)
|
||
|
||
# 收集贡献者
|
||
changes['contributors'].add(commit['author']['name'])
|
||
|
||
return changes
|
||
|
||
def format_release_notes(version, changes, prev_version):
|
||
"""AI 生成结构化发布说明"""
|
||
|
||
notes = f"""# 🎉 Release {version}
|
||
|
||
## 📊 变更统计
|
||
- **新功能**: {len(changes['features'])} 个
|
||
- **Bug 修复**: {len(changes['bug_fixes'])} 个
|
||
- **功能改进**: {len(changes['enhancements'])} 个
|
||
- **破坏性变更**: {len(changes['breaking_changes'])} 个
|
||
"""
|
||
|
||
if changes['features']:
|
||
notes += "\n## ✨ 新功能\n"
|
||
notes += "\n".join(f"- {feature}" for feature in changes['features'])
|
||
notes += "\n"
|
||
|
||
if changes['bug_fixes']:
|
||
notes += "\n## 🐛 Bug 修复\n"
|
||
notes += "\n".join(f"- {fix}" for fix in changes['bug_fixes'])
|
||
notes += "\n"
|
||
|
||
if changes['breaking_changes']:
|
||
notes += "\n## ⚠️ 破坏性变更\n"
|
||
notes += "\n".join(f"- {change}" for change in changes['breaking_changes'])
|
||
notes += "\n"
|
||
|
||
if changes['contributors']:
|
||
notes += f"\n## 🙏 贡献者\n"
|
||
notes += ", ".join(sorted(changes['contributors']))
|
||
notes += "\n"
|
||
|
||
notes += f"\n---\n**完整变更日志**: https://www.gitlink.org.cn/{owner}/{repo}/compare/{prev_version}...{version}"
|
||
|
||
return notes
|
||
|
||
def analyze_commit_message(message):
|
||
"""AI 分析提交消息"""
|
||
return {
|
||
'breaking_change': bool(re.search(r'BREAKING|breaking|!', message)),
|
||
'performance': bool(re.search(r'performance|优化|提升', message, re.I)),
|
||
'security': bool(re.search(r'security|安全|漏洞', message, re.I))
|
||
}
|
||
```
|
||
|
||
## Release Notes 模板
|
||
|
||
### 标准模板
|
||
|
||
```markdown
|
||
# 🎉 Release {VERSION}
|
||
|
||
## 📊 变更统计
|
||
- **新功能**: {FEATURE_COUNT} 个
|
||
- **Bug 修复**: {BUG_FIX_COUNT} 个
|
||
- **功能改进**: {ENHANCEMENT_COUNT} 个
|
||
- **破坏性变更**: {BREAKING_COUNT} 个
|
||
|
||
## ✨ 新功能
|
||
{FEATURES_LIST}
|
||
|
||
## 🐛 Bug 修复
|
||
{BUG_FIXES_LIST}
|
||
|
||
## 🔧 功能改进
|
||
{ENHANCEMENTS_LIST}
|
||
|
||
## ⚠️ 破坏性变更
|
||
{BREAKING_CHANGES_LIST}
|
||
|
||
## 🙏 贡献者
|
||
{CONTRIBUTORS_LIST}
|
||
|
||
## 📥 安装
|
||
```bash
|
||
# 使用 npm
|
||
npm install {PACKAGE}@{VERSION}
|
||
|
||
# 使用 yarn
|
||
yarn add {PACKAGE}@{VERSION}
|
||
|
||
# 使用 pnpm
|
||
pnpm add {PACKAGE}@{VERSION}
|
||
```
|
||
|
||
## 🔄 升级指南
|
||
{UPGRADE_GUIDE}
|
||
|
||
## 📚 文档
|
||
完整文档请查看: https://www.gitlink.org.cn/{OWNER}/{REPO}/wiki
|
||
|
||
---
|
||
**完整变更日志**: https://www.gitlink.org.cn/{OWNER}/{REPO}/compare/{PREV_VERSION}...{VERSION}
|
||
```
|
||
|
||
### 简化模板
|
||
|
||
```markdown
|
||
# {VERSION}
|
||
|
||
## 新增
|
||
{FEATURES}
|
||
|
||
## 修复
|
||
{BUG_FIXES}
|
||
|
||
## 改进
|
||
{ENHANCEMENTS}
|
||
|
||
## 贡献者
|
||
{CONTRIBUTORS}
|
||
|
||
## 链接
|
||
- [完整变更](https://www.gitlink.org.cn/{OWNER}/{REPO}/compare/{PREV_VERSION}...{VERSION})
|
||
- [问题追踪](https://www.gitlink.org.cn/{OWNER}/{REPO}/issues)
|
||
```
|
||
|
||
## 自动化分类规则
|
||
|
||
基于提交信息和 Issue 标签的自动分类:
|
||
|
||
```python
|
||
RELEASE_CATEGORIES = {
|
||
'features': {
|
||
'labels': ['feature', 'enhancement'],
|
||
'commit_keywords': ['feat:', 'add', 'new'],
|
||
'icon': '✨',
|
||
'title': '新功能'
|
||
},
|
||
'bug_fixes': {
|
||
'labels': ['bug', 'fix'],
|
||
'commit_keywords': ['fix:', 'bugfix'],
|
||
'icon': '🐛',
|
||
'title': 'Bug 修复'
|
||
},
|
||
'enhancements': {
|
||
'labels': ['improvement', 'optimize'],
|
||
'commit_keywords': ['improve:', 'optimize:', 'refactor:'],
|
||
'icon': '🔧',
|
||
'title': '功能改进'
|
||
},
|
||
'breaking_changes': {
|
||
'labels': ['breaking', 'major'],
|
||
'commit_keywords': ['BREAKING', 'breaking:', '!'],
|
||
'icon': '⚠️',
|
||
'title': '破坏性变更'
|
||
},
|
||
'security': {
|
||
'labels': ['security', 'vulnerability'],
|
||
'commit_keywords': ['security:', 'fix security'],
|
||
'icon': '🔒',
|
||
'title': '安全修复'
|
||
}
|
||
}
|
||
```
|
||
|
||
## 版本号规范
|
||
|
||
遵循语义化版本 (Semantic Versioning):
|
||
|
||
```
|
||
MAJOR.MINOR.PATCH
|
||
|
||
MAJOR: 不兼容的 API 变更
|
||
MINOR: 向后兼容的功能新增
|
||
PATCH: 向后兼容的 Bug 修复
|
||
```
|
||
|
||
版本号示例:
|
||
- `1.0.0` → `1.1.0`:新增功能
|
||
- `1.1.0` → `1.1.1`:Bug 修复
|
||
- `1.1.1` → `2.0.0`:破坏性变更
|
||
|
||
## 质量检查
|
||
|
||
发布前检查清单:
|
||
|
||
- [ ] Release Notes 完整性检查
|
||
- [ ] 变更统计准确性验证
|
||
- [ ] 破坏性变更标识
|
||
- [ ] 升级指南完整性
|
||
- [ ] 文档链接正确性
|
||
- [ ] 安装指令有效性
|
||
- [ ] 贡献者列表完整性
|
||
|
||
## 最佳实践
|
||
|
||
1. **定期发布**:建立定期发布节奏
|
||
2. **变更追踪**:确保所有变更都被记录
|
||
3. **清晰分类**:使用明确的分类和标签
|
||
4. **用户友好**:提供升级指南和迁移说明
|
||
5. **版本规范**:遵循语义化版本规范
|
||
|
||
## References
|
||
|
||
- [workflow-issue-triage](workflow-issue-triage.md) — Issue 分类工作流
|
||
- [workflow-pr-review](workflow-pr-review.md) — PR 审查工作流
|
||
- [gitlink-workflow](../SKILL.md) — 工作流总览
|
||
- [gitlink-shared](../../gitlink-shared/SKILL.md) — 认证和全局参数
|
||
- [release +create](../../gitlink-release/references/gitlink-release-create.md) — 创建 Release
|
||
- [release +list](../../gitlink-release/references/gitlink-release-list.md) — 列出 Release
|