Files
sanguo_moziplus_v2/docs/design/23-toolchain-pr-lifecycle.md
T
cfdaily a4bb752d71
CI / lint (pull_request) Successful in 6s
CI / test (pull_request) Successful in 8s
CI / notify-on-failure (pull_request) Successful in 0s
feat(toolchain): add PR synchronize and review comment notifications
- pull_request.synchronize: notify reviewer to re-review after push
- pull_request_review COMMENTED: notify PR author of review comments
- New templates: review_updated.md, review_comment.md
- Idempotency: add review ID to content dedup key
- Design doc: docs/design/23-toolchain-pr-lifecycle.md
2026-06-11 14:00:44 +08:00

145 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# §23 — 工具链事件中枢补全:PR 全生命周期通知
> 状态:草案,待评审
> 作者:庞统
> 日期:2026-06-11
> 框架:基于 §20 Task Type Architecture + §13 工具链设计
## 背景
### 问题
工具链事件中枢(`toolchain_routes.py`)当前只覆盖了 PR 生命周期中约一半的交互节点。review 驳回后 PR 作者修改代码,没有机制通知 reviewer 重新 review——流程在这里断链。
### 当前覆盖
| 事件节点 | handler | 模板 | 状态 |
|---|---|---|---|
| PR 创建 → 通知 reviewer | `_handle_pull_request` (opened) | `review_request.md` | ✅ |
| Review 通过 → 通知 PR 作者 | `_handle_pull_request_review` (APPROVED) | `review_result.md` | ✅ |
| Review 驳回 → 通知 PR 作者 | `_handle_pull_request_review` (REQUEST_CHANGES) | `review_result.md` | ✅ |
| Issue 指派 → 通知被指派人 | `_handle_issues` (assigned) | `issue_assigned.md` | ✅ |
| CI 失败评论 → 通知 | `_handle_issue_comment` ([CI]) | `ci_failure.md` | ✅ |
| 部署失败 Issue → 通知 | `_handle_issues` (opened+"部署失败") | `deploy_failure.md` | ✅ |
### 缺失节点
| # | 事件节点 | Gitea 事件 | 优先级 | 理由 |
|---|---|---|---|---|
| E1 | PR 更新(push 新 commit)→ 通知 reviewer | `pull_request.synchronize` | **高** | review 驳回→修改→重 review 的关键闭环 |
| ~~E2~~ | ~~PR 合并通知~~ | ~~已删除~~ | ~~—~~ | ~~和 §22 CD 成功通知重叠,已删~~ |
| E3 | Review 评论(COMMENTED)→ 通知 PR 作者 | `pull_request_review` (COMMENTED) | 中 | reviewer 讨论提问,作者应知道 |
| E4 | PR 上普通评论 → 通知相关人 | `issue_comment` (on PR) | 低 | 非关键路径 |
## 方案
### 框架对齐
按 §20 Task Type Architecture,新增事件处理遵循:
1. `_EVENT_HANDLERS` 映射 → 路由到对应 handler 函数
2. handler 提取变量 → `render_template()` 渲染模板
3. `_TEMPLATE_MAP` 注册模板名 → `templates/toolchain/` 下新建模板文件
4. 通知目标通过 Gitea username → `to_agent_id()` 映射
### 新增 Handler 1`_handle_pull_request_synchronize`
**触发**`pull_request` 事件 + `action=synchronize`PR 分支有新 push
**通知对象**PR 的 reviewer(从 PR 的 `requested_reviewers` 或最近一次 non-COMMENTED review 的提交者)
**实现**
修改 `_handle_pull_request` 的 action 过滤,从只处理 `opened` 扩展为同时处理 `synchronize`
```python
async def _handle_pull_request(payload: Dict[str, Any]) -> None:
action = payload.get("action", "")
if action == "opened":
await _handle_pr_opened(payload)
elif action == "synchronize":
await _handle_pr_synchronize(payload)
# 其他 action 忽略
```
新增 `_handle_pr_synchronize`
1. 从 payload 取 PR 信息(number、title、author、head sha
2. 查询最近一次 reviewGitea API `GET /repos/{owner}/{repo}/pulls/{number}/reviews`)取 reviewer
3. 如果没有 review 记录(首次 push 后 reviewer 还没 review),跳过(opened 事件已经通知过了)
4. 渲染 `review_updated.md` 模板,发送 Mail 给 reviewer
**关键设计决策**
- 不用 `requested_reviewers`(可能为空),用最近 review 的提交者
- 只在有 review 历史时才通知(避免 opened + synchronize 重复通知)
- Mail from 用 `system`
### ~~Handler 2PR 合并通知~~ — 已删除
> 司马懿 review 指出与 §22 CD 成功通知重叠。CD 成功通知已隐含合并信息,无需单独发 merged 通知。
### 新增 Handler 3review COMMENTED 处理
**触发**`pull_request_review` 事件 + `state=COMMENTED`
**通知对象**PR 作者(不是 reviewer
**实现**
修改现有 `_handle_pull_request_review`,当前逻辑是"非 COMMENTED 才通知",改为 COMMENTED 也通知,但用不同模板:
```python
# 现有逻辑:非 COMMENTED 通知 PR 作者
if state in ("APPROVED", "REQUEST_CHANGES"):
template_name = "review_result"
elif state == "COMMENTED":
template_name = "review_comment"
else:
return # PENDING 等忽略
```
### 新增模板
| 模板文件 | 变量 | 说明 |
|---|---|---|
| `review_updated.md` | repo, pr_number, pr_title, pr_author, branch, new_sha, reviewer | PR 有新 commit,请重新 review |
| ~~`pr_merged.md`~~ | ~~已删除~~ | ~~—~~ |
| `review_comment.md` | repo, pr_number, pr_title, reviewer, comment_body | reviewer 提交了评论 |
### `_EVENT_HANDLERS` 无需改动
`synchronize``closed` 都是 `pull_request` 事件的 action 子类型,已映射到 `_handle_pull_request`。COMMENTED 是 `pull_request_review` 的 state 子类型,已映射到 `_handle_pull_request_review`
所以 **`_EVENT_HANDLERS` 不需要修改**,只需修改 handler 内部的 action/state 分发逻辑。
### 不做的事
| 项 | 理由 |
|---|---|
| E4 PR 上普通评论通知 | 低优,非关键路径,后续按需加 |
| Issue 关闭通知 | 低优,关怀性质 |
| reviewer 从 `requested_reviewers` 取 | 不可靠(可能为空),用最近 review 记录更稳定 |
## 改动范围
| 文件 | 改动 |
|---|---|
| `src/api/toolchain_routes.py` | 修改 `_handle_pull_request`(扩展 action 分发)+ 新增 `_handle_pr_synchronize` + 修改 `_handle_pull_request_review`(支持 COMMENTED |
| `templates/toolchain/review_updated.md` | 新增 |
| ~~`templates/toolchain/pr_merged.md`~~ | ~~已删除~~ |
| `templates/toolchain/review_comment.md` | 新增 |
| `src/daemon/toolchain_templates.py` | `_TEMPLATE_MAP` 新增 3 个映射 |
| `docs/design/23-toolchain-pr-lifecycle.md` | 本文档 |
## 验证计划
`sanguo/moziplus-v2` 测试仓库上 E2E 验证:
1. **synchronize**:创建 PR → review 驳回 → push 新 commit → 验证 reviewer 收到"请重新 review" Mail
~~2. merged~~:已删除
3. **COMMENTED**:review 提交纯评论 → 验证 PR 作者收到通知
## 风险评估
- **风险等级**:低。新增事件处理,不修改现有 handler 逻辑
- **幂等性**:复用现有 `_is_duplicate` 机制
- **性能**synchronize handler 有一次 Gitea API 调用(查 review 历史),频率低(只在 push 后触发)