forked from Gitlink/gitlink-cli
Compare commits
1 Commits
master
...
feat/workf
| Author | SHA1 | Date |
|---|---|---|
|
|
3ad282d395 |
|
|
@ -0,0 +1,113 @@
|
|||
# Release Pipeline — Architecture
|
||||
|
||||
> 自动化发布管理 Pipeline 架构说明
|
||||
> 第八届 CCF 开源创新大赛 · Track 1: GitLink CLI · 子赛题三
|
||||
|
||||
---
|
||||
|
||||
## 1. 总体架构
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph Layer1["Layer 1: 数据采集(只读)"]
|
||||
A1["release +list"] --> |当前版本号 上次发布时间| A2
|
||||
A3["pr +list --state merged"] --> |合并 PR 列表| A2
|
||||
A4["ci +builds"] --> |CI 状态| A2
|
||||
A5["compare +view"] --> |Commit 列表 Diff 统计| A2
|
||||
A6["issue +list"] --> |已关闭 Issue 列表| A2
|
||||
end
|
||||
|
||||
subgraph Layer2["Layer 2: AI 分析"]
|
||||
direction TB
|
||||
A2["数据聚合与清洗"]
|
||||
A2 --> B1["PR/Commit 穿透去重"]
|
||||
B1 --> B2["Issue status_id 二次过滤"]
|
||||
B2 --> B3["语义化版本推断 (Major/Minor/Patch)"]
|
||||
B3 --> B4["Changelog 分类生成"]
|
||||
B4 --> B5["就绪度检查 (PR/CI/Issue)"]
|
||||
B5 --> B6["通知列表生成"]
|
||||
end
|
||||
|
||||
subgraph Layer3["Layer 3: 执行(写入)"]
|
||||
C1["release +create"] --> C2{"用户确认?"}
|
||||
C2 --> |是| C3["创建 Release"]
|
||||
C2 --> |否| C4["终止"]
|
||||
C6["issue +comment"] --> C7{"选择模式"}
|
||||
C7 --> |A 全量自动| C8["逐个通知 遇错跳过"]
|
||||
C7 --> |M 逐个确认| C9["每次询问 y/N"]
|
||||
C7 --> |S 跳过| C10["跳过通知"]
|
||||
end
|
||||
|
||||
B5 --> C1
|
||||
B6 --> C6
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 步骤流(含决策节点)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Start([开始]) --> S1["Step 1: release +list<br/>获取当前版本"]
|
||||
S1 --> S2{"有 Release?"}
|
||||
S2 --> |否| S2a["设 baseline v0.0.0"]
|
||||
S2a --> S3
|
||||
S2 --> |是| S3["Step 2: pr +list --state merged<br/>获取合并 PR"]
|
||||
S3 --> S4{"有新 PR?"}
|
||||
S4 --> |否| Stop1([终止: 无需发布])
|
||||
S4 --> |是| S5["Step 3: ci +builds<br/>检查 CI 状态"]
|
||||
S5 --> S6{"CI 通过?"}
|
||||
S6 --> |失败| S6a["⚠️ 警告用户"]
|
||||
S6a --> S6b{"继续?"}
|
||||
S6b --> |否| Stop2([终止])
|
||||
S6b --> |是| S7
|
||||
S6 --> |通过/未知| S7["Step 4: compare +view<br/>获取变更提交"]
|
||||
S7 --> S8["Step 5: issue +list<br/>获取已解决 Issue"]
|
||||
S8 --> S9["Step 6: AI 分析<br/>去重 → 分类 → 版本推断 → Changelog"]
|
||||
S9 --> S10["Step 7a: release +create<br/>创建 Release(--dry-run)"]
|
||||
S10 --> S11{"用户确认?"}
|
||||
S11 --> |否| Stop3([终止])
|
||||
S11 --> |是| S12["实际创建 Release"]
|
||||
S12 --> S13["Step 7b: issue +comment<br/>通知模式选择"]
|
||||
S13 --> S14[执行通知]
|
||||
S14 --> End([完成])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据流
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Input["输入"]
|
||||
I1["release +list"] --> |tag_name: v1.2.3| P
|
||||
I2["pr +list --state merged"] --> |PR 列表| P
|
||||
I3["ci +builds"] --> |CI 状态| P
|
||||
I4["compare +view --head master --base v1.2.3"] --> |Commit 列表| P
|
||||
I5["issue +list --state all"] --> |Issue 列表| P
|
||||
end
|
||||
|
||||
subgraph Process["处理"]
|
||||
P["数据聚合"]
|
||||
P --> D1["PR/Commit 核销去重"]
|
||||
P --> D2["Issue status_id 过滤<br/>(3=已解决 / 5=关闭)"]
|
||||
D1 --> C["Changelog 生成"]
|
||||
D2 --> C
|
||||
end
|
||||
|
||||
subgraph Output["输出"]
|
||||
C --> O1["release +create --tag v1.3.0 --body ..."]
|
||||
C --> O2["issue +comment --number N<br/>(逐个通知)"]
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 文件结构
|
||||
|
||||
```
|
||||
doc/workflows/
|
||||
├── release-pipeline-architecture.md # 本文件:架构图
|
||||
├── release-pipeline-workflow.md # 工作流说明文档
|
||||
└── release-pipeline-transcript.md # Agent 对话记录
|
||||
```
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
# 自动化发布管理 Pipeline
|
||||
|
||||
## 场景描述
|
||||
|
||||
开源项目维护者在发版时通常需要手动完成:检查哪些 PR 已合并待发布、检查 CI 是否绿色、翻阅提交历史写 Release Notes、创建 Release、通知相关 Issue。本工作流将上述步骤串联为一条完整的自动化链,AI Agent 按步骤执行,维护者只需确认关键决策点。
|
||||
|
||||
## 工作流架构
|
||||
|
||||

