0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Claude Code】 Copilotのコードレビュー修正を自動化する

0
Posted at

はじめに

今回はGitHubを用いた開発において、GitHub Copilotによるコードレビューを導入している場合におすすめのSkillを作成してみました。
内容としては、

  1. 出したプルリクエストに対するGitHub Copilotのレビュー結果を取得する
  2. 修正の提案をClaude Codeがレビューし、必要があれば対応する

です。

関連するこれらの記事も参考にしてみてください。

リクエスト内容

skill-creatorを使用しています。
今回は以下のようにリクエストしました。
曖昧な内容は逆質問で聞いてくれるのでとても助かります。

SCR-20260511-pzcv.png

完成したのがこちら

一部マークダウンの仕様上、[```]の前に#を入れています。

~.claude/skills/handle-copilot-review/SKILL.md
---
name: handle-copilot-review
description: 現在のgitブランチに紐づくPullRequestを特定し、GitHub Copilotコードレビュー(copilot-pull-request-reviewer[bot])が残した未解決の指摘を1件ずつ取り出して、コメント内容と該当コード・周辺コンテキストを確認した上で「採用すべきか」をユーザーと対話的に判断していくスキル。ユーザーが `/handle-copilot-review` と入力したとき、または「Copilotのレビューを処理して」「Copilotレビューを反映」「Copilotの指摘を見て」「Copilotのコメントに対応して」「PRのCopilotレビュー見てくれる?」「Copilotレビュー潰して」など、PR上に積まれたGitHub Copilotレビューを精査・取り込み・取捨選択したい場面で必ず使用する。コメント1件ごとに「適用 / スキップ / さらに議論」をユーザー判断で進める対話型ワークフロー、未解決スレッドのみを対象にする取り扱い、Copilot以外のレビュアーを対象外とする方針が必要なすべてのケースで本スキルを優先的に呼び出すこと。コミットやpushは行わず、作業ツリーへの修正反映までを担当する。
---

# handle-copilot-review

現在のgitブランチに紐づくGitHub PullRequestを特定し、GitHub Copilotコードレビュー(`copilot-pull-request-reviewer[bot]`)が残した **未解決の** 指摘コメントを1件ずつ精査して、コードコンテキストを踏まえながらユーザーと対話で「採用するか」を決定し、必要なものは作業ツリーに反映していくスキル。

## このスキルが目指すこと

GitHub Copilotコードレビューは便利な反面、機械的に出される指摘の中には「文脈を踏まえると不要」「事実誤認」「スタイル上の好み」など、そのまま採用すべきでないものも混ざる。一方で本質的なバグや見落としを拾うこともあり、無視はできない。本スキルの役割は次の通り:

1. 現在のブランチからPR番号を特定し、ユーザーに提示する
2. Copilotの未解決レビューコメントを **未解決スレッド単位** で取得する
3. コメント1件ごとに「指摘内容 + 該当コード + 周辺コンテキスト」を提示し、Claudeとして採用可否の評価を述べる
4. ユーザーが **適用 / スキップ / さらに議論** の3択で判断する
5. 「適用」なら作業ツリーに修正を反映、「スキップ」なら何もせず次へ、「さらに議論」ならその場で対話を続ける
6. 全件処理後、何を適用し何をスキップしたかの一覧をサマリ表示する
7. **コミット・push・PRスレッドの返信や解決操作は一切行わない**

ユーザーが目指すゴールは「Copilotの指摘を丁寧に1件ずつ吟味し、本当に取り込むべきものだけを反映した状態の作業ツリー」である。スキルはレビューの判断を奪わず、判断のためのお膳立てに徹する。

## 実行手順

### Step 1: 前提条件と現在の状態を一括取得

以下を **並列で** 実行する:

#```bash
git branch --show-current
#```

#```bash
git status --short
#```

#```bash
gh auth status
#```

#```bash
gh repo view --json nameWithOwner,defaultBranchRef --jq '{repo: .nameWithOwner, default: .defaultBranchRef.name}'
#```

これで「現在のブランチ / 作業ツリーの状態 / gh CLIの認証状態 / リポジトリ名」が一度に揃う。

#### 致命的な前提が満たされない場合

- `gh auth status` が認証エラー → 「`gh auth login` で認証してから再度実行してください」と伝えて終了。
- `gh repo view` が失敗(GitHubリポジトリでない、ghコマンドがない等) → その旨を伝えて終了。
- 現在のブランチがmain/masterなどデフォルトブランチ → 「デフォルトブランチにはPRが紐づきません。featureブランチに切り替えてください」と伝えて終了。

#### 未コミット変更がある場合

`git status --short` で出力がある場合、Copilotの指摘を反映する前から作業ツリーに変更が残っている状態である。次のように案内する:

#```
作業ツリーに未コミットの変更があります:
- `path/to/file.ts`
- ...

このまま本スキルでさらに修正を加えると、Copilot対応の変更と既存の変更が混ざります。
以下のどちらで進めますか?
1. 一旦中断して既存の変更をコミット/退避してから再実行(推奨)
2. このまま続行する(コミット時にユーザー自身で切り分ける前提)
#```

ユーザーが「続行」を選んだ場合のみStep 2へ進む。

### Step 2: 現在のブランチに紐づくPR番号の特定

#```bash
gh pr view --json number,title,url,headRefName,baseRefName,state
#```

このコマンドは現在チェックアウトしているブランチに紐づくPRを返す。返ってきた情報を以下のフォーマットでユーザーに提示する:

#```
## 対象PRを特定しました

- ブランチ: `feat/xxx`
- PR: #123 [タイトル]
- URL: https://github.com/owner/repo/pull/123
- 状態: OPEN / DRAFT / MERGED / CLOSED

このPRのCopilotレビューを処理します。
#```

#### PRが見つからない場合

`gh pr view` が `no pull requests found` で失敗した場合:

#```
このブランチ `feat/xxx` に紐づくPullRequestが見つかりませんでした。

考えられる原因:
- まだPRを作成していない(`/draft-pr` でPRを作成してから再実行してください)
- ブランチ名が一致するPRがない
- リモートへpushされていない

このまま終了します。
#```

#### PRがCLOSED / MERGEDの場合

確認を取る:

#```
このPRは既に <CLOSED|MERGED> 状態です。それでもCopilotレビューを処理しますか?
通常、MERGED後のレビュー対応は不要です。
#```

ユーザーが続行を選ばない限り終了する。

### Step 3: Copilotの未解決レビューコメントを取得

PRの **レビュースレッド** をGraphQLで取得する。`pulls/:number/comments` のRESTエンドポイントでは `isResolved` を取得できないため、GraphQLを使う。

#```bash
gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
  repository(owner: $owner, name: $repo) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes {
          id
          isResolved
          isOutdated
          path
          line
          startLine
          originalLine
          comments(first: 20) {
            nodes {
              databaseId
              author { login }
              body
              path
              line
              startLine
              diffHunk
              url
              createdAt
            }
          }
        }
      }
    }
  }
}' -F owner=<owner> -F repo=<repo> -F number=<pr-number>
#```

