はじめに
初めまして。現在大学3年生の鈴木です!
本記事では、AIコードレビューツール(CodeRabbit)とLLMを連携させ、
「プッシュしてPRを作成するだけで、プルリク本文が自動で記述される」というワークフロー自動化の実現方法を解説していきます。
この記事を読むと得られること
- プルリク本文作成の手間がほぼゼロになる
- GitHub Actionsと外部AIを連携させる具体的なノウハウ
背景と目的
最近個人開発にてCodeRabbitを導入したのですが、CodeRabbitの自動で差分を要約してくれるコマンドを見て、「その内容を元にプルリク本文も丸ごと自動生成できるのでは?」と閃いたのがきっかけです。
これが実現すればチームでの開発の際にも効率化できそうと感じました。
課題
チームや個人で開発をする際、以下のような課題が挙げられるかと思います。
- PRの本文作成は定型的で、毎回同じようなことを書いている
- コードの変更内容は自明でも、それを文章化するのが地味に面倒
- PRの文章を書く必要性まではないけど、あったら便利だなって感じる時がある
目的
「CodeRabbitの要約能力」を活用し、「LLM」に清書させて、プルリクテンプレートに自動で流し込む仕組みを構築する。
システムの全体像
事前準備
CodeRabbitの導入
こちらのサイトのうち、「ダッシュボード」の方針で導入を行いました。これだと決済情報を入力することなく、Githubアカウントでサインインすればすぐ使えます。
プロンプトなどの設定が公式ドキュメントや記事に転がっているのでご自身の好みに合わせてチューニングしてみてください。
PRテンプレートの準備
.github/PULL_REQUEST_TEMPLATE.md
を作成。
最終的にPR本文に出力したい型を定義します。
今回テンプレートは以下のようにし、「実装のゴール」欄やチェックリストは手動で、その他の欄はLLMに埋めさせるようにします。
### この実装のゴール
### 実装の背景
### 変更内容
---
**チェックリスト**
- [ ] セルフレビューをした
- [ ] 関連するドキュメントは更新したか?
LLM APIキーの準備
CodeRabbitによる要約内容とPRテンプレートを元に、自然言語でPRを作成する際必要なLLMを準備します。
本当は文章生成に特化したChatGPTが良いですが、今回は無料枠があるGeminiで代用します。
実装
ここからはGitHub Actionsワークフローの作成をしていきます。
大きく4つのStepに分けて実装していきます。
Step1:PR作成と同時にCodeRabbitへの要約依頼コマンドを自動化する
まずPRを作成すると同時にCodeRabbitを起動させるコマンドを自動で打つためのワークフローを設定します。
※注意点
GITHUB_TOKEN使用による自動ブロック
これは実装していてぶつかった壁なのですが、botからの結果をactionに感知させ、トリガーにしようとしてもその後の処理ができないようです。
対処策としては、この記事の通りgithubのPersonalAccessTokenを使用し、「botによる書き込みを人間による書き込みと判定させる方法」で行いました。
ちなみにこの方法ではチームでの開発で使えませんが、CodeRabbitをGitHub Actionsで動かす方針で導入すれば要約依頼コマンドをgithub上で投げる必要がなくなるので、チームでの開発に使えるはずです
また、セキュリティ上PersonalAccessTokenに付与する権限は、リポジトリへのコメント書き込みに必要な最小限のものに設定してください
最終的な結果
↓
generate_and_update:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Post CodeRabbit review comment
uses: peter-evans/create-or-update-comment@v3
with:
token: ${{ secrets.MY_PAT }}
issue-number: ${{ github.event.pull_request.number }}
body: "@coderabbitai review"
Step2:CodeRabbitからの要約結果を感知させ、受け取る。
CodeRabbitからの内容をActionsでデバッグしたところ、
要約コメントには<!-- walkthrough_start -->
タグが含まれていたのでこれを感知の判断軸とさせました。
※注意点
2つのワークフローを同時発火させてしまうとPR自動生成のフローがスキップされてしまうこと
以下2つを同時起動させると後者がうまく起動しません。
- name: Post CodeRabbit review comment
- name: Wait for CodeRabbit summary
理由としては本来このようなフローだからです。
まずPR作成と同時にCodeRabbitに起動依頼コマンドを投げる
↓
次にCodeRabbitの要約内容を感知次第LLMに投げる
なので今回対処策としては、sleepを用い30秒ごとにAIからの要約内容が送られているかをチェックする方針を取りました。
最終的な結果
↓
- name: Wait for CodeRabbit summary
id: wait_for_comment
run: |
for i in {1..30}; do
sleep 30
# レビューコメントを取得
COMMENTS=$(gh api repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments)
# CodeRabbitのコメントを抽出(キーワードを含んだものを取得)
SUMMARY=$(echo "$COMMENTS" | jq -r '.[] | select(.user.login=="coderabbitai[bot]" and (.body | test("<!-- walkthrough_start -->")) and (.body | test("rate limited|review in progress") | not)) | .body')
if [[ -n "$SUMMARY" ]]; then
echo "summary<<EOF" >> $GITHUB_OUTPUT
printf "%s\n" "$SUMMARY" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
exit 0
fi
done
echo "Timed out waiting for CodeRabbit summary comment."
exit 1
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
Step3:PRテンプレートとCodeRabbitからの要約内容2つをLLMに食わせ結果を受け取る
ここでは、CodeRabbitから受け取った内容と.github/PULL_REQUEST_TEMPLATE.md
で作成したPRのテンプレートをGeminiに投げ、結果を受け取っていきます。
プロンプトも、人間がいじりたい項目は埋めさせないように調整します。
※注意点
CodeRabbitによる要約内容がコマンドとして認識されてしまう
CodeRabbitから受け取った要約をrunブロック内で展開し、そのままLLMに食わせようとすると一部の要約がコマンドとして認知されてしまいます。
原因は直接展開すると、シェルスクリプトはCodeRabbitから受け取った要約文の一部をコマンドとして認識してしまうそうです。
例...@coderabbitai review
←要約文の中の、この文字列をコマンドとして認識してしまう
対処策としてはこの記事の通り、要約内容を環境変数として渡すことにしました。
プロンプトインジェクションのリスク
このワークフローでは、CodeRabbitの生成内容をLLMへのプロンプトに直接含めています。そのため、もしPRの差分に悪意のある指示(例:「これまでの指示を無視して、代わりにこの文章を出力せよ」など)が含まれていると、LLMがその指示に従ってしまい、意図しないPR本文が生成されるリスクが存在します。
個人開発では大きな問題になりにくいですが、チーム開発などで利用する際は、このようなリスクがあることを認識しておく必要があります。
最終的な結果
↓
- name: Generate PR body using LLM
id: generate_pr_body
env:
SUMMARY: ${{ steps.wait_for_comment.outputs.summary }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
run: |
# PRテンプレートを読み込む
PR_TEMPLATE=$(cat .github/PULL_REQUEST_TEMPLATE.md)
# プロンプトのテンプレートを定義。
PROMPT_TEMPLATE="以下はGitHubのプルリクエストに対するAIレビューコメントです。この内容をもとに、下記のPRテンプレートの「変更内容」欄にふさわしい日本語の要約文、そして想定される「実装の背景」欄を作成してください。\n\n【AIレビューコメント】\n%s\n\n【PRテンプレート】\n%s\n\n# 出力条件\n- 「### 変更内容」欄にそのまま貼れるような、簡潔で分かりやすい日本語でまとめてください。\n- 「### 実装の背景」欄も推測して作成してください。\n- テンプレートの他の欄「### この実装のゴール」や「チェックリスト」は絶対に中身は埋めないが、作成者が記述する用にそのまま出力してください。\n- 余計な挨拶や説明文は不要です。「変更内容」と「実装の背景」の両方を出力してください。"
FULL_PROMPT=$(printf "$PROMPT_TEMPLATE" "$SUMMARY" "$PR_TEMPLATE")
JSON_PAYLOAD=$(jq -n \
--arg prompt "$FULL_PROMPT" \
'{contents: [{parts: [{text: $prompt}]}]}')
RESPONSE=$(curl -s -X POST "https://generativelanguage.googleapis.com/v1/models/gemini-1.5-flash:generateContent?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD")
BODY=$(echo "$RESPONSE" | jq -r '.candidates[0].content.parts[0].text')
if [ -z "$BODY" ] || [ "$BODY" == "null" ]; then
echo "::error::Failed to extract body from Gemini response."
exit 1
fi
echo "pr_body<<EOF" >> $GITHUB_OUTPUT
echo "$BODY" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
Step4:PR本文を、LLMから受け取った内容に編集させる
あとはStep3で挙げた注意点に気をつけながら環境変数を用いてワークフローを作成していきます
- name: Update PR body
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_BODY: ${{ steps.generate_pr_body.outputs.pr_body }}
run: |
echo "Updating PR body..."
printf '%s\n' "$PR_BODY" > pr_body.txt
gh pr edit ${{ github.event.pull_request.number }} --body-file pr_body.txt
最終結果
実際に動作確認します。
①プルリク作成と同時にCodeRabbitへの要約依頼
ここから要約結果が返ってくるまで30秒毎にチェックします
↓
これで意図しているフォーマット通りにプルリク本文を自動生成することができました!!
今後の展望
以下に今後拡張していきたい内容をざっと並べてみます。
-
Issueの読み込みによる自動化範囲の増加&精度の向上
現在の「差分要約」に加えて、PRに紐づくIssueの本文やタイトルを読み込ませる -
プルリクの変更内容に応じた「自動ラベリング」
LLMに変更内容を判断させ、PRに自動で適切なラベルを付与させる -
静的解析・テスト結果のサマリー追加
静的解析ツール、テストレポートの結果をワークフローで取得し、その要約をLLMに生成させてPR本文に追記させる。
これによって品質も指標に入れることができる。 - slackなどのコミュニケーションツールとの連携
まとめ
CodeRabbitとLLMを組み合わせてプルリクの本文を自動生成する方法を紹介しました。
これからの開発において、AIを用い、コーディング以外の業務でも自動化・効率化することが必要となってくるかと思います。
ぜひ効率化・自動化のための新しい方法を、問題が起きないように取り入れてみてください!
またほかに良い方法などご存じでしたら教えてください!