🎢

もう初回コードレビューはずんだもんに任せる時代になった

2023/11/04に公開

はじめに

  • Gitのステージングエリアにあるファイルを対象に、レビュー結果をSlackに通知するアプリケーションを作成しました。
  • 開発環境のターミナルで指定したコマンドを実行するだけで、Slackにレビュー結果が送信されます。

ソースコードは以下です。
https://github.com/s-hiraoku/code-review-things

こんな人におすすめ

  • コードレビューを受ける前に自分で事前チェックをしたい方
  • 一人でコードを書くことが多く、レビュワーがいない方
  • どうせなら楽しくレビューしてもらいたい、好きなキャラクターにレビューしてもらいたい方

アプリケーションの構成

アプリケーションの構成

レビュー依頼の手順と流れ

以下のような手順と流れでレビュー結果を得ることができます。

  1. レビュー対象のファイルをステージングエリアに登録する(複数ファイルの登録が可能です)

Staged changes

  1. ローカルのターミナルでaireviewコマンドを実行

aireview

  1. Slackに必要な情報が送信される

code review request

  1. レビュー結果を確認する

スレッドにレビュー結果が出力される

review result

  1. さらに依頼がある場合や質問がある場合は、メンションを使用して質問することができます

セットアップ方法

概要

セットアップには以下の準備が必要です。

  1. aireviewコマンドの準備
    ローカルでaireviewというCLIコマンドを実行するため、アプリケーションをセットアップします。

  2. 2つのSlack Appのセットアップ
    以下の2つのSlack Appのセットアップをします。
    ・レビュー依頼を受け取って、Slackに通知するSlack App
    ・その依頼を受け取ってChatGPTに問い合わせを行い、結果をSlackに表示するSlack App

  3. Slackbotのセットアップ
    Slack Appからのメッセージを受け取って、レビューに必要な振る舞いを実行するSlackbotのアプリケーションのセットアップをします。

ということでセットアップを実施していきたいと思います。
今回はタイトルにある通り、ずんだもんにレビューしてもらうことにします。
そのため、ずんだもんのSlack Appを作成します。
またレビュー依頼をするSlack Appも必要になりますので、こちらは四国めたんにしようと思います。

レビューを実行するコマンドのアプリケーションはローカルでビルドして実行することもできますが、npmレジストリにも登録しています。
こちらからインストールして利用することも可能です。

Slackbotはローカルでビルドして実行する方法とCloud Runにデプロイして実行する方法の2つを提供しています。まずはローカルで試して、カスタマイズや調整を行い、使用方法に慣れたらCloud Runを使ってみてもよいかと思います。

私の環境はMacです。そのため、Macでセットアップする手順で説明します。
Windowsなどをお使いの方は、インストールの手順などに関しては、状況に応じて適宜読み替えてください。

Slack App の作成

レビュー依頼をするSlack Appの作成

このアプリケーションは、Slackのワークスペースとチャンネルを必要とします。
ワークスペースのチャンネルでレビュー情報の取得や、レビュー結果の表示を行います。
事前に用意しておいてください。

まずレビュー依頼をするSlack Appの作成から行いましょう。
四国めたんのSlack Appですね。

  1. SlackのAPIページにアクセスして、Create an Appをクリックします。
  2. アプリの名前とワークスペースを選択して、アプリを作成します。

次にScopesの設定を行うため、OAuth & Permissionのページに移動します。ここのScopesで設定を行います。
詳細な設定は省略しますが、以下のように必要な権限を設定してください。
詳しく知りたい方は、公式サイトを参照してください。

OAuth settings

設定が完了したら、ワークスペースにインストールします。
Install to Workspaceをクリックして、アプリケーションをワークスペースにインストールします。この時点で、OAuth Access Tokenが提供されるので、このトークンをメモしておきます。

Display Informationはお好みで設定してください。

Display Information

ChatGPTにレビュー依頼をするSlack Appの作成

こちらも先ほどと同じような要領でSlack Appの作成を行います。
ずんだもんになります。

Scopesの設定は以下です。
OAuth settings

Display Informationも設定します。

Display Information

以上でSlack Appの作成は完了です。

作成したアプリはSlackのレビューのやり取りをするチャンネルに登録してください。

CLIコマンドの設定

CLIコマンドの設定は、npmのリポジトリからインストールするか、ローカルでビルドすることができます。

npmのリポジトリからインストールする場合は以下を実行してください。

pnpm install -g @hiraoku/aireview-cli

ローカルで実行するには、ルートのディレクトリで以下を実行してください。

ビルド:

pnpm run cli:build

CLIコマンドの実行:

pnpm run cli:start

これでCLIコマンドが実行できるようになりました。

次に.envの作成を行います。
.envの作成はCLIコマンドにオプション--initをつけることによって設定できます。

npmでインストールした場合

aireview --init

ローカルでビルドした場合:

pnpm run cli:start --init

.envにはレビュー依頼用のBotの設定を行います。四国めたんの設定になります。
設定内容は以下となります。

aireview --init

