ほぼ無料で優秀なレビュアーを1人増やせるツール、Qodo Mergeを試す
TL;DR
- コードレビューをAIに任せられる、Qodo Mergeという無料で簡単に使えるOSSツールがあるよ
- 設定できる項目が多いから使いそうなものを抽出してみたよ
- 筆者は、PRの要約やAIのレビューに対する質問ができる機能ががありがたいなと思ったよ
私たちの研究室
アドベントカレンダー 17日目🎄
Qodo Mergeとは
Qodo Merge(旧 PR-Agent)とは、AIを用いてプルリクエスト(PR)のレビューを効率化するOSSツールです。
Qodo Mergeを使うことで「GitHubでPRを立てれば自動でAIがコードレビューをしてくれる」仕組みを簡単に構築することができます。
無料で使えるQodo Mergeと、月額課金で使えるQodo Merge Proの2種類があり、Pro版では無料版の機能に加えてカスタムプロンプトなどの機能が使えます。
今回は無料版のQodo Mergeを使ってみます。
使ってみる
必要なものはOpenAIのAPIキーのみです。(必要な料金もOpenAIのAPI利用料のみです)
作業自体はInstallationに書いてある通りでとても簡単です。
まず、リポジトリのGithub Actionsの設定のところでOPENAI_KEY
の環境変数を設定します。
次に、リポジトリに.github/workflows/pr_agent.yaml
のファイルを以下の内容で作成し、mainブランチにマージします。
on:
pull_request:
types: [opened, reopened, ready_for_review]
issue_comment:
jobs:
pr_agent_job:
if: ${{ github.event.sender.type != 'Bot' }}
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
contents: write
name: Run pr agent on every pull request, respond to user comments
steps:
- name: PR Agent action step
id: pragent
uses: Codium-ai/pr-agent@main
env:
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# opeanAIのモデル選択
config.model: "o1-preview"
# opeanAIのフォールバックモデル選択
config.fallback_model: "o1-preview-2024-09-12"
# pr_descriptionにおいてPRのタイトルも自動生成する
pr_description.generate_ai_title: true
# pr_descriptionにおける追加プロンプト
pr_description.extra_instructions: "回答は必ず全て日本語で記述してください。"
# pr_reviewにおける追加プロンプト
pr_reviewer.extra_instructions: "回答は必ず全て日本語で記述してください。"
# pr_reviewにおけるPRにスコアを付ける機能を有効化
pr_reviewer.require_score_review: true
# pr_reviewにおけるPRが分割できるかどうかを判断してくれる機能を有効化
pr_reviewer.require_can_be_split_review: true
# pr_improveにおける追加のプロンプト
pr_code_suggestions.extra_instructions: "回答は必ず全て日本語で記述してください。"
# pr_improveにおいて問題点にのみ焦点を当てるか(falseだと可読性や保守性等の指摘が入りやすくなる)
pr_code_suggestions.focus_only_on_problems: false
# pr_improveにおける各提案にGood/Badの評価をつける機能を有効化
pr_code_suggestions.allow_thumbs_up_down: true
# pr_update_changelogにおける追加のプロンプト
pr_update_changelog.extra_instructions: "回答は必ず全て日本語で記述してください。"
コメントが付いている部分の設定は自分なりに機能を有効化したり、日本語対応させたりするために追加したものです。複雑ですがこちらに設定できる全項目が並んでいます。
また、openAIのモデルはここの一覧から選ぶこともできます。
デフォルトのgpt-4o
では何をやっても日本語で返してくれなかったので、ここではo1-preview
を選択してみました。
以上で設定は完了です。
あとはPRを立てれば自動でAIがレビューをしてくれるようになります。
今回はNext.jsのcreate-next-appで最初に作成されるpage.tsxを少し修正したPRを立ててみます。
修正後のコードはChatGPTに「以下を企業のランディングページみたいに少し書き換えて」と修正前のコードを添えて作ってもらいました。
ヘッダー要素がや仮の企業情報が追加され、その他CSSや文言も少し修正されたみたいです。
修正前のコード
import Image from "next/image";
export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
src/app/page.tsx
</code>
.
</li>
<li>Save and see your changes instantly.</li>
</ol>
<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
/>
Deploy now
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
</div>
</main>
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
/>
Learn
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Examples
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to nextjs.org →
</a>
</footer>
</div>
);
}
修正後のコード
import Image from "next/image";
export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<header className="flex flex-col items-center gap-4">
<Image
className="dark:invert"
src="/next.svg"
alt="Company logo"
width={200}
height={50}
priority
/>
<h1 className="text-3xl font-bold text-center sm:text-left">Innovate with Confidence</h1>
<p className="text-center sm:text-left text-gray-600 dark:text-gray-400 max-w-2xl">
Empowering businesses with cutting-edge solutions and seamless deployment. Discover the tools to bring your ideas to life.
</p>
</header>
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<section className="flex flex-col items-center gap-8 sm:items-start">
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2">
Start by exploring our resources and tools to accelerate your journey.
</li>
<li>Join a global community of innovators and creators.</li>
</ol>
<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-blue-600 text-white hover:bg-blue-700 text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Deploy Icon"
width={20}
height={20}
/>
Get Started
</a>
<a
className="rounded-full border border-solid border-gray-300 dark:border-gray-600 transition-colors flex items-center justify-center hover:bg-gray-100 dark:hover:bg-gray-800 text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Learn More
</a>
</div>
</section>
{/* Company Info Section */}
<section className="flex flex-col gap-4 max-w-2xl">
<h2 className="text-2xl font-bold">About Our Company</h2>
<p className="text-gray-600 dark:text-gray-400">
We are a technology company dedicated to empowering businesses worldwide with innovative solutions. Our mission is to bridge the gap between vision and execution through cutting-edge tools and platforms.
</p>
<ul className="text-sm text-gray-600 dark:text-gray-400">
<li><strong>Founded:</strong> 2015</li>
<li><strong>Headquarters:</strong> San Francisco, CA</li>
<li><strong>Our Mission:</strong> Innovating to create a seamless digital future for businesses.</li>
</ul>
</section>
</main>
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
/>
Tutorials
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Templates
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Visit Next.js →
</a>
</footer>
</div>
);
}
PRを立てると、GitHub Actionsが動き出します。
1,2分経つとPRがどんどん華やかに更新されていきます。
以下に詳細をまとめます。
Describe
DescribeはPRを要約してくれる機能です。
以下のようなことをやってくれました。
- PRタイトルの自動付与
- PR種別の自動判別
- 差分の要約
Review
ReviewはPRのレビューを実際にやってくれるというよりは、レビューをするための考慮点などをまとめてくれる機能です。
以下のようなことをやってくれました。
- レビューに掛かる労力の見積もり
- PRに対する点数を付ける(100点満点っぽい?)
- セキュリティ上の懸念があるかの判断
- どこにフォーカスを当ててレビューすべきかの助言
Improve
ImproveはPRのレビューを実際にやってくれる機能です。
人間の目では見落とす可能性がある細かい点まで指摘してくれていますね。
Ask
AskはAIが行ったPRのレビューに関して質問できる機能です。
/ask "[質問内容]"
とコメントすると質問に回答してくれます。
Update Changelog
Update Changelogはchangelogを作成してくれる機能です。
/update_changelog
とコメントするとchangelogを作成してくれます。リリース時に便利ですね。
感想
思った以上にできることが多くてビックリしました。カスタマイズ性も高く、そして何より簡単で使いやすい。本当に開発人員が1人増えたみたいです。
普段はPRを立てるときは自分で伝わりやすくするように要約していたので、要約してくれる機能は大変有難いと思いました。(PRテンプレートを使わなくなるかも)
また、PRコメントの意図がどうしても分からず質問したくなることもありますが、この点もAskという機能で考慮されているところも素晴らしいと思います。
Discussion