`<owner>` `<repo>` はStep 1の `gh repo view` 結果から、`<pr-number>` はStep 2の結果から取る。

#### フィルタリングの方針

返ってきたスレッドから以下の条件で絞り込む:

- `isResolved == false` のスレッドのみ
- スレッド内の最初のコメント `author.login` が **`copilot-pull-request-reviewer`** または **`copilot-pull-request-reviewer[bot]`** で始まるもの(GitHub Copilotコードレビューのbotアカウント)

`isOutdated == true`(コメント以降にコードが変更されて行番号が古い)のものは「Outdated」として明示しつつ処理対象に含める。Outdatedでも指摘の本質は有効なことが多いため、勝手にスキップしない。

#### 該当コメントが0件の場合

#```
このPRには未解決のCopilotレビューコメントはありませんでした。

(参考)
- Copilotレビュー総コメント数: N件
- うち解決済み: M件
- うちCopilot以外のレビュアー: K件

対応すべき指摘がないため終了します。
#```

### Step 4: 未解決コメントの俯瞰を提示

処理対象のスレッドが1件以上ある場合、まず全体像をユーザーに提示する:

#```
## 未解決のCopilotレビューコメント

N件の未解決指摘があります。1件ずつ確認していきます。

| # | ファイル | 行 | 概要 | Outdated |
|---|---------|----|----|----------|
| 1 | `src/foo.ts` | 42 | 〜の境界チェック漏れの指摘 | - |
| 2 | `src/bar.ts` | 88-95 | 〜のループ条件についての提案 | ⚠ |
| 3 | `README.md` | 12 | 〜の表記揺れ修正 | - |
| ... |