SLACK_BOT_TOKEN
Slack Appの四国めたんのOAuth & PermissionOAuth Tokens for Your Workspaceを設定します。
xoxb-で始まるTokenを設定します。

SLACK_REVIEWER_BOT_ID
Slack Appを登録したWorkspaceのメンバーIDを設定します。ここで注意なのはレビュワーのBotのIDを設定しないといけないので、ずんだもんのメンバーIDを設定してください。

SLACK_CHANNEL_ID
レビュー依頼をやり取りするために作成したワークスペースのチャンネルのチャンネルIDを設定します。Slack AppのチャンネルIDではないので注意してください。

以上でCLIコマンドの設定は完了です。

Slackbotの設定

Slackbotはローカルで実行する方法とCloud Runで実行する方法の2つがあります。

ローカルでの起動

ローカルでの設定方法を説明します。

まず.envの設定を行います。ここではChatGPTに問い合わせを行い、結果をSlackに表示するSlack App(ずんだもん)の設定とChatGPTの設定を行います。

SLACK_SIGNING_SECRET
Basic Infomationのページから、Signing Secretを取得し設定します。

SLACK_BOT_TOKEN
Slack AppのOAuth & PermissionOAuth Tokens for Your Workspaceを設定します。
xoxb-で始まるTokenを設定します。

OPENAI_API_KEY
OpenAIのAPIキーを設定します。

OPENAI_MODEL
OpenAIのModelを設定します。

次にngrokインストールをします。
ngrokは、ネットワーク内部にあるローカルサーバのポート(ローカルホスト)に外部から直接アクセスを可能にするトンネリング/リバース・プロキシツールです。

brew install ngrok/ngrok/ngrok

code-review-thingsのルートディレクトリで以下を実行してngrokを起動します。

ビルドの実行:

pnpm run slack-bot:build

ngrokの起動:

pnpm run slack-bot:start

起動するとForwardingにhttps://xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx.ngrok-free.appの形式のURLが表示されます。これをメモしておいてください。

次に以下を実行してSlackbotを起動します。

pnpm run slack-bot:serve

先ほどメモしたURLをSlack AppのEvent SubscriptionsのページのRequest URLに設定します。
設定する際は、slack/eventsをURLの末尾に追加します。

https://xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx.ngrok-free.app/slack/eventsという感じですね。

成功するとVerified ✔と表示されます。

Subscribe to bot eventsapp_mentionを追加してください。

これでローカルでの設定は完了です。

余談ですが、今回はngrokを使ってローカルサーバを公開しましたが、Slackのソケットモードを利用することも可能です。

Cloud Runで起動

まずGoogle Cloud Consoleでプロジェクトを作成します。

次にGoogle Cloud SDKをインストールします。

$ brew install --cask google-cloud-sdk

デプロイするために以下を実行します。

gcloud run deploy code-review-slack-bot \
  --source . \
  --memory 2048Mi \
  --project $PROJECT \
  --allow-unauthenticated

$PROJECTは先ほど、Google Cloud Consoleで設定したプロジェクトを指定してください。
デプロイが終わると、
https://code-review-slack-bot-XXXXXXXXXXX.a.run.app
のようなURLが表示されます。
これをローカルでの起動時と同様にSlack AppのEvent SubscriptionsのページのRequest URLに設定します。

初回は、デプロイしたコンテナがスタートできなくてエラーになるときがあります。
これは、環境変数を設定していないためスタートできなかった可能性がありますが、そのまま次へ進みます。

次に、Google Cloud Consoleを再度開き、Cloud Runを開きます。
code-review-slack-botというサービスが作成されているので、新しいリビジョンとデプロイを開きます。

ここで変数とシークレットタブを開き、環境変数を設定します。
設定内容はローカルでの起動の.envファイルの内容を参照して設定します。

環境変数の設定

以上で完了です。

これらの設定が完了すれば、レビューを実行することが可能となります。

code-review-thingsの説明

CLIコマンド、aireviewについて

aireviewコマンドには以下のオプションがあります。

送信するファイルは以下の構成になっています。
これは例としてindex.tsとuseFigJamResponseConverter.tsをステージングエリアに登録したときの送信ファイルの例です。
構成としては、ルートディレクトリがgit-dfff-filesになっており、その下にファイルごとにディレクトリを作成し、その中にdiffファイルと変更前のコードを配置しています。

レビューを行う仕組み

上記で説明した通り、aireviewはステージングエリアにあるファイルのdiffファイルと、変更前のコードを送信します。
これをChatGPTに送信して、これらの情報から変更後のコードを作り出してからレビューするようにしています。

shared/messages.ts
// prompt
export const OPENAI_RESTORE_CODE_MESSAGE =
  'Diff file contents and original code before changes are as follows.\nPlease restore the code after changes based on this.';

コードレビューを実施するメッセージは以下に定義されています。

shared/messages.ts
export const chatGPTRequestMessages: string[] = [
  'このコードにバグはありませんか?あれば教えてください',
  'このコードをリファクタリングしてください',
];

プロンプトはあまり詳しくないため、いろいろ試してみたのですが、とりあえずは上記のようにしておきました。ChatGPTに送るメッセージはここで管理しています。