|
||||
|
||||
三层架构:
|
||||
- **Layer 1: 数据采集** — 只读命令获取所有上下文
|
||||
- **Layer 2: AI 分析** — 数据清洗、去重、分类、版本推断
|
||||
- **Layer 3: 执行写入** — 创建 Release + 通知 Issue(默认 dry-run)
|
||||
|
||||
---
|
||||
|
||||
## 前置条件
|
||||
|
||||
- `gitlink-cli` 已安装并认证(`gitlink-cli auth status`)
|
||||
- 具备目标仓库的 `write` / `maintain` 权限(执行写操作时需要)
|
||||
- GitLink Token 有效期 **7 天**,过期需 `gitlink-cli auth login` 重新登录
|
||||
|
||||
---
|
||||
|
||||
## 执行步骤
|
||||
|
||||
### Step 1:获取当前发布信息
|
||||
|
||||
确定当前最新版本号和 version_id。
|
||||
|
||||
```bash
|
||||
gitlink-cli release +list --owner <owner> --repo <repo> --limit 1 --format json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"data": {
|
||||
"releases": [
|
||||
{
|
||||
"version_id": 42,
|
||||
"tag_name": "v1.2.3",
|
||||
"created_at": "2026-05-01T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**提取字段**:`tag_name`(当前版本号)、`version_id`(Release ID)、`created_at`(上次发布时间)。
|
||||
|
||||
**无 Release 时**:假设 baseline 为 `v0.0.0`,首个 Release 推荐 `v0.1.0`。
|
||||
|
||||
---
|
||||
|
||||
### Step 2:检查已合并 PR
|
||||
|
||||
获取自上次发布以来合并的 PR。
|
||||
|
||||
```bash
|
||||
gitlink-cli pr +list --owner <owner> --repo <repo> --state merged \
|
||||
--sort-by updated_at --sort-direction desc --limit 50 --format json
|
||||
```
|
||||
|
||||
AI Agent 从返回中过滤 `updated_at` > 上次发布 `created_at` 的 PR。
|
||||
|
||||
> **排序字段注意**:`pr +list` 的排序字段为 `updated_at`,与 `issue +list` 的 `updated_on` 不同,Agent 需按命令组使用正确字段名。
|
||||
|
||||
**决策点**:若无新合并 PR(`len(prs) == 0`),终止并提示"自上次发布以来无变更"。
|
||||
|
||||
---
|
||||
|
||||
### Step 3:检查 CI 状态
|
||||
|
||||
验证 master 分支的 CI 是否通过。
|
||||
|
||||
```bash
|
||||
gitlink-cli ci +builds --owner <owner> --repo <repo> --format json
|
||||
```
|
||||
|
||||
| CI 状态 | 行为 |
|
||||
|---------|------|
|
||||
| `success` | ✅ 继续 |
|
||||
| `failed` | ⚠️ 警告用户,询问是否继续 |
|
||||
| `running` | ⏳ 等待或询问是否跳过 |
|
||||
| 无 CI/401 | ℹ️ 跳过(CI 未配置) |
|
||||
|
||||
---
|
||||
|
||||
### Step 4:获取变更提交
|
||||
|
||||
通过 `compare +view` 获取 commit 列表和 diff 统计。
|
||||
|
||||
```bash
|
||||
gitlink-cli compare +view --owner <owner> --repo <repo> \
|
||||
--head master --base v1.2.3 --format json
|
||||
```
|
||||
|
||||
> **GitLink 主分支是 `master`**(非 GitHub 的 `main`),所有分支参数均使用 `master`。
|
||||
|
||||
> ⚠️ **BREAKING CHANGE 检查要点**:Conventional Commits 中 `BREAKING CHANGE` 通常写在 commit 正文的 **Footer(最后几行)**,而非标题。Agent 必须检查 `commit.body` 或 PR 描述中的完整文本。
|
||||
|
||||
```json
|
||||
{
|
||||
"commits": [
|
||||
{
|
||||
"sha": "abc123",
|
||||
"message": "feat: add user avatar upload (#234)",
|
||||
"body": "Implement avatar upload feature\n\nBREAKING CHANGE: avatar API response format changed",
|
||||
"author": { "login": "zhangsan" }
|
||||
}
|
||||
],
|
||||
"total_commits": 18,
|
||||
"files_changed": 24
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 5:获取已解决 Issue
|
||||
|
||||
> ⚠️ **GitLink 状态过滤防御机制**:
|
||||
>
|
||||
> GitLink API 的 `--state closed` 过滤**不精确**,且 Issue 状态分为 `1=新增, 2=正在解决, 3=已解决, 5=关闭`。被修复的 Issue 可能停留在"已解决(3)"而未演进到"关闭(5)"。
|
||||
>
|
||||
> **解决方案**:不相信 API 的 state 过滤结果。改用 `--state all` 拉取全量列表,AI Agent 在本地根据 `status_id == 3 || status_id == 5` 做二次精确筛选。
|
||||
|
||||
```bash
|
||||
gitlink-cli issue +list --owner <owner> --repo <repo> \
|
||||
--state all --sort-by issues.updated_on --sort-direction desc \
|
||||
--limit 50 --format json
|
||||
```
|
||||
|
||||
> **排序字段注意**:`issue +list` 命令组的排序字段为 `issues.updated_on`,与 `pr +list` 的 `updated_at` 不同,Agent 务必使用正确的字段名。
|
||||
|
||||
AI 过滤逻辑:
|
||||
1. 拉取全部近期有更新的 Issue(`--state all`)
|
||||
2. 本地按 `status_id == 3`(已解决)或 `status_id == 5`(关闭)筛选
|
||||
3. 再过滤 `updated_on` > 上次发布 `created_at` 的条目
|
||||
|
||||
---
|
||||
|
||||
### Step 6:生成 Changelog(AI 分析)
|
||||
|
||||
聚合 Step 1-5 的数据,生成结构化的 Release Notes。
|
||||
|
||||
#### ⚠️ PR 与 Commit 穿透去重
|
||||
|
||||
Step 2 的合并 PR 列表与 Step 4 的 commit 列表存在天然重叠(PR 的提交历史包含在 commit 中)。**必须做关联核销,否则 Changelog 条目会翻倍。**
|
||||
|
||||
```
|
||||
Agent 去重逻辑:
|
||||
1. 优先以 PR 标题作为 Changelog 条目来源(经过 Code Review,质量最高)
|
||||
2. 扫描 commit 列表,做以下核销:
|
||||
- "Merge pull request #234" → 丢弃,由 PR 条目覆盖
|
||||
- "feat: add avatar (#234)" → 关联到 PR #234,以 PR 描述为准
|
||||
- "fix: critical hotfix"(无 PR 编号的孤立 commit)→ 保留为独立条目
|
||||
3. 最终 Changelog 来源:
|
||||
├── 已关联 PR 的 commit → 去重,用 PR 标题
|
||||
├── 孤立 commit → 保留为独立条目
|
||||
└── 已关闭 Issue → 补充到对应分类
|
||||
```
|
||||
|
||||
#### 语义化版本推断
|
||||
|
||||
```
|
||||
1. 扫描 BREAKING CHANGE(两处):
|
||||
a. commit.body 的 Footer 部分
|
||||
b. PR 描述的 Body
|
||||
→ 任一处有 → MAJOR 升级 (v1.2.3 → v2.0.0)
|
||||
|
||||
2. 有 feat: 前缀(无 breaking)→ MINOR 升级 (v1.3.0)
|
||||
|
||||
3. 仅有 fix:/perf:/docs: 等 → PATCH 升级 (v1.2.4)
|
||||
```
|
||||
|
||||
#### 分类规则
|
||||
|
||||
| 类型 | Changelog 分类 | 版本影响 |
|
||||
|:---|:--------------|:--------:|
|
||||
| `BREAKING CHANGE` | ⚠️ 不兼容变更 | MAJOR |
|
||||
| `feat:` | ✨ 新功能 | MINOR |
|
||||
| `fix:` | 🐛 Bug 修复 | PATCH |
|
||||
| `perf:` | ⚡ 性能优化 | PATCH |
|
||||
| `refactor:` | ♻️ 代码重构 | PATCH |
|
||||
| `docs:` | 📝 文档 | PATCH |
|
||||
| `test:` | ✅ 测试 | PATCH |
|
||||
| `ci:` / `build:` | 🔧 CI/CD | PATCH |
|
||||
|
||||
#### Release Notes 模板
|
||||
|
||||
```markdown
|
||||
## v1.3.0 (2026-06-12)
|
||||
|
||||
### ✨ 新功能
|
||||
- feat(user): 新增用户头像上传功能 (#234)
|
||||
- feat(search): 支持全文搜索 (#256)
|
||||
|
||||
### 🐛 Bug 修复
|
||||
- fix(login): 修复登录超时问题 (#245)
|
||||
|
||||
### 📊 统计
|
||||
- 18 commits | 24 files changed | +1200 -300
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 7a:创建 Release(写入,默认 dry-run)
|
||||
|
||||
> ⚠️ **安全措施**:所有写操作**默认 `--dry-run` 预览**,用户确认后才实际执行。
|
||||
|
||||
```bash
|
||||
# 第一步:dry-run 预览
|
||||
gitlink-cli release +create \
|
||||
--owner <owner> --repo <repo> \
|
||||
--tag v1.3.0 \
|
||||
--name "v1.3.0" \
|
||||
--body "## v1.3.0\n\n### ✨ 新功能\n..." \
|
||||
--target master \
|
||||
--dry-run
|
||||
|
||||
# 第二步:用户确认后,移除 --dry-run 实际创建
|
||||
gitlink-cli release +create \
|
||||
--owner <owner> --repo <repo> \
|
||||
--tag v1.3.0 \
|
||||
--name "v1.3.0" \
|
||||
--body "## v1.3.0\n\n### ✨ 新功能\n..." \
|
||||
--target master
|
||||
```
|
||||
|
||||
> **验证**:创建后用 `release +list` 确认,再用 `release +view --id <version_id>` 查看详情。
|
||||
> ⚠️ `release +view` 必须使用 `version_id`(整数),不能用 tag 名称。
|
||||
|
||||
---
|
||||
|
||||
### Step 7b:通知相关 Issue(写入)
|
||||
|
||||
> ⚠️ **防频控与防单点失败机制**:
|
||||
>
|
||||
> 批量通知可能因 Issue 数量多而触发 Rate Limit,或单条评论失败导致整体中断。
|
||||
> Agent 先展示待通知清单,让用户选择通知模式:
|
||||
|
||||
```
|
||||
请选择通知模式:
|
||||
[A] 全量自动通知 — 逐个执行,遇错跳过
|
||||
[M] 逐个确认 — 每次评论前询问 y/N
|
||||
[S] 跳过通知 — 不执行任何 Issue 评论
|
||||
```
|
||||
|
||||
```bash
|
||||
# 单条通知命令
|
||||
gitlink-cli issue +comment --owner <owner> --repo <repo> \
|
||||
--number <issue_number> \
|
||||
--body "🎉 此问题已在 v1.3.0 中修复,请更新验证。"
|
||||
```
|
||||
|
||||
**容错策略**:若某条评论失败,记录错误日志并继续执行下一条,**不阻塞整体 Pipeline**。Rate Limit 触发时等待 60 秒重试 1 次。
|
||||
|
||||
---
|
||||
|
||||
## 预期输出
|
||||
|
||||
工作流执行完毕后生成一份 Markdown 报告:
|
||||
|
||||
```markdown
|
||||
# 发布报告:v1.2.3 → v1.3.0
|
||||
|
||||
## 版本信息
|
||||
- 当前版本:v1.2.3 → 目标版本:v1.3.0
|
||||
- 升级类型:MINOR(新增功能)
|
||||
|
||||
## 就绪度检查
|
||||
- ✅ 已合并 PR:18 个
|
||||
- ✅ CI 状态:通过
|
||||
- ✅ 已关闭 Issue:6 个
|
||||
|
||||
## Release Notes
|
||||
(完整 Changelog)
|
||||
|
||||
## 执行结果
|
||||
- ✅ Release v1.3.0 创建成功
|
||||
- ✅ 6 个 Issue 已通知
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
### GitLink 特有防御汇总
|
||||
|
||||
| 防御点 | 说明 |
|
||||
|--------|------|
|
||||
| **Issue 状态二次过滤** | 不信任 `--state closed`,用 `status_id == 3 \|\| 5` 本地筛 |
|
||||
| **BREAKING CHANGE 查 Body** | 不仅查 commit title,还要查 commit.body 的 Footer |
|
||||
| **主分支为 master** | 所有 `--target` / `--base` 参数使用 `master` |
|
||||
| **排序字段名差异** | `pr +list` 用 `updated_at`,`issue +list` 用 `issues.updated_on` |
|
||||
| **release +view 用 version_id** | 不能传 tag_name,否则返回 HTML 页面 |
|
||||
| **默认 dry-run** | 所有写操作首次执行均为预览模式 |
|
||||
|
||||
### 已知限制
|
||||
|
||||
- `ci +builds` 可能因 CI 未激活返回 401,此时跳过检查
|
||||
- `compare +view` 的 commit.body 字段可能因 API 版本不同而缺失
|
||||
- 初次发布(无历史 Release)需走初始化路径,无法做比较
|
||||
|
||||
## 扩展思路
|
||||
|
||||
- **集成 gitlink-changelog Skill**:将 Changelog 生成逻辑抽取为独立 Skill,可在其他工作流中复用
|
||||
- **预发布流程**:支持 `--prerelease` 创建 beta/rc 版本
|
||||
- **Hotfix 流程**:支持从特定 tag 创建 hotfix 分支并快速发布 PATCH 版本
|
||||
- **跨仓库发布**:支持同时发布关联的多个仓库(如前端 + 后端 + 文档)
|
||||
Loading…
Reference in New Issue