mcpField
R
review-gitlab

review-gitlab

github.com/thisfrontenddev测试与质量073 次安装11 周前更新
代码仓库

关于 review-gitlab

review-gitlab 是用于 GitLab Merge Request 的代码审查技能,面向希望先审阅分析、再决定是否发布评论的开发者。它采用只读分析与用户批准后写入的两阶段流程,并为发现的问题附上 Claude Code 修复提示。

主要功能

  1. 01按规模分块审查变更
  2. 02检查缺陷、安全、性能与类型
  3. 03读取现有评论以避免重复
  4. 04为发现项生成修复提示
  5. 05批准后发布 GitLab 评论

适用场景

  1. 01深入审查大型 Merge Request
  2. 02在发布前检查并确认审查发现
  3. 03跟踪已报告问题及其修复状态
  4. 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_projectsget_projects—(可选 --verbose)
list_open_merge_requestslist_open_mrs--project-id N
get_merge_request_detailsget_mr--project-id N --mr IID
get_merge_request_diffget_mr_diff--project-id N --mr IID
get_merge_request_commentsget_mr_comments--project-id N --mr IID
add_merge_request_commentadd_mr_comment--project-id N --mr IID --body-file F
add_merge_request_diff_commentadd_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_detailsget_issue--project-id N --issue IID
set_merge_request_descriptionset_mr_description--project-id N --mr IID --body-file F
set_merge_request_titleset_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_commentedit_note--project-id N --mr IID --note-id ID --body-file F
delete_merge_request_commentdelete_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):

  1. gitlab.mjs get_mr --project-id N --mr IID — 元数据 + diff_refs(包含 Phase 2 所需的 base_sha、start_sha、head_sha)
  2. gitlab.mjs get_mr_diff --project-id N --mr IID — 完整代码差异
  3. 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 个文件

分组启发式规则(按优先级应用):

  1. 功能组 — 相互协作的文件(例如,一个区块的 block.ts + Component.tsx + index.ts)
  2. 目录 — payload/blocks/**、components/**、app/[locale]/**、packages/**
  3. 配置/基础设施 — package.json、CI 配置、迁移文件、docker 文件 → 合并为一块
  4. 生成文件/锁文件 — 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 可一次性审查):

  1. 打印进度标题:"Reviewing chunk 2/5: Design system components..."
  2. 从差异数据中提取该分块的差异(按属于该分块的文件路径筛选)
  3. 对于每个有实质改动的文件:使用 Read 工具读取完整的本地文件,以了解改动周围的上下文
  4. 结合差异和本地上下文分析:
    • 错误:逻辑错误、边界值偏差、null/undefined 风险、竞态条件
    • 安全性:注入漏洞、身份验证问题、数据泄露、OWASP 十大风险
    • 性能:N+1 查询、不必要的重新渲染、缺少记忆化、大型负载
    • 风格:违反项目约定(参见 CLAUDE.md/AGENTS.md — 禁止使用原生 HTML 标签、禁止使用内联样式、仅使用 PandaCSS、严格遵守导入规范等)
    • 逻辑:业务逻辑错误、遗漏边界情况、错误处理不完整
    • 类型:TypeScript 类型安全问题、类型过于宽泛、缺少类型保护
  5. 记录发现,包括:文件、行号、严重程度、类别、描述、修复提示
  6. 不要在分块之间展示发现——先累计所有发现,最后一次性展示
第 7 步:计算置信度分数

从 7/10 开始,根据以下五个维度进行调整:

1. 覆盖范围
调整值条件
+1已结合完整的本地上下文阅读所有改动文件
0已阅读大多数文件,跳过少量文件(生成文件/锁定文件)
-1分块审查时各分块之间存在上下文缺失
-2跳过了许多文件,或只阅读了差异(没有阅读本地文件)
2. 代码复杂度
调整值条件
+1简单明了——声明式代码、配置、UI 组件、翻译
0标准——控制流清晰、功能实现结构良好
-1有一定复杂度——算法、状态机、复杂的数据转换
-2高度复杂——动态代码生成、深层嵌套的异步逻辑、精细复杂的缓存
3. 安全性发现
调整值条件
+1已审查安全敏感区域,未发现问题
0MR 中没有安全敏感代码
-1发现轻微安全问题
-2发现严重安全问题
4. 测试覆盖信号
调整值条件
+1MR 包含覆盖新增/改动逻辑的测试
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:

  1. 评分卡评论:将评分卡(从 `` 到结尾的 --- 之间的全部内容)作为 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——创建普通评论,而非可解决的讨论串)。
  2. 代码行级问题:对于每个已批准的问题,将其作为差异评论发布: 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 调用)。

  3. 增强评论:对于每条已批准的增强评论(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*`

    尽可能并行编辑这些评论。

  4. 如果用户编辑了任何评论文本,发布时请使用编辑后的版本。

  5. 编辑/删除现有评论:如果用户选择了 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 进行优化——明确、无歧义,避免用代词指代代码
  • 如果需要新增导入,请包含导入路径

评论

支持 Markdown