GitHub ActionsでDependabotプルリクエストを自動承認・自動マージする設定

## はじめに

Dependabotは、依存関係の更新を自動で行ってくれる便利なツールですが、毎回手動でプルリクエストを承認し、マージするのは手間です。そこで、GitHub Actionsを使用して、Dependabotが作成するプルリクエストを自動で承認し、すべてのチェックが成功した後に自動マージする方法を解説します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263492/a0a11315-e27f-d66f-6493-341468245eb7.png)

また、ユニットテストやVercelのチェックやGitGuardianのチェックなどが成功する前にマージされると本番に影響してしまうので、下記のコードでは全部のワークフローが成功してからmergeされるように書いてます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263492/0dedeb3b-5049-5665-b83e-d7eb92fa0702.png)

## 設定ファイルの内容

このプロセスには、主に2つの設定ファイルが関与します。

### 1. `dependabot-auto-approve.yml`

このファイルは、Dependabotによるプルリクエストを自動で承認するためのワークフローです。

```yaml
name: Dependabot auto-approve
on: pull_request

permissions:
  pull-requests: write

jobs:
  dependabot:
    runs-on: ubuntu-latest
    if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'owner/repo'
    steps:
      - name: Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v2.2.0
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"
      - name: Approve a PR
        run: gh pr review --approve "$PR_URL"
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### 2. `dependabot-auto-merge.yml`

このファイルは、すべてのステータスチェックが成功した場合にDependabotによるプルリクエストを自動でマージするためのワークフローです。

```yaml
name: Dependabot auto-merge
on: pull_request

permissions:
  contents: write
  pull-requests: write
  checks: read
  actions: read
  statuses: read

jobs:
  dependabot:
    runs-on: ubuntu-latest
    if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'owner/repo'
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      PR_URL: ${{github.event.pull_request.html_url}}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: SetUp auto-merge
        id: auto-merge
        uses: dependabot/fetch-metadata@v2.2.0
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Wait 5 minutes for other checks to complete
        run: sleep 300
      - name: Check if all workflows have passed
        run: |
          MAX_RETRIES=6
          RETRY_INTERVAL=300  # 5分を秒で指定
          ATTEMPT=0
          CURRENT_WORKFLOW="Dependabot auto-merge"

          while [ $ATTEMPT -lt $MAX_RETRIES ]; do
            echo "Fetching PR status checks..."
            WORKFLOWS=$(gh pr view "$PR_URL" --json statusCheckRollup -q '.statusCheckRollup')

            # デバッグ: 各ステータスチェックの状態を出力
            echo "Debug: Current status of all checks:"
            WORKFLOW_STATUS=$(jq -r '[.[] | {name: (.workflowName // .name // .context), type: .["__typename"], status: .status, state: .state, conclusion: .conclusion}]' <<< "$WORKFLOWS")

            # 現在のワークフロー以外のすべてのチェックが成功したか確認
            all_passed=true
            while IFS= read -r check; do
              name=$(jq -r '.name' <<< "$check")
              type=$(jq -r '.type' <<< "$check")
              status=$(jq -r 'if .type == "CheckRun" then .conclusion else .state end' <<< "$check")
              if [[ "$name" != "$CURRENT_WORKFLOW" && "$status" != "SUCCESS" ]]; then
                all_passed=false
                echo "Failed check: $name ($type) - Status: $status"
                break
              fi
            done < <(echo "$WORKFLOW_STATUS" | jq -c '.[]')

            if $all_passed; then
              echo "All other checks have passed"
              exit 0
            else
              echo "Some status checks have not passed. Attempt $((ATTEMPT + 1)) of $MAX_RETRIES."
              echo "Retrying in $RETRY_INTERVAL seconds..."
              sleep $RETRY_INTERVAL
              ATTEMPT=$((ATTEMPT + 1))
            fi
          done
          echo "Failed to merge the PR after $MAX_RETRIES attempts due to failing status checks."
          exit 1
      - name: Auto-merge for Dependabot PRs
        run: gh pr merge --auto --merge "$PR_URL"

```

## 設定ポイント

### 自動承認 (`dependabot-auto-approve.yml`)
- **イベントのトリガー**: プルリクエストが作成されると自動的にワークフローが実行されます。
- **権限設定**: `permissions` で `pull-requests: write` を指定し、プルリクエストに対する書き込み権限を持たせます。
- **承認処理**: Dependabotが作成したプルリクエストを自動的に承認します。

### 自動マージ (`dependabot-auto-merge.yml`)
- **他のワークフローを待つ**: 初期実行は他のワークフローが走りだしたばっかなので、5分待ってから下記の処理を開始します。
- **ステータスチェックの確認**: ステータスチェックが全て成功するまで最大6回リトライを行い、5分ごとに再試行します。
- **自動マージ処理**: ステータスチェックが全て成功した場合に自動的にマージを行います。

### 注意点
- **依存関係のメタデータ**: `dependabot/fetch-metadata` は最新のバージョンを使用することを推奨します。
- **チェックの結果**: `__typename`によって、成功(SUCESS)を示す項目が異なることに注意が必要です。`CheckRun`の場合は `conclusion` に、`StatusContext`の場合は `state` に結果が格納されてる。
- github.repositoryに自分のアカウント/リポジトリを入れる

## まとめ

このように、GitHub Actionsを利用することで、Dependabotによるプルリクエストを自動で承認し、必要なチェックが成功した後に自動マージすることができます。これにより、開発プロセスをスムーズに進めることができ、手動での介入を減らすことが可能になります。
基本的なDependabotなどの説明は割愛してるので、他の記事を参考に試してみてください！

### 参考資料
https://github.com/dependabot/fetch-metadata
https://docs.github.com/ja/actions/writing-workflows/about-workflows
https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token