進めてよろしいですか? OKであれば1件目から処理を開始します。
#```

ユーザーOKでStep 5へ。

### Step 5: コメント1件ずつの精査ループ

`N` 件のコメントに対して、以下のサイクルを **1件ずつ順番に** 回す。複数件をまとめて処理しない。

#### 5-1. 該当コードの読み込み

スレッドの `path` と `line` / `startLine` を使って、対象ファイルの該当箇所と前後の文脈(前後10〜20行程度)を `Read` ツールで読む。複数行コメント(`startLine` ≠ `line`)の場合はその範囲をすべてカバーする。

Outdatedの場合は、コメント時点の `diffHunk` を見つつ、現状のファイル内容も読む。「Copilotが見ていた時点 → 現在」のズレが評価の鍵になる。

#### 5-2. コメント内容と評価をユーザーに提示

以下のフォーマットで提示する:

#```
## コメント i/N

**ファイル**: `<path>` の <line> 行目 <Outdatedなら "(⚠ Outdated)">
**コメントURL**: <url>

### Copilotの指摘
> <body — 改行は引用ブロックに保ったまま貼る>

### 該当箇所(現状)
#```<lang>
<path>:<startLine>-<endLine>
<前後コンテキスト込みのコード>
#```

### Claudeの評価
<以下のいずれかの観点を、具体的な根拠とともに述べる:>
- **指摘は妥当**: <なぜ妥当か。修正案の概略>
- **指摘は的外れ/不要**: <なぜ不要か。文脈・既存設計・他箇所での処理など>
- **判断保留**: <情報不足、設計判断が必要、副作用が大きいなど、ユーザーの意思決定が必要な理由>

### 提案する修正(指摘が妥当な場合)
<具体的にどう書き換えるかの提示。短ければインラインdiff、長ければ「<関数名> の <処理> を <方針> に変更」>

---

このコメントをどう扱いますか?
- **適用**: Claudeが提案した修正を作業ツリーに反映
- **スキップ**: 何もせず次のコメントへ
- **さらに議論**: 修正方針を一緒に詰めたい / 別案を相談したい
#```

評価は **判断を押し付けない**。Copilotの指摘でも、コードベース全体の文脈や既存の慣習を踏まえると不要なことはある。Claudeは「自分はこう見える」を根拠付きで提示するに留め、最終判断は必ずユーザーに委ねる。

特に次のような指摘は **的外れ寄り** と判断する傾向が強い:

- 既に他の箇所で実施されているチェックの重複提案
- スタイル上の好みで、リポジトリの既存パターンと矛盾する提案
- パフォーマンス上の懸念だが、対象が明らかにホットパスでない箇所
- 「コメントを追加すべき」系で、コードが自明な場合

逆に次のような指摘は **採用寄り** と判断する傾向が強い:

- nullable/undefined/空配列の境界条件の見落とし
- 例外パス・エラーハンドリングの欠落
- セキュリティ的に明確に問題のあるパターン(SQLi、XSS、認証バイパス等)
- 既存の型定義・スキーマと矛盾する実装

ただし上記はあくまで傾向であり、最終的にはコードと文脈を見て判断する。

#### 5-3. ユーザー判断に応じた処理

**「適用」と回答された場合:**

