forked from Gitlink/gitlink-cli
179 lines
6.3 KiB
Markdown
179 lines
6.3 KiB
Markdown
# 裁决记录 — PASS
|
||
|
||
> 模拟 `gitlink-gatekeeper` 在一个真实风格 PR 上的完整执行记录:采集 → 逐维算分 → 硬门禁 → 裁决 → 渲染评分卡 → dry-run 回写命令。
|
||
> 策略:默认 `gatekeeper.yaml`(权重 40/20/15/15/10,severity_penalty blocker=100/major=25/minor=5/nit=1,thresholds pass=85 / request_changes=60,max_changed_files=80)。
|
||
> 命令均来自 `REFERENCE.md` 第 7 节 CLI 映射,已对照 `gitlink-cli pr/ci/label` 真实 shortcut 核验。
|
||
|
||
**场景**:`Gitlink/forgeplus` 仓库 PR #214,给搜索模块增加分页参数校验,附带单元测试,CI 全绿。
|
||
|
||
---
|
||
|
||
## ① 采集上下文
|
||
|
||
```bash
|
||
# PR 元信息(标题/描述/作者/关联)
|
||
gitlink-cli pr +view -i 214 --owner Gitlink --repo forgeplus --format json
|
||
|
||
# 变更文件列表
|
||
gitlink-cli pr +files -i 214 --owner Gitlink --repo forgeplus --format json
|
||
|
||
# diff(供 AI 审查)
|
||
gitlink-cli pr +diff -i 214 --owner Gitlink --repo forgeplus --format json
|
||
|
||
# commits
|
||
gitlink-cli api GET /Gitlink/forgeplus/pulls/214/commits --format json
|
||
|
||
# CI 状态
|
||
gitlink-cli ci +builds --owner Gitlink --repo forgeplus --format json
|
||
```
|
||
|
||
**采集结果摘要**
|
||
|
||
| 信号 | 值 |
|
||
|------|----|
|
||
| 标题 | `feat(search): validate pagination params` |
|
||
| 描述 | 非空,长度 142 字符(≥30),且含 `Closes #198` |
|
||
| `changed_files` | 5 |
|
||
| `changed_src`(匹配 `source_globs`) | 3(`search.go` / `paginate.go` / `params.go`) |
|
||
| `changed_tests`(匹配 `test_globs`) | 2(`paginate_test.go` / `params_test.go`) |
|
||
| commits | 4 条,全部 `type(scope): subject` 形式 → conforming=4 |
|
||
| CI | passing |
|
||
| AI 审查发现 | 0 blocker / 0 major / 1 minor / 2 nit |
|
||
|
||
---
|
||
|
||
## ② 逐维算分(公式代入,可复算)
|
||
|
||
**review_findings(权重 40)** — `REFERENCE.md` §3.1
|
||
```
|
||
penalty = 1×5(minor) + 2×1(nit) = 7
|
||
score = 40 × max(0, 1 − 7/40) = 40 × (33/40) = 40 × 0.825 = 33
|
||
```
|
||
|
||
**test_coverage(权重 20)** — §3.2
|
||
```
|
||
changed_src=3 > 0, changed_tests=2 > 0
|
||
ratio = min(1, 2/3) = 0.6667
|
||
score = round(20 × (0.5 + 0.5×0.6667)) = round(20 × 0.8333) = round(16.667) = 17
|
||
```
|
||
|
||
**pr_hygiene(权重 15)** — §3.3
|
||
```
|
||
描述≥30 ✓ (+1/3)
|
||
关联 Issue(body 含 #198) ✓ (+1/3)
|
||
体量 changed_files=5 ≤ max_changed_files/2 = 40 ✓ (+1/3)
|
||
命中比例 = 3/3 = 1
|
||
score = round(15 × 1) = 15
|
||
```
|
||
|
||
**commit_quality(权重 15)** — §3.4
|
||
```
|
||
conforming/total = 4/4
|
||
score = round(15 × 4/4) = 15
|
||
```
|
||
|
||
**ci_status(权重 10)** — §3.5
|
||
```
|
||
CI passing → score = 10
|
||
```
|
||
|
||
**总分**
|
||
```
|
||
total = 33 + 17 + 15 + 15 + 10 = 90
|
||
```
|
||
|
||
---
|
||
|
||
## ③ 硬门禁判定(§4)
|
||
|
||
| 门禁 | 配置 | 命中? |
|
||
|------|------|:------:|
|
||
| `forbid_blocker_findings` | true | 否(0 blocker) |
|
||
| `require_ci_pass` | true | 否(passing) |
|
||
| `require_tests_for_src_changes` | true | 否(changed_src=3>0 但 changed_tests=2>0) |
|
||
| `require_linked_issue` | false | —(未启用) |
|
||
| `max_changed_files` | 80 | 否(5 ≤ 80) |
|
||
|
||
`hard_gate_failed = false`。
|
||
|
||
---
|
||
|
||
## ④ 裁决(§5)
|
||
|
||
```
|
||
hard_gate_failed = false
|
||
total = 90 ≥ thresholds.pass(85)
|
||
→ verdict = PASS
|
||
```
|
||
|
||
---
|
||
|
||
## ⑤ 渲染的评分卡
|
||
|
||
```markdown
|
||
## 🛡️ Gatekeeper Report — PR #214 feat(search): validate pagination params
|
||
|
||
**Verdict: ✅ PASS** · Score: 90/100 · policy: gatekeeper.yaml@v1
|
||
|
||
| Dimension | Weight | Score | Notes |
|
||
|-----------|:------:|:-----:|-------|
|
||
| Review findings | 40 | 33/40 | 0 blocker / 0 major / 1 minor / 2 nit |
|
||
| Test coverage | 20 | 17/20 | 3 src / 2 test files |
|
||
| PR hygiene | 15 | 15/15 | desc ✓ / linked issue #198 ✓ / size ✓ |
|
||
| Commit quality | 15 | 15/15 | 4/4 conventional |
|
||
| CI status | 10 | 10/10 | passing |
|
||
|
||
### 🟡 Should fix (1)
|
||
- [minor] `validatePage` 对负数与零分两个分支处理,可合并 — paginate.go:41
|
||
|
||
### 🔵 Nits (2)
|
||
- [nit] 导出函数 `ValidateParams` 缺少 doc 注释 — params.go:18
|
||
- [nit] 测试用例命名建议统一为 `TestXxx_Case` — params_test.go:7
|
||
|
||
### ✅ Strengths
|
||
- 源码改动均有对应测试,覆盖良好
|
||
- commit 全部符合 Conventional Commits,关联了 Issue #198
|
||
- CI 全绿
|
||
|
||
### Next steps
|
||
1. 评分达标且无硬门禁失败,可合并;如需自动合并请在策略中开启 `auto_merge` 并显式带 `--apply`
|
||
2. 两个 nit 可在后续提交一并处理,不阻塞合并
|
||
---
|
||
*Generated by gitlink-gatekeeper · policy-as-code PR gate · re-run after changes*
|
||
```
|
||
|
||
---
|
||
|
||
## ⑥ 将执行的回写命令(dry-run 展示)
|
||
|
||
> 默认 `behavior.dry_run_default: true` → 不传 `--apply` 时只打印以下命令,不真正回写。
|
||
> `behavior.auto_merge: false` → 即便裁决 PASS 也**不会**触发合并。
|
||
|
||
```bash
|
||
# [dry-run] 1) 把评分卡作为评论回写到 PR(与 workflow 脚本一致,走 pr +comment)
|
||
gitlink-cli pr +comment -i 214 -b "$(cat scorecard.md)" --owner Gitlink --repo forgeplus
|
||
# 也可作为评审记录回写:gitlink-cli pr +review -i 214 --status common --content "$(cat scorecard.md)"
|
||
# (GitLink review status 为 common/approved/rejected;gatekeeper 自动裁决统一用建议性的 common,
|
||
# 强语义 approved/rejected 留给人工授意。)
|
||
|
||
# [dry-run] 2) 打 PASS 标签(labels.pass = "gatekeeper:pass")
|
||
# 2a. 确保标签存在(首次需创建;已存在则跳过)
|
||
gitlink-cli label +create -n "gatekeeper:pass" -c "#2EA043" \
|
||
-d "Gatekeeper verdict: PASS" --owner Gitlink --repo forgeplus
|
||
# 2b. 标签挂到 PR 背后的 issue(GitLink PR 复用 issue 标签体系)。
|
||
# 注意:用 PR 关联的 issue.id(非 PR 号),先从 pr +view 取:
|
||
ISSUE_ID=$(gitlink-cli pr +view -i 214 --owner Gitlink --repo forgeplus --format json | jq -r '.data.issue.id')
|
||
gitlink-cli api POST /Gitlink/forgeplus/issues/$ISSUE_ID --body '{
|
||
"issue_tag_ids": [<gatekeeper:pass 的 tag_id>],
|
||
"done_ratio": 0,
|
||
"subject": "<PR 原标题>",
|
||
"description": "<PR 原描述>"
|
||
}'
|
||
# 也可用 gitlink-cli issue +update,它会自动保留 subject/description,免手动回传。
|
||
|
||
# 合并默认禁用(auto_merge=false)。仅当策略 auto_merge=true 且裁决=PASS 且显式 --apply 时才会执行:
|
||
# gitlink-cli pr +merge -i 214 --method squash --owner Gitlink --repo forgeplus
|
||
```
|
||
|
||
> 实际写回需追加 `--apply`,且 Agent 会先向用户复述「将回写 1 条评论 + 打 1 个 gatekeeper:pass 标签,不合并」并等待确认。
|