mcpField
A
attach-review-to-pr

attach-review-to-pr

github.com/neolabhq测试与质量1.8k1.2k 次安装9 周前更新
代码仓库

关于 attach-review-to-pr

介绍如何在 GitHub 拉取请求中发布针对具体代码行的审查意见。说明优先使用可用的 MCP 工具,也涵盖 GitHub CLI API 备用方案、批量审查和问题排查。

主要功能

  1. 01针对 diff 的具体行发表评论
  2. 02将多条意见合并为一次审查
  3. 03使用 GitHub CLI REST API 端点
  4. 04指定多行评论范围
  5. 05排查提交和行号验证问题

适用场景

  1. 01对 PR 中更改的代码行提供反馈
  2. 02将相关意见作为一次审查提交
  3. 03内联评论 MCP 工具不可用时发表评论

MCP 相关

建议在可用时使用 `mcp__github_inline_comment__create_inline_comment` 工具添加 PR 行内评论,并将 GitHub CLI API 调用作为备用方案。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/neolabhq/context-engineering-kit --skill attach-review-to-pr

安装后在 Claude Code 中输入/attach-review-to-pr确认已加载。

详细介绍

如何为拉取请求添加针对特定行的审查评论

本指南介绍如何使用 GitHub CLI(gh)API,或在无法使用 mcp__github_inline_comment__create_inline_comment 时,通过该工具为拉取请求添加针对特定行的审查评论,类似于在 GitHub UI 中对代码的特定行发表评论。

首选方法:使用 MCP GitHub 工具

如果可用,请使用 mcp__github_inline_comment__create_inline_comment MCP 工具,在拉取请求中发布针对特定行的行内评论。此方法与 GitHub UI 的集成更好,也是推荐的方法。

备用方法:如果 MCP 工具不可用,请使用下文所述的 GitHub CLI(gh)API 方法:

概述

虽然 gh pr review 提供了基本的审查功能(批准、请求更改、一般评论),但它不支持直接添加针对特定行的评论。要对代码的特定行发表评论,必须使用较底层的 gh api 命令直接调用 GitHub REST API。

前提条件

  1. 已安装并完成身份验证的 GitHub CLI:

    gh auth status
    
  2. 有权访问要审查的仓库和拉取请求

了解 GitHub 的审查评论系统

GitHub 有两种 PR 评论:

  1. Issue 评论——在 PR 对话中的一般评论
  2. 审查评论——针对代码更改特定行的评论

审查评论可通过两种方式添加:

  • 单条评论——使用 /pulls/{pr}/comments 端点
  • 包含多条评论的审查——使用 /pulls/{pr}/reviews 端点

添加单条针对特定行的评论

基本语法
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \
  -f body='Your comment text here' \
  -f commit_id='<commit-sha>' \
  -f path='path/to/file.js' \
  -F line=42 \
  -f side='RIGHT'
参数说明
参数类型必需说明
bodystring是审查评论的文本(支持 Markdown)
commit_idstring是要发表评论的提交 SHA
pathstring是被评论文件的相对路径
lineinteger是差异中的行号(整数请使用 -F)
sidestring是新增或修改的行使用 RIGHT,已删除的行使用 LEFT
start_lineinteger否多行评论的起始行
start_sidestring否多行评论的起始侧
参数标志
  • -f(--field)——用于字符串值
  • -F(--field)——用于整数值(注意大写 F)
完整示例
# First, get the latest commit SHA for the PR
gh api repos/NeoLabHQ/learning-platform-app/pulls/4 --jq '.head.sha'

# Then add your comment
gh api repos/NeoLabHQ/learning-platform-app/pulls/4/comments \
  -f body='Consider adding error handling here. Should we confirm the lesson was successfully marked as completed before navigating away?' \
  -f commit_id='e152d0dd6cf498467eadbeb638bf05abe11c64d4' \
  -f path='src/components/LessonNavigationButtons.tsx' \
  -F line=26 \
  -f side='RIGHT'
了解行号

line 参数指的是差异中的位置,而非文件中的绝对行号:

  • 对于新文件:行号与文件中的行号一致
  • 对于已修改的文件:使用“Files changed”选项卡中显示的行号
  • 对于多行评论:使用 start_line 和 line 指定范围
响应

成功时会返回包含评论详情的 JSON 对象:

{
  "id": 2532291222,
  "pull_request_review_id": 3470545909,
  "path": "src/components/LessonNavigationButtons.tsx",
  "line": 26,
  "body": "Consider adding error handling here...",
  "html_url": "https://github.com/NeoLabHQ/learning-platform-app/pull/4#discussion_r2532291222",
  "created_at": "2025-11-16T22:40:46Z"
}

一次添加多条针对特定行的评论

要在一次审查中为不同文件添加多条评论,请使用 /reviews 端点并提供 JSON 输入。