`Edit` ツールで対象ファイルを修正する。複数ファイルにまたがる修正が必要なら、まずユーザーに「この修正は <他ファイル> にも変更が必要です。一緒に反映してよいですか?」と確認する。修正後、以下のように報告する:

#```
✅ 適用しました
- `<path>` を修正
  - <変更概要(1行)>

次のコメント (i+1/N) に進みます。
#```

**「スキップ」と回答された場合:**

#```
⏭ スキップしました。

理由をメモしておきたい場合はその旨を伝えてください(最終サマリに含めます)。
次のコメント (i+1/N) に進みます。
#```

ユーザーが理由を伝えたら、後のサマリ用にメモしておく。

**「さらに議論」と回答された場合:**

その場でフリーフォームの対話に入る。Claudeは追加のコード調査・関連箇所の検索・別案の提示など、ユーザーの議論に応える。議論が収束したら、ユーザーに改めて「適用 / スキップ」のどちらにするかを確認し、確定してから次のコメントへ進む。

#### 5-4. 中断時の挙動

ユーザーが途中で「ここで一旦止めて」「中断して」と伝えた場合は、その時点までの結果をStep 6のサマリ形式でまとめ、未処理のコメントは「未処理: i件」として残す。作業ツリーは「適用」したものだけが反映された状態のまま、何も巻き戻さない。

### Step 6: 全件処理後のサマリ

すべてのコメントを処理(または中断)した後、以下を出力する:

#```
## Copilotレビュー対応 完了サマリ

PR: #123 [タイトル]
処理結果: 適用 P件 / スキップ Q件 / 議論後適用 R件 / 議論後スキップ S件 / 未処理 T件

### 適用した変更
- コメント 1: `src/foo.ts:42` — <変更概要>
- コメント 3: `src/bar.ts:88` — <変更概要>
- ...

### スキップした指摘
- コメント 2: `README.md:12` — <理由(ユーザーが述べた場合のみ)>
- ...

### 未処理(中断時のみ)
- コメント 7〜N

### 作業ツリーの状態
`git status --short` を実行して現在の変更を表示:
<git status の結果>

### 次のアクション
適用した変更をコミットする場合は `/auto-commit` スキルで分割コミットできます。
PRスレッド上の「Resolve conversation」操作は本スキルでは行っていません。レビュー応答が必要な場合はGitHub上で手動操作してください。
#```

`git status --short` は実行して結果を埋め込む(ユーザーが現在の変更状態を把握しやすくするため)。

## エッジケース

- **Copilotコードレビューを有効化していないリポジトリ**: Step 3の結果でCopilot bot 由来のスレッドが1件も得られない(Step 3末尾の「該当コメントが0件の場合」と同じ)。リポジトリ設定で有効化が必要かもしれない旨を補足してよい。

- **bot名のバリエーション**: Copilotのbot名は将来変わる可能性がある。`author.login` に `copilot` を部分一致で含むbotアカウント(末尾 `[bot]` を含む)を広めに拾ってよい。ただし `copilotxxx` のような無関係なユーザー名が含まれないよう、`login.startsWith("copilot-pull-request-reviewer")` または `login == "copilot[bot]"` 程度に限定する。

- **同一スレッドに複数コメントがある場合**: スレッド内の最初のコメントがCopilotであっても、その後に人間が返信していることがある。本スキルは **スレッド単位** で評価し、スレッドの最初のCopilotコメントを主指摘として、後続コメントは「議論の経過」としてコンテキスト表示する。返信コメント自体を独立した処理対象としない。

- **`isOutdated == true` のコメント**: 上述の通り処理対象に含める。提示時に Outdated バッジを表示し、Claudeの評価で「コメント時点と現状のコードが変わっている」旨を必ず触れる。すでに修正済みで指摘自体が解消されていることもあるため、その場合は「現状のコードでは既に解消済み」と評価しスキップを推奨する。

- **コメント本文が極端に長い場合**: そのまま全文引用する(要約しない)。Copilotの指摘は根拠を含めて読むことに意味があるため、勝手な要約で情報を落とさない。

