GitHub AppとCloud Runを活用した組織向けPR Agent環境構築

# はじめに

[前回の記事](https://qiita.com/hamawata/items/cdf0e212130edae4a307)では、PR Agent導入までのプロセスと導入した感想について記述しました。

この記事では、GitHub Appを活用し、Cloud Run上で動作するPR Agent環境の構築手順を解説します。本記事を読むことで、以下の内容を習得できます。

- GitHub Appを使ったリポジトリ運用の効率化
- Cloud Runを利用したセキュアなデプロイ方法

組織でPR Agentを利用する場合に、リポジトリごとの個別設定を不要にし、全体で統一的に利用可能な環境を目指します。

本記事では、Google Cloudを利用した構築を中心に解説しますが、AWS環境での利用については公式リポジトリをご参照ください。

[PR Agent公式ドキュメント（AWS Lambda版）](https://github.com/Codium-ai/pr-agent/blob/main/docs/docs/installation/github.md#deploy-as-a-lambda-function)


# 全体の流れ

本記事で構築するシステムでは、GitHub AppとCloud Runを活用し、組織全体で効率的にPR Agentを運用できる環境を作ります。そのための手順を大まかに示すと、次のようになります。

1. **GitHub Appの作成と設定**: GitHubリポジトリのイベントを受信するアプリを作成
2. **OpenAIのAPI設定**: PRレビューの生成に使用するAPIキーを取得
3. **Google Cloud環境の構築**: [Terraform](https://www.terraform.io/)を用いて、Cloud Runをデプロイする環境を構築
4. **Webhook設定とアプリインストール**: GitHub AppをWebhook経由でCloud Runと連携

次に、これらの手順に基づくシステム全体の動作イメージを図示します。


# システム全体図

以下の図は、GitHub AppとCloud Runを活用したPR Agentの動作フローを示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27575/4bdd08ce-fcfe-5746-25ea-9a03a29a9dbe.png)


処理の流れは以下の通りです。

1. Pull Request（PR）上で `/review` や `/improve` のコマンドをコメントとして送信
2. GitHub Appに設定されたWebhook URLへイベントを送信
3. Webhookを受け取ったCloud RunのWebサーバーがPRの情報を取得
4. WebサーバーがPRの情報を基にプロンプトを生成し、OpenAIのAPIに送信
5. APIからのレスポンスを基にレビューコメントを作成し、PRにコメントを投稿


# 構築手順


## 前提条件

以下のアカウントや環境が準備されていることを前提とします。

- **GitHubアカウント**: 組織の管理権限が付与されていること
- **OpenAIアカウント**: 支払い情報などが設定されていること
- **Google Cloudアカウント**: アカウントとプロジェクトが作成されていること


## GitHub Appの作成と設定

- GitHub Appの作成ページにアクセス
https://github.com/organizations/{組織アカウントID}/settings/apps/new
- 必要事項を入力して `Create GitHub App` をクリック
   - **GitHub App name**: 任意の名前を入力
   - **Homepage URL**: 任意のURLを入力（例: https://github.com/Codium-ai/pr-agent）
   - **Webhook**: Activeのチェックを外します（Cloud Run構築後に設定）
   - **Permissions**:
     - Repository permissions: `Issues` と `Pull Requests` に `Read and write` を、`Metadata`に`Read-only` 権限を付与
   - **Where can this GitHub App be installed?**: 「Only on this account」を選択
- 作成完了後 https://github.com/organizations/{組織アカウントID}/settings/apps/{アプリ名} にアクセスし、`Generate a private key` から秘密鍵を作成してダウンロード


# Open AIの設定

- [OpenAI APIキー作成ページ](https://platform.openai.com/settings/organization/api-keys)にアクセスし、APIキーを作成
- 必要に応じてクレジットを追加
  - クレジット追加はこちら: [OpenAI Billing Overview](https://platform.openai.com/settings/organization/billing/overview)


# Google Cloudでの環境構築

## Secret Managerにシークレットを追加

[Google Cloud Secret Manager](https://console.cloud.google.com/security/secret-manager)で以下の名前でシークレットを作成

  - `pr-agent-github-private-key`: GitHub Appの秘密鍵
  - `pr-agent-github-webhook-secret`: 任意の推測されづらい文字列を入力
  - `pr-agent-openai-key`: OpenAIで発行したAPIキー

:::note info
セキュリティ上、シークレット値はTerraformで直接扱わず、Google Cloudコンソールで作成したものを参照します。
:::

:::note warn
pr-agent-github-webhook-secretの値は後のGitHub Appの設定で利用します。
値が流出すると、デプロイしたCloud Runを不正利用される恐れがあるので推測されづらい値を指定することが重要です。
:::

## Cloud Runの構築

Terraformを使用してCloud Run環境を構築します。ここは各セクションに分割して要点のみ記述しています。
実際に利用できるtfファイルについては[こちら](https://gist.github.com/hamawata/9d8dd7627cf815b68dbe66eb6abe9b79)を参照してください。

### 1. サービスアカウントの作成

Cloud Runの実行に必要な権限を持つアカウントを作成

```tf
resource "google_service_account" "pr-agent" {
  account_id   = "pr-agent"
  display_name = "PR Agent service account"
  description  = "Managed by Terraform."
}
```

### 2. シークレットへのアクセス権限付与

Secret Managerに格納したAPIキーやWebhookのシークレットを読み取る権限をサービスアカウントに付与

```tf
data "google_secret_manager_secret" "pr-agent-openai-key" {
  secret_id = "pr-agent-openai-key"
}

resource "google_secret_manager_secret_iam_member" "secret-accessor-pr-agent-openai-key" {
  secret_id = data.google_secret_manager_secret.pr-agent-openai-key.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.pr-agent.email}"
}

# 以下、他のシークレットについても設定
```

### 3. Cloud Runサービスの作成

PR Agentが動作する実行環境を作成

```tf
resource "google_cloud_run_v2_service" "pr-agent" {
  name     = "im-pr-agent"
  location = "asia-northeast1"

  template {
    containers {
      name  = "app"
      image = "codiumai/pr-agent:0.24-github_app"
      ports {
        name           = "http1"
        container_port = 3000
      }
      env {
        name  = "OPENAI.KEY"
        value_source {
          secret_key_ref {
            secret  = "pr-agent-openai-key"
            version = "latest"
          }
        }
      }
      # 以下、その他環境変数やprobeの設定を指定
    }

    service_account = google_service_account.pr-agent.email
    timeout         = "300s"
  }
}
```

### 4. Cloud Runの公開設定

GitHubからのWebhookを受け取るためにCloud Runサービスを公開

```tf
resource "google_cloud_run_service_iam_binding" "pr-agent" {
  role    = "roles/run.invoker"
  members = ["allUsers"]
}
```

---

デプロイ完了後、[Cloud Runコンソール](https://console.cloud.google.com/run)からCloud RunのURLを取得します。

:::note info
Cloud Runの環境変数でPR Agentの設定を変更することができます。

設定項目一覧は以下のファイルで確認できるので、動作を変更したい場合は参照してみてください。（環境変数で指定する場合は大文字で指定します）
https://github.com/Codium-ai/pr-agent/blob/v0.24/pr_agent/settings/configuration.toml

:::

## Webhook設定とアプリインストール

- GitHub Appの設定ページ https://github.com/organizations/{組織アカウントID}/settings/apps/{アプリ名} に戻り、Webhook URLを設定
  - **Webhook URL**: `https://{Cloud Runドメイン}/api/v1/github_webhooks`
  - **Secret**: `pr-agent-github-webhook-secret`に設定した値


- AppsのPermissions & events https://github.com/organizations/{組織アカウントID}/settings/apps/{アプリ名}/permissions に移動し必要なイベントを有効化
  - Issues
  - Pull request
  - Issue comment
  - Pull request review
  - Pull request review comment


- GitHub Appの Install App https://github.com/organizations/{組織アカウントID}/settings/apps/{アプリ名}/installations にアクセスして組織アカウントに`Install`

- Installの画面に遷移するので、PR Agentを利用したいリポジトリを選択します


以上の手順で構築完了です！
許可したリポジトリのPRコメントで`/review`などで動作するでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27575/9138598d-49dd-034c-b6ed-e4910439536d.png)


# おわりに

PR Agentを組織で利用するために、GitHub AppとCloud Runにより構築する手順を紹介しました。

引き続き、明日以降のアドベントカレンダーの記事もぜひお楽しみに！

https://qiita.com/advent-calendar/2024/intimatemerger