关于 review-gitlab
review-gitlab 是用于 GitLab Merge Request 的代码审查技能,面向希望先审阅分析、再决定是否发布评论的开发者。它采用只读分析与用户批准后写入的两阶段流程,并为发现的问题附上 Claude Code 修复提示。
主要功能
- 01按规模分块审查变更
- 02检查缺陷、安全、性能与类型
- 03读取现有评论以避免重复
- 04为发现项生成修复提示
- 05批准后发布 GitLab 评论
适用场景
- 01深入审查大型 Merge Request
- 02在发布前检查并确认审查发现
- 03跟踪已报告问题及其修复状态
- 04为 Claude Code 准备修复指引
MCP 相关
此技能不使用 GitLab MCP 服务,而是通过内置 CLI 与 GitLab 交互。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thisfrontenddev/ skills --skill review-gitlab安装后在 Claude Code 中输入/review-gitlab确认已加载。
附带文件scripts/gitlab.mjs
详细介绍
你正在对 GitLab 合并请求执行深入代码审查。请严格遵循两阶段工作流:先在本地分析并展示审查结果,然后只将用户批准的评论发布到 GitLab。
大型 MR 会分多个区块进行审查,以确保深入。每条审查结果都包含一段供 Claude Code 使用的修复提示词。
GitLab 访问 — 内嵌 CLI
所有 GitLab 交互都通过随此技能一同提供、位于技能自身目录中的 CLI scripts/gitlab.mjs 进行。通过 Bash 调用:node <skill-dir>/scripts/gitlab.mjs <command> [flags],其中 <skill-dir> 是此技能的安装位置:
- 项目级安装(从仓库根目录运行):
node .claude/skills/review-gitlab/scripts/gitlab.mjs … - 用户级安装:
node ~/.claude/skills/review-gitlab/scripts/gitlab.mjs …
下文中的 gitlab.mjs <command> 是完整调用 node <skill-dir>/scripts/gitlab.mjs <command> 的简写。CLI 会从环境中读取 MR_MCP_GITLAB_TOKEN(以及可选的 MR_MCP_GITLAB_HOST,默认值为 https://gitlab.com)。每条命令都会将 JSON 输出到 stdout;发生错误时,会将 {"error": "..."} 输出到 stderr,并以非零状态码退出。
不存在 GitLab MCP 服务。 不要调用任何 mcp__gitlab-mr__* 或 mcp__gitlab-mr-edit__* 工具;请改用下方的 CLI 命令。
| 旧版 MCP 工具 | CLI 命令 | 必需标志 |
|---|---|---|
get_projects | get_projects | —(可选 --verbose) |
list_open_merge_requests | list_open_mrs | --project-id N |
get_merge_request_details | get_mr | --project-id N --mr IID |
get_merge_request_diff | get_mr_diff | --project-id N --mr IID |
get_merge_request_comments | get_mr_comments | --project-id N --mr IID |
add_merge_request_comment | add_mr_comment | --project-id N --mr IID --body-file F |
add_merge_request_diff_comment | add_diff_comment | --project-id N --mr IID --base-sha S --start-sha S --head-sha S --file P --line L --body-file F |
get_issue_details | get_issue | --project-id N --issue IID |
set_merge_request_description | set_mr_description | --project-id N --mr IID --body-file F |
set_merge_request_title | set_mr_title | --project-id N --mr IID --title "…" |
create_merge_request_comment(Notes API,普通评论) | create_note | --project-id N --mr IID --body-file F |
edit_merge_request_comment | edit_note | --project-id N --mr IID --note-id ID --body-file F |
delete_merge_request_comment | delete_note | --project-id N --mr IID --note-id ID |
传递评论内容: 评论、评分卡和描述文本都是较长的 Markdown(包含反引号、换行和代码围栏),直接通过命令行传递容易出错。对于每条写入命令,请先将内容写入临时文件(例如 /tmp/claude-review-<short>.md),然后通过 --body-file <path> 传入。简单的一行文本可使用简短的 --body "text" 标志;set_mr_title 也支持与 --body-file 类似的 --title-file。对任何读取命令添加 --verbose,即可获取未经筛选的完整 GitLab 响应。
输入
用户提供了:$ARGUMENTS
内容可能是以下形式之一:
- 完整的 GitLab MR URL:
https://gitlab.com/group/project/-/merge_requests/42 - 带 MR IID 的路径:
group/project !42 - 仅提供 MR IID,且项目可从上下文中明确得知:
!42
阶段 0 — 设置
步骤 1:解析输入
从输入中提取项目路径(例如 group/project)和 MR IID(例如 42)。
如果提供的是完整 URL,请按以下方式解析:
https://gitlab.com/group/subgroup/project/-/merge_requests/42→ 项目路径 =group/subgroup/project,IID =42
步骤 2:查找项目 ID
运行 gitlab.mjs get_projects 列出项目。匹配项目路径(path_with_namespace),以查找数值 id(即 --project-id)。
如果 $ARGUMENTS 中仅包含 MR IID(例如 !42),请向用户询问项目路径。
步骤 3:获取 MR 数据(3 个并行调用)
并行运行以下命令(在同一条消息中独立调用 Bash):
gitlab.mjs get_mr --project-id N --mr IID— 元数据 +diff_refs(包含 Phase 2 所需的base_sha、start_sha、head_sha)gitlab.mjs get_mr_diff --project-id N --mr IID— 完整代码差异gitlab.mjs get_mr_comments --project-id N --mr IID— 已有的审查评论(用于去重)
Phase 1 — 分析(只读,不写入 GitLab)
重要:Phase 1 期间不要运行任何写入命令。不要运行 add_mr_comment、create_note、add_diff_comment、edit_note、delete_note 或 set_mr_*。Phase 1 严格只读。
步骤 4:分类并制定分块计划
统计变更文件总数,并估算差异内容的总字符数。对 MR 进行分类:
| 规模 | 阈值 | 策略 |
|---|---|---|
| 小型 | <15 个文件或 <50K 字符 | 单次审查 — 一起审查所有差异 |
| 中型 | 15-50 个文件或 50K-150K 字符 | 分为 3-5 块 |
| 大型 | 50 个以上文件或 150K 以上字符 | 分为 5-10 块,每块约 15-25 个文件 |
分组启发式规则(按优先级应用):
- 功能组 — 相互协作的文件(例如,一个区块的
block.ts+Component.tsx+index.ts) - 目录 —
payload/blocks/**、components/**、app/[locale]/**、packages/** - 配置/基础设施 —
package.json、CI 配置、迁移文件、docker 文件 → 合并为一块 - 生成文件/锁文件 —
payload-types.ts、pnpm-lock.yaml、*.gen.ts→ 完全跳过(在“跳过的文件”部分注明)
开始审查前打印分块计划:
Review plan: [Single-pass | N chunks]
- Chunk 1: [Label] ([N] files) — file1.ts, file2.ts, ...
- Chunk 2: [Label] ([N] files) — ...
- Skipped: [N] files (generated/lock)
步骤 5:索引已有评论
根据 get_mr_comments 的结果,建立所有已有审查评论的索引:
note_id(每条评论的id字段 — 编辑/删除操作时需要)- 文件路径 + 行号(针对差异评论)
- 问题内容 / 评论涉及的内容
- 是否已解决或仍未解决
- 作者姓名
审查期间的规则:
- 如果已有评论指出了某个问题 → 跳过该问题,并在“之前已提出”部分列出
- 如果已有评论指出的问题似乎已在当前差异中修复 → 标注为“似乎已修复”
- 还要检查是否有包含 `` 的评论 — 如果找到,记录其
note_id和日期,以便制定评分卡更新策略
补充缺少修复提示的先前 Claude Code 审查评论:
- 查找包含 `` 标记的差异评论(由先前运行此技能的流程发布),且尚未包含
💡 **修复提示:**块 - 如果该问题仍然存在(当前差异中尚未修复),为其生成修复提示
- 在草稿中单独的“已补充的评论”部分列出这些评论
- 这些内容将通过
note_id编辑到原评论中(追加修复提示块) - 注意:引入此标记之前发布的评论无法被检测到,这是预期行为
第 6 步:分块深入审查
对于每个分块(小型 MR 可一次性审查):
- 打印进度标题:
"Reviewing chunk 2/5: Design system components..." - 从差异数据中提取该分块的差异(按属于该分块的文件路径筛选)
- 对于每个有实质改动的文件:使用 Read 工具读取完整的本地文件,以了解改动周围的上下文
- 结合差异和本地上下文分析:
- 错误:逻辑错误、边界值偏差、null/undefined 风险、竞态条件
- 安全性:注入漏洞、身份验证问题、数据泄露、OWASP 十大风险
- 性能:N+1 查询、不必要的重新渲染、缺少记忆化、大型负载
- 风格:违反项目约定(参见 CLAUDE.md/AGENTS.md — 禁止使用原生 HTML 标签、禁止使用内联样式、仅使用 PandaCSS、严格遵守导入规范等)
- 逻辑:业务逻辑错误、遗漏边界情况、错误处理不完整
- 类型:TypeScript 类型安全问题、类型过于宽泛、缺少类型保护
- 记录发现,包括:文件、行号、严重程度、类别、描述、修复提示
- 不要在分块之间展示发现——先累计所有发现,最后一次性展示
第 7 步:计算置信度分数
从 7/10 开始,根据以下五个维度进行调整:
1. 覆盖范围
| 调整值 | 条件 |
|---|---|
| +1 | 已结合完整的本地上下文阅读所有改动文件 |
| 0 | 已阅读大多数文件,跳过少量文件(生成文件/锁定文件) |
| -1 | 分块审查时各分块之间存在上下文缺失 |
| -2 | 跳过了许多文件,或只阅读了差异(没有阅读本地文件) |
2. 代码复杂度
| 调整值 | 条件 |
|---|---|
| +1 | 简单明了——声明式代码、配置、UI 组件、翻译 |
| 0 | 标准——控制流清晰、功能实现结构良好 |
| -1 | 有一定复杂度——算法、状态机、复杂的数据转换 |
| -2 | 高度复杂——动态代码生成、深层嵌套的异步逻辑、精细复杂的缓存 |
3. 安全性发现
| 调整值 | 条件 |
|---|---|
| +1 | 已审查安全敏感区域,未发现问题 |
| 0 | MR 中没有安全敏感代码 |
| -1 | 发现轻微安全问题 |
| -2 | 发现严重安全问题 |
4. 测试覆盖信号
| 调整值 | 条件 |
|---|---|
| +1 | MR 包含覆盖新增/改动逻辑的测试 |
| 0 | 现有测试可能覆盖这些改动 |
| -1 | 没有测试,且改动影响业务逻辑或数据流 |
5. 领域熟悉度
| 调整值 | 条件 |
|---|---|
| +1 | 文档完善且模式清晰的领域(例如 Payload 区块) |
| 0 | 标准项目领域 |
| -1 | 不熟悉的领域、第三方集成、未记录文档的 API |
最终分数 = clamp(7 + 调整值之和,1,10)
按照下方评分卡格式中的标准表格展示明细(每个维度一行,包含分值和说明)。
第 8 步:展示审查草稿
合并所有分块的发现,去重,并按严重程度排序(严重问题优先),然后展示完整草稿。
严重程度表情符号:
- 🔴 严重 — 错误、安全漏洞、数据丢失风险
- 🟠 警告 — 性能问题、潜在错误、逻辑问题
- 🟡 建议 — 风格问题、小幅改进、最佳实践
- 🟢 细节 — 外观问题、可选改进、纯风格问题
使用此确切格式:
## MR Review Draft: group/project !IID
**Title:** [MR title]
**Author:** [MR author]
**Branch:** [source_branch] → [target_branch]
**Review method:** [Single-pass | Chunked (N chunks)]
**Files reviewed:** X/Y (Z skipped)
---
### Review Scorecard (will be posted as MR comment)
## 🔍 Review Scorecard
# Confidence Score: [N]/10
| Criteria | Points | Explanation |
|----------|--------|-------------|
| Base | 7 | — |
| Read coverage | [+1/0/-1/-2] | [One-line reason] |
| Code complexity | [+1/0/-1/-2] | [One-line reason] |
| Security | [+1/0/-1/-2] | [One-line reason] |
| Test coverage | [+1/0/-1/-2] | [One-line reason] |
| Familiarity | [+1/0/-1] | [One-line reason] |
**Reviewed:** [X]/[Y] files ([Z] skipped: [reason])
**Method:** [Single-pass review | Chunked deep review (N chunks)]
### Summary
[2-4 sentence assessment. Is it ready to merge? What are the main themes?]
### Findings Breakdown
| Severity | Count | Key Areas |
|----------|-------|-----------|
| Critical | N | [areas or —] |
| Warning | N | [areas or —] |
| Suggestion | N | [areas or —] |
| Nit | N | [areas or —] |
### Verdict
[APPROVE / APPROVE WITH SUGGESTIONS / REQUEST CHANGES / NEEDS DISCUSSION]
[One sentence explaining the verdict]
---
*Automated review by Claude Code — [N] inline comments posted, [M] existing comments edited with fix prompts*
---
### Previously Raised (will NOT be re-posted)
- `src/foo.tsx:12` — Missing null check (by @author, still open)
- `src/bar.tsx:45` — Unused import (by @author, appears fixed)
*[Or: "No existing review comments found."]*
---
### Augmented Comments (fix prompts for previous Claude Code review comments)
These will be edited into previous `/review-gitlab` comments that lacked a fix prompt:
A1. ✏️ Edit previous review on `[file_path]:[line_number]` (note_id: [id]) — "[original comment summary]"
💡 **Fix prompt:** "[Imperative fix description referencing exact file paths,
line numbers, current code, and expected replacement.]"
A2. ✏️ Edit previous review on `[file_path]:[line_number]` (note_id: [id]) — "[original comment summary]"
💡 **Fix prompt:** "[...]"
*[Or: "No existing comments need augmentation."]*
---
### New Findings
1. 🔴 **Bug** — `[file_path]:[line_number]`
> [Clear description of the issue]
💡 **Fix prompt:** "[Imperative description of what to change, referencing exact
file paths, line numbers, current code, and expected replacement. Specific enough
to execute without further searching.]"
2. 🟠 **Performance** — `[file_path]:[line_number]`
> [Clear description of the issue]
💡 **Fix prompt:** "[...]"
3. 🟡 **Convention** — `[file_path]:[line_number]`
> [Clear description of the issue]
💡 **Fix prompt:** "[...]"
[...more findings sorted by severity...]
---
### Skipped Files
- `apps/nextjs/payload-types.ts` — Generated
- `pnpm-lock.yaml` — Lock file
[Or: "No files skipped."]
然后询问:
**What would you like to post to GitLab?**
- `all` — scorecard + all findings + all augmented comments
- `none` — discard everything
- `scorecard only` — just the scorecard comment
- `1, 3, 5` — scorecard + these numbered findings only
- `all except 2` — scorecard + all findings except these
- `augments only` — scorecard + augmented comment edits only (no new findings)
- `A1, A2` — specific augmented comments only
- `edit 3` — edit an existing posted finding's comment (by note_id from Step 5)
- `delete 3` — delete an existing posted finding's comment (by note_id from Step 5)
- `dry-run <selection>` — preview what would be posted without posting (e.g. `dry-run all`, `dry-run 1, 3`)
- Or edit any finding/prompt before posting
如果未发现问题,仍需展示评分卡,给出正面评价,并询问用户是否希望发布。
阶段 2 — 发布(仅在用户批准后)
等待用户回复并作出选择。然后:
步骤 9:发布已批准的评论
试运行模式: 如果用户的选择以 dry-run 开头,请勿运行任何写入命令。请改为解析 dry-run 前缀后的选择(例如,dry-run all → 视为 all,dry-run 1, 3 → 视为 1, 3),并为每项_将要执行_的操作打印一个摘要块:
## Dry Run — Actions Preview
The following actions would be taken (nothing was posted):
1. 📝 **Create scorecard comment** (plain note)
- Command: `gitlab.mjs create_note`
- Body preview: [first 200 chars of scorecard]...
2. 💬 **Post diff comment** on `src/foo.tsx:42`
- Command: `gitlab.mjs add_diff_comment`
- Severity: 🔴 Critical — [category]
- Body preview: [first 150 chars]...
3. ✏️ **Edit existing comment** (note_id: 12345) — append fix prompt
- Command: `gitlab.mjs edit_note`
- Appending: 💡 Fix prompt for [description]
4. ✏️ **Update existing scorecard** (note_id: 67890)
- Command: `gitlab.mjs edit_note`
- Body preview: [first 200 chars]...
---
Total: N new comments, M edits, D deletes
Ready to post? Reply with your selection (without `dry-run`) to execute.
然后停止并等待用户的下一条回复。请勿继续发布评论。
正常发布模式: 根据用户的选择。对于每次写入,将评论正文写入临时文件(例如 /tmp/claude-review-<n>.md),并传入 --body-file:
-
评分卡评论:将评分卡(从 `` 到结尾的
---之间的全部内容)作为 MR 通用评论发布。评分卡更新策略:
- 如果在步骤 5 中找到了包含 `` 的现有评论,请原地编辑该评论:
gitlab.mjs edit_note --project-id N --mr IID --note-id <recorded id> --body-file <file>。在新评分卡正文末尾追加\n\n> ℹ️ Updated from previous scorecard。 - 如果没有找到现有评分卡,请发布新的评分卡:
gitlab.mjs create_note --project-id N --mr IID --body-file <file>(Notes API——创建普通评论,而非可解决的讨论串)。
- 如果在步骤 5 中找到了包含 `` 的现有评论,请原地编辑该评论:
-
代码行级问题:对于每个已批准的问题,将其作为差异评论发布:
gitlab.mjs add_diff_comment --project-id N --mr IID --base-sha <base> --start-sha <start> --head-sha <head> --file <path> --line <line> --body-file <file>,其中:--base-sha/--start-sha/--head-sha:取自diff_refs(在步骤 3 中获取)--file:差异中显示的文件路径--line:行号(映射到 GitLab API 中的new_line——目标是文件的新版本)- 正文文件内容:
\n**[Severity emoji] [Category]**: [description]\n\n💡 **Fix prompt:**\n\``\n[fix prompt text]\n````
尽可能并行运行差异评论命令(在同一条消息中发起相互独立的 Bash 调用)。
-
增强评论:对于每条已批准的增强评论(A1、A2 等),原地编辑原评论:
gitlab.mjs edit_note --project-id N --mr IID --note-id <original id> --body-file <file>。将正文设置为原评论正文,并在末尾追加修复提示块:- 追加:
\n\n💡 **Fix prompt:**\n\``\n[fix prompt text]\n```\n\n*— Fix prompt added by Claude Code review*`
尽可能并行编辑这些评论。
- 追加:
-
如果用户编辑了任何评论文本,发布时请使用编辑后的版本。
-
编辑/删除现有评论:如果用户选择了
edit N或delete N:edit N— 询问用户要使用的新文本(也可以让用户直接提供文本),然后运行gitlab.mjs edit_note --project-id N --mr IID --note-id <id of finding #N> --body-file <file>。delete N— 向用户确认,然后运行gitlab.mjs delete_note --project-id N --mr IID --note-id <id of finding #N>。
步骤 10:报告结果
发布后,报告:
## Review Posted ✓
Posted to [MR URL]:
- Scorecard comment [posted | edited in place] (confidence: N/10, verdict: [VERDICT])
- [N] inline comments on [files list]
- [M] existing comments edited with fix prompts
- [D] comments deleted (if any)
[Any errors that occurred during posting]
如果任何评论发布失败(例如,文件已删除导致行号无效),请报告错误并继续发布其余评论。
修复提示指南
为问题编写修复提示时,请遵循以下规则:
- 引用差异中的确切文件路径和行号
- 清楚地描述当前代码和预期替换内容
- 当多个文件中的相关修复具有相同根本原因时,将它们合并到一个提示中
- 使用祈使语气:“替换……”“移除……”“添加……”“重构……”
- 内容应具体到无需进一步搜索代码库即可执行
- 针对 Claude Opus/Sonnet 进行优化——明确、无歧义,避免用代词指代代码
- 如果需要新增导入,请包含导入路径