- **適用しようとした修正が他の箇所と矛盾する場合**: 例えば「null check を追加せよ」という指摘に従うと、別の場所のロジック前提(必ず非nullで来る契約)が崩れる場合。修正適用前にClaudeが気づいたら、「この修正を入れると `<他箇所>` の前提と矛盾する可能性があります」と明示してユーザーに再確認する。

- **複数のコメントが同じ箇所を指摘している場合**: 1件ずつ処理する原則は変えない。ただし2件目以降を提示する際に「1件目で `<行X>` を修正済みです。本コメントは同じ箇所への別観点の指摘です」と前置きを入れる。

- **修正反映時に予期せぬビルド/型エラーを誘発しそうな場合**: Claudeが事前に気づける範囲で警告を出す。「この修正により `<関数>` のシグネチャが変わるため、呼び出し元 N箇所の更新が必要です。同時に反映しますか?」と確認する。

- **PRのレビュースレッド数が極端に多い場合(数十件超)**: 全件処理は時間がかかる旨を事前に伝え、「全件処理 / ファイル単位で絞り込み / 特定のファイルのみ」を選べるようにする。ファイル単位の絞り込みを選んだ場合、対象ファイルパスをユーザーに尋ねてから該当スレッドのみ処理する。

## 振る舞いの原則

- **承認なしに作業ツリーを変更しない**: Edit ツールでの修正は必ずユーザーが「適用」を選んだ後にのみ実行する。Claudeの評価が「妥当」であっても、勝手に修正を入れない。

- **コミット・pushはしない**: 本スキルは作業ツリーへの反映までを担当する。コミットは `/auto-commit`、pushはユーザーの手動操作に委ねる。これは「Copilot対応」「機能実装」「リファクタ」などをまとめてコミットしてしまうのを防ぐため。

- **PR上のスレッドを勝手にResolveしない**: 「Resolve conversation」操作(GraphQLの `resolveReviewThread` mutation)は本スキルでは実行しない。指摘への対応が完了したかどうかの判定はレビュアー側が行うのが本筋であり、被レビュー側が自分でresolveすることは慣習として避けたい。

- **判断を奪わない**: Claudeの評価はあくまで判断材料の提示。「適用すべき」「スキップすべき」と断定的に誘導せず、根拠を述べたうえで「Claudeはこう見ている」のトーンに留める。

- **Copilot以外のレビュアーは対象外**: 人間のレビュアーが残したコメントには本スキルでは触れない。人間とのやり取りは個別に対応する必要があるため、機械的な処理対象にしない。

- **全文引用を厭わない**: Copilotコメント本文・該当コードはケチらず全文を提示する。スクロールの手間より「情報を落として誤判断する」リスクのほうが高い。

- **対話途中で中断されても整合性を保つ**: 適用済みの修正はそのまま残し、未処理を明示する。巻き戻しはしない(やり直したい場合はユーザーが `git restore` で戻す)。

## 参考: なぜスレッド単位で処理するのか

GitHubのレビューコメントはスレッド構造を持つ。Copilotが残した最初のコメントに対して、後から人間が「これは違う、こういう理由でこのままで良い」と返信しているケースもある。スレッド単位で処理することで:

1. **解決状態を正確に扱える**: `isResolved` はスレッド単位の属性。コメント単位では取得できない。
2. **議論の経過を踏まえられる**: 既に人間が反論済みの指摘を、機械的に「採用」してしまう事故を防げる。
3. **PR上のUIと一致する**: GitHub UIでもスレッド単位で表示・解決されるため、ユーザーの認知モデルに合う。

そのため本スキルは `pulls/:number/comments`(コメント単位のRESTエンドポイント)ではなく、GraphQLの `reviewThreads` を使う。

使ってみた

あらかじめプルリクエストを作成し、実行してみました。

Claude Code
/handle-copilot-review

(以下がGithub上での修正提案になります)

SCR-20260511-qcby.png

SCR-20260511-qbuf.png

SCR-20260511-qcvm.png

具体的な修正内容は割愛しますが、期待通りの挙動になりました!
今回は以上になります。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?