为什么要用审查一次添加多条评论?
  • 原子操作——所有评论会一并添加
  • 单条通知——避免发送多条通知造成骚扰
  • 更好的用户体验——评论会作为一条连贯的审查显示
  • 与 GitHub UI 使用相同机制——“Start a review” → “Finish review”
基本语法
cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews --input -
{
  "event": "COMMENT",
  "body": "Overall review summary (optional)",
  "comments": [
    {
      "path": "file1.tsx",
      "body": "Comment on file 1",
      "side": "RIGHT",
      "line": 15
    },
    {
      "path": "file2.tsx",
      "body": "Comment on file 2",
      "side": "RIGHT",
      "line": 30
    }
  ]
}
EOF
审查事件类型
事件说明使用场景
COMMENT一般审查评论仅提供反馈,不批准
APPROVE批准 PR更改看起来不错,可以合并
REQUEST_CHANGES请求更改合并前必须修复的问题
完整示例
cat <<'EOF' | gh api repos/NeoLabHQ/learning-platform-app/pulls/4/reviews --input -
{
  "event": "COMMENT",
  "body": "Testing multiple line-specific comments via gh api",
  "comments": [
    {
      "path": "src/components/CourseCard.tsx",
      "body": "Test comment generated by Claude",
      "side": "RIGHT",
      "line": 15
    },
    {
      "path": "src/components/CourseProgressWidget.tsx",
      "body": "Test comment generated by Claude",
      "side": "RIGHT",
      "line": 30
    },
    {
      "path": "src/components/LessonProgressTracker.tsx",
      "body": "Test comment generated by Claude",
      "side": "RIGHT",
      "line": 20
    }
  ]
}
EOF
响应
{
  "id": 3470546747,
  "state": "COMMENTED",
  "html_url": "https://github.com/NeoLabHQ/learning-platform-app/pull/4#pullrequestreview-3470546747",
  "submitted_at": "2025-11-16T22:42:43Z",
  "commit_id": "e152d0dd6cf498467eadbeb638bf05abe11c64d4"
}

常见问题和解决方案

问题 1:"user_id can only have one pending review per pull request"

错误消息:

gh: Validation Failed (HTTP 422)
{"message":"Validation Failed","errors":[{"resource":"PullRequestReview","code":"custom","field":"user_id","message":"user_id can only have one pending review per pull request"}]}

原因: GitHub 只允许每位用户对每个 PR 有一条待处理(尚未提交)的评审。如果你之前通过 UI 或 API 开始了评审但没有提交,就会阻止创建新的评审。

解决方案 1:提交待处理的评审

# Check for pending reviews
gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews | jq '.[] | select(.state=="PENDING")'

# Submit it through the UI or ask the user to submit it

解决方案 2:改用单条评论端点

# Add individual comments without creating a review
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \
  -f body='Comment text' \
  -f commit_id='<sha>' \
  -f path='file.tsx' \
  -F line=26 \
  -f side='RIGHT'
问题 2:使用 --raw-field 时数组语法无效

尝试失败:

# This does NOT work - GitHub API receives an object, not an array
gh api repos/{owner}/{repo}/pulls/{pr}/reviews \
  --raw-field 'comments[0][path]=file1.tsx' \
  --raw-field 'comments[0][line]=15' \
  --raw-field 'comments[1][path]=file2.tsx' \
  --raw-field 'comments[1][line]=30'

错误:

Invalid request. For 'properties/comments', {"0" => {...}, "1" => {...}} is not an array.

解决方案: 通过 heredoc 使用 JSON 输入:

cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/{pr}/reviews --input -
{
  "comments": [...]
}
EOF
问题 3:行号无效

错误消息:

Pull request review thread line must be part of the diff

原因: 此文件的差异中不存在该行号。

解决方案:

  • 确认此 PR 确实修改了该文件
  • 查看“Files changed”标签页,确认差异中的实际行号
  • 确保使用正确的 commit_id(PR 中的最新提交)
问题 4:commit_id 错误

错误消息:

commit_sha is not part of the pull request

解决方案: 获取最新提交的 SHA:

gh api repos/{owner}/{repo}/pulls/{pr_number} --jq '.head.sha'

最佳实践

1. 首先获取 PR 信息

添加评论前,先收集必要信息:

# Get PR details
gh pr view {pr_number} --json headRefOid,files

# Or use the API
gh api repos/{owner}/{repo}/pulls/{pr_number} --jq '{commit: .head.sha, files: [.changed_files]}'

# List files changed
gh api repos/{owner}/{repo}/pulls/{pr_number}/files --jq '.[] | {filename: .filename, additions: .additions, deletions: .deletions}'
2. 检查是否有待处理的评审
# Check if you have a pending review
gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews \
  --jq '.[] | select(.state=="PENDING" and .user.login=="YOUR_USERNAME")'
3. 使用有意义的评论文本
  • 具体且具有建设性
  • 引用文档或最佳实践
  • 请求修改时提供替代方案
  • 使用代码块提供代码建议:
Consider using async/await:

\`\`\`typescript
async function getData() {
  const result = await fetch(url);
  return result.json();
}
\`\`\`
4. 批量提交相关评论

使用评审端点将相关评论分组:

  • 同一文件或区域的所有评论
  • 针对特定问题(安全、性能等)的所有评论
  • 完整的评审会话
5. 选择合适的事件类型
# For feedback during development
"event": "COMMENT"

# When approving
"event": "APPROVE"

# When blocking merge
"event": "REQUEST_CHANGES"

工作流示例

示例 1:快速添加单条评论
#!/bin/bash
OWNER="NeoLabHQ"
REPO="learning-platform-app"
PR=4

# Get latest commit
COMMIT=$(gh api repos/$OWNER/$REPO/pulls/$PR --jq '.head.sha')

# Add comment
gh api repos/$OWNER/$REPO/pulls/$PR/comments \
  -f body='Consider extracting this into a separate function for better testability' \
  -f commit_id="$COMMIT" \
  -f path='src/utils/validation.ts' \
  -F line=45 \
  -f side='RIGHT'
示例 2:全面评审
#!/bin/bash
OWNER="NeoLabHQ"
REPO="learning-platform-app"
PR=4

# Create review with multiple comments
cat <<EOF | gh api repos/$OWNER/$REPO/pulls/$PR/reviews --input -
{
  "event": "COMMENT",
  "body": "Thanks for the PR! I've reviewed the changes and have a few suggestions.",
  "comments": [
    {
      "path": "src/components/CourseCard.tsx",
      "body": "Consider memoizing this component to prevent unnecessary re-renders",
      "side": "RIGHT",
      "line": 25
    },
    {
      "path": "src/utils/courseProgress.ts",
      "body": "This function could benefit from error handling for invalid course IDs",
      "side": "RIGHT",
      "line": 12
    },
    {
      "path": "src/state/CourseProgressState.ts",
      "body": "Consider adding JSDoc comments to document the expected behavior",
      "side": "RIGHT",
      "line": 8
    }
  ]
}
EOF
示例 3:多行评论
# Comment on a range of lines (e.g., lines 10-15)
gh api repos/$OWNER/$REPO/pulls/$PR/comments \
  -f body='This entire block could be simplified using array destructuring' \
  -f commit_id="$COMMIT" \
  -f path='src/utils/parser.ts' \
  -F start_line=10 \
  -f start_side='RIGHT' \
  -F line=15 \
  -f side='RIGHT'

实用辅助脚本

获取 PR 文件和行号
#!/bin/bash
# pr-files.sh - List all files changed in a PR with line counts

OWNER="$1"
REPO="$2"
PR="$3"

gh api repos/$OWNER/$REPO/pulls/$PR/files --jq '.[] | "\(.filename): +\(.additions)/-\(.deletions)"'
检查评审状态
#!/bin/bash
# check-reviews.sh - Check review status for a PR

OWNER="$1"
REPO="$2"
PR="$3"

echo "=== Reviews ==="
gh api repos/$OWNER/$REPO/pulls/$PR/reviews --jq '.[] | "\(.user.login): \(.state) at \(.submitted_at)"'

echo -e "\n=== Pending Reviews ==="
gh api repos/$OWNER/$REPO/pulls/$PR/reviews --jq '.[] | select(.state=="PENDING") | "\(.user.login): \(.state)"'

相关文档

API 参考

POST /repos/{owner}/{repo}/pulls/{pull_number}/comments

在特定行创建评审评论。

端点: https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/comments

参数:

  • body(string,必填):评论文本
  • commit_id(string,必填):提交的 SHA
  • path(string,必填):相对文件路径
  • line(integer,必填):差异中的行号
  • side(string,必填):"LEFT" 或 "RIGHT"
  • start_line(integer,可选):多行评论的起始行
  • start_side(string,可选):多行评论的起始侧
POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews

创建评审,并可选择添加特定行的评论。

端点: https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/reviews

参数:

  • event(string,必填):"APPROVE"、"REQUEST_CHANGES" 或 "COMMENT"
  • body(string,可选):总体评审评论
  • comments(array,可选):评论对象数组
  • commit_id(string,可选):要评审的提交 SHA

评论对象:

  • path(string,必填):相对文件路径
  • body(string,必填):评论文本
  • line(integer,必填):差异中的行号
  • side(string,必填):"LEFT" 或 "RIGHT"
  • start_line(integer,可选):多行评论的起始行
  • start_side(string,可选):多行评论的起始侧

评论

支持 Markdown