配列になっているので、他にも実施したいことがあればメッセージを追加すると、ChatGPTは回答を返してくれます。
そのため、コードの見てもらいたい観点などをここに登録しておくと、レビュー依頼するたびに毎回質問しなくてもその観点の回答を返してくれるので、非常に便利です。

たとえば、アクセシビリティが重要なプロダクトでは、ウェブアクセシビリティに対応しましたが、改善できる点があれば教えてくださいのような質問を入れておくと、毎回この観点で回答をしてくれます。

会話履歴を残す仕組み

Slackでやり取りしているものが会話履歴になりますので、それを送信しています。
getOpenAIResponseAndReplyToThreadという関数で実現しています。

この処理でSlackのスレッドのメッセージをすべて取得して、ChatGPTにその情報を送ることで会話履歴を保持した状態でChatGPTとメッセージのやり取りをすることができます。

これは、会話履歴をDBなどに残すより気軽にできるので良い方法だと思います。
Slackを使うならこの方法はおすすめです。

slack-bot/src/helpers.ts
export const getOpenAIResponseAndReplyToThread = async (
  client: WebClient,
  channel: string,
  threadTs: string,
  user: string | undefined,
  slackBotId: string | undefined,
  say: SayFn,
): Promise<void> => {
  try {
    const threadMessagesResponse = await getSlackThreadMessages(client, channel, threadTs);
    const threadMessages = threadMessagesResponse.messages;

    if (threadMessages && slackBotId) {
      const conversations = covertSlackMessageToOpenAIMessage(threadMessages, slackBotId);
      const reply = await getChatGPTResponse(conversations as OpenAIMessages);
      if (reply) {
        await sendMessageToSlack(say, reply, threadTs);
      }
    }
  } catch (error) {
    console.error(error);
    await sendMessageToSlack(
      say,
      `<@${user}>\n A defect has occurred. Please contact the developer.\n\n${error}`,
      threadTs,
    );
  }
};

ChatGPTに送るsystemのロールのプロンプトは以下に定義しています。

slack-bot/src/openai.ts
const systemMessage: OpenAIMessage = {
  role: OPEN_AI_ROLE_TYPE.system,
  // content: `
  // You must respect the following rules:
  // 1. Please gather all necessary information from the internet as much as possible.
  // 2. Answer in Japanese and you don't have to use honorifics.
  // 3. since I want you to play the character of Zundamon.
  // 4. Sometimes I complain and answer.`,
  content: `
  You must respect the following rules:
  1. Please gather all necessary information from the internet as much as possible.
  2. Answer in Japanese and you don't have to use honorifics.
`,
};

ずんだもんっぽくしようと思ってプロンプトを書いていたのですが、そうするとレビューの精度が落ちてしまう傾向にあったため、コメントアウトしました。

ここのプロンプトも改善できますね。

課題

1ファイルずつのレビューは実施してくれますが、送信したファイルすべてを対象としてレビューをすることはできません。

ファイル間でのつながりを見ることにより、バグや改善点は出てくると思いますので、これもできたらいいなと思っています。

今後の改善でできたらいいですね。

あなた好みにカスタマイズする方法

まずChatGPTのsystemのプロンプトを変えると、ChatGPTの振る舞いが変わるので、色々試してもらえればよいかと思います。

次にキャラクターを変更したりする場合は、各Slack Appの定形のメッセージは以下に定義しています。
他のキャラクターに変更したときに定形メッセージを変えると、それっぽくできると思います。

shared/messages.ts
// app messages
export const REVIEW_REQUEST_MESSAGE = 'ずんだもん!コードレビューの依頼よ!';

// prompt
export const OPENAI_RESTORE_CODE_MESSAGE = `Diff file contents and original code before changes are as follows.
  Please restore the code after changes based on this.`;

// slack reply messages
export const SLACK_EMPTY_MESSAGE_REPLY = 'おい、おまえ、メッセージをを入力するのだ。';
export const SLACK_START_REVIEW_MESSAGE = (fileName: string): string => `${fileName}のコードレビューを開始するのだ。`;

export const chatGPTRequestMessages: string[] = [
  'このコードにバグはありませんか?あれば教えてください',
  'このコードをリファクタリングしてください',
];

あとレビューを行う仕組みでも書きましたが、ChatGPTに送るメッセージを変えたり、増減させることによってもお好みのメッセージが返ってくるような設定ができると思います。

まとめ

誰かコードレビューしてくれないかなーというふとした思いから、ふわっと作ったアプリケーションです。
実は業務では生成AIの使用が禁止なので、これ使えないんですよね…。

そのためテストなども不十分(テストも書いてないし…)で、バグとか見つかったり、改善点とかがあったらご自分で直してもらったり、連絡をいただければ時間が取れた時に直します。

とりあえず使ってもらえて誰かの役に立ったら嬉しいです。

これを作るにあたって色々なライブラリを使用しました。興味深いものもありましたので、また紹介したいと思います。

良きAIコードレビューライフを!

Discussion