🗣️

Renovate 対応を自動化する Devin x GitHub Actions【ソースコード付き】

に公開

こんにちは。
株式会社キカガクの @tetsuro_b です。

弊社ではパッケージの脆弱性管理ツールとして Renovate を採用しています。

が、更新の内容によっては build や lint で CI が落ちてしまうケースもしばしばです。
その場合、これまでは以下のような対応をとっており地味に大変な日常業務のひとつでした。

  1. PR の CI でエラー内容確認
  2. PR からどのパッケージがどんな内容で変更されたのか読み解き
  3. 対応方針検討
  4. 対応実施

本記事では この部分を Devin に丸投げして対応してもらう ための GitHub Actions を作った(Devin が)ので紹介します。

Renovate とは

Renovate は、プロジェクトの依存関係を自動的に最新版に更新してくれるツールです。
GitHub App としてリポジトリにインストールして利用します。

https://github.com/renovatebot/renovate

なぜ Devin を使うのか

一番の理由は Renovate によって作成されるパッケージの diff がわかる Web ページを直接確認できるからです。

Renovate により PR が作成されると更新されたパッケージの内容に応じて以下のような URL が生成されます

https://app.renovatebot.com/package-diff?name=react&from=19.0.0&to=19.1.0

例えば上記の URL にアクセスすると React v19.0.0 ~ v19.1.0 の差分を確認できます。

Renovate の PR で CI が落ちるようになるということは更新されたパッケージの何かしらの変更が原因であることが多いため、Devin に対応前に変更内容を確認してもらうことでより解決の精度が上がることを期待し Devin を使ってみることにしました。

GitHub Actions ソースコード

以下のコードをコピペして .github/workflows/renovate-ci-failure.yaml などに入れると Devin に丸投げできる GitHub Actions の完成です。

GitHub Actions のソースコード(クリックして開く)

以下の GitHub Actions のソースコードはほぼ Devin が作ってくれたものなのでリファクタしたほうが良い箇所などもあるかもしれません。
ご自身のリポジトリなどに導入する際は、念のためコードをご確認いただき導入することをおすすめします。

name: '[Renovate] CI Failure - Devin Review'

on:
  workflow_run:
    workflows:
      - {ここに失敗をトリガーにしたい Actions 名を記載}
      - 例)'check build'
    types: [completed]

permissions:
  pull-requests: write
  issues: write
  actions: read

jobs:
  request_devin_review:
    runs-on: ubuntu-latest
    if: >
      github.event.workflow_run.conclusion == 'failure' &&
      github.event.workflow_run.event == 'pull_request'
    steps:
      - name: Get PR information
        id: pr_info
        uses: actions/github-script@v7
        with:
          script: |
            const branchName = context.payload.workflow_run?.head_branch || context.ref.replace('refs/heads/', '');

            const { data: pullRequests } = await github.rest.pulls.list({
              owner: context.repo.owner,
              repo: context.repo.repo,
              head: `${context.repo.owner}:${branchName}`,
              state: 'open'
            });

            if (pullRequests.length === 0) {
              core.setFailed('No open PR found for this branch');
              return;
            }

            const pr = pullRequests[0];
            const hasRenovateLabel = pr.labels.some(label => label.name === 'renovate');
            const hasDevinProcessedLabel = pr.labels.some(label => label.name === 'devin-processed');

            core.setOutput('pr_number', pr.number);
            core.setOutput('pr_url', pr.html_url);
            core.setOutput('pr_title', pr.title);
            core.setOutput('pr_body', pr.body || '');
            core.setOutput('has_renovate_label', hasRenovateLabel);
            core.setOutput('has_devin_processed_label', hasDevinProcessedLabel);
            core.setOutput('is_draft', pr.draft);

      - name: Request Devin Code Review
        if: >
          steps.pr_info.outputs.has_renovate_label == 'true' &&
          steps.pr_info.outputs.is_draft == 'false' &&
          steps.pr_info.outputs.has_devin_processed_label == 'false'
        env:
          DEVIN_API_KEY: ${{ secrets.DEVIN_API_KEY }}
          PR_URL: ${{ steps.pr_info.outputs.pr_url }}
          PR_TITLE: ${{ steps.pr_info.outputs.pr_title }}
          PR_BODY: ${{ steps.pr_info.outputs.pr_body }}
          FAILED_WORKFLOW: ${{ github.event.workflow_run.name }}
        run: |
          # プロンプトを定義
          PROMPT="renovateラベル付きPRでCI「${FAILED_WORKFLOW}」が失敗しました。以下の手順で対応してください:

          1. PRの概要欄を取得し「This PR contains the following updates:」セクションからrenovateで更新されたバージョンへのリンク(例:https://app.renovatebot.com/package-diff?name=eslint-config-next&from=xxx&to=xxx)を開く
          ※ PR に複数の更新リンクが有るケースもあるのですべてのリンクを閲覧する

          2. 失敗したActionsと同等のコマンドを package.json から探しローカルで動かしエラー内容を確認

          3. バージョン差分情報を参考にエラーを修正(同じ修正が多くのファイルに必要な場合はコマンドなどを用い一括置換を検討)

          4. PRへ変更内容をpush

          5. CI失敗時は再調査(2回以上失敗したら停止)

          6. CIを2回以上失敗した場合、もしくは正常に CI が完了した場合には「renovateで更新された内容/Devinの修正内容/Devinの修正意図」を PR にコメントすること

          PR: ${PR_URL}"

          # jqを使ってJSONを生成
          JSON_PAYLOAD=$(jq -n --arg prompt "$PROMPT" '{prompt: $prompt}')

          curl -X POST "https://api.devin.ai/v1/sessions" \
               -H "Authorization: Bearer $DEVIN_API_KEY" \
               -H "Content-Type: application/json" \
               -d "$JSON_PAYLOAD"

      - name: Add devin-processed label
        if: >
          steps.pr_info.outputs.has_renovate_label == 'true' &&
          steps.pr_info.outputs.is_draft == 'false' &&
          steps.pr_info.outputs.has_devin_processed_label == 'false'
        uses: actions/github-script@v7
        with:
          script: |
            const pr_number = ${{ steps.pr_info.outputs.pr_number }};
            await github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: pr_number,
              labels: ['devin-processed']
            });

今回作成した GitHub Actions をフロー図にするとざっくり以下のとおりです。

実際に CI 落ちた PR を修正できるのか

まだわずかな期間でしか運用できてはいないですが、思いのほか修正してくれます!!
※ ただし毎回完璧にこなしてくれるわけではなく、修正してくれた結果その修正とは別の修正や追加の修正を人間がいれることもあります。

今回の肝となるのは Devin に依頼するプロンプトです。
以下に GitHub Actions のソースコードからプロンプト部分を抜き出します。

1. PRの概要欄を取得し「This PR contains the following updates:」セクションからRenovate で更新されたバージョンへのリンク(例:https://app.renovatebot.com/package-diff?name=xxx&from=xxx&to=xxx)を開く
※ PR に複数の更新リンクが有るケースもあるのですべてのリンクを閲覧する
2. 失敗したActionsと同等のコマンドを package.json から探しローカルで動かしエラー内容を確認
3. バージョン差分情報を参考にエラーを修正(同じ修正が多くのファイルに必要な場合はコマンドなどを用い一括置換を検討)
4. PRへ変更内容をpush
5. CI失敗時は再調査(2回以上失敗したら停止)
6. CIを2回以上失敗した場合、もしくは正常に CI が完了した場合には「 Renovate で更新された内容/Devinの修正内容/Devinの修正意図」を PR にコメントすること

ポイントなる部分を以降で少し説明します。

何のパッケージがどんな変更がされたのかブラウザで確認してもらう

パッケージの変更自体は PR の Files changed を見れば分かりますが、そのパッケージがどんな変更がされたかまではわかりません。

そのため Devin にはまずは PR から Renovate 側で用意されている「パッケージの更新内容がわかるページ」にアクセスしてもらい変更内容を把握してもらうようにしています。
※ Renovate の PR の Change の列がリンク化されているのでそこをクリックすると、パッケージの更新内容(ソースコード)が表示されます。

Devin のコンソールからセッションの様子を観察してみると実際に「パッケージの更新内容がわかるページ」にアクセスして内容を確認していることが分かります。
※ 添付の画像は本ブログ用に React v19.0.0 ~ v19.1.0 の差分をみてもらっているだけで実際に弊社のプロジェクトで更新されたパッケージの内容ではありません。

PR の CI の失敗回数に制限を設ける ( 2 回 )

弊社では Devin のセッションにおける上限 ACU は 5ACU で設定しています。

では CI の回数制限はなんのためかというと、Renovate 対応に 5ACU も使ってほしくないからです😂
※ 5ACU = 約 1,500 円

100 % 毎回完璧な修正をしてくれれば 5ACU の上限でも良いのですが、Renovate の PR には複雑な修正が必要なものや、対応方針を色々調査のうえ決めたいものなど一筋縄ではいかないものも多いです。

そのためそういった PR に対して無駄に ACU を費やしてもらいたく無いので上限を定めています。

CI 回数制限の副産物として、Devin が本気で対応方針を考えてくれたりもします。(効果があるかはわからない。)

Renovate の更新内容/Devin の修正内容/意図をコメントしてもらう

Devin がなぜそういう修正したのか、そもそもどんな内容で package が更新されたのか、それらを総合的に把握してからマージしたいので Devin には対応後に PR にコメントを入れてもらうように指示を入れています。

PR の File Changed だけだとキャッチアップが難しかったり、そもそも Renovate の対応にそこまで脳内のリソースを使いたくないのでこのコメントがあるかないかで全然マージまでのハードルが変わってくるのでおすすめです。

Actions 実行後は 「devin-processed」 ラベルを付与

これは工夫というよりも Devin の重複実行を防止するためのものです。
例えばこのラベルをいれる仕組みがないと以下のように無限に Devin が呼び出される可能性があります。

  1. CI が落ちる
  2. Devin のセッションが起動
  3. Devin が修正内容を push
  4. CI が落ちる ~~ 以降 2-4 のループ都度新しい Devin が呼びだされる

Devin 呼び出し後に devin-processed ラベルを PR に貼ることで2回目以降に Devin のセッションが新しく起動されないようにしています。

まとめ

Devin は Slack からサクッと指示を出せるのも魅力的ですが Devin API を活用することで、簡単に GitHub Actions などのワークフローに取り込むことができます。
今後もさまざまな場所で Devin にはがんばってもらえるように環境整備していこうと思います。

最後に(宣伝)

わたしの X(Twitter) では AI 活用に関する情報を日々情報発信しております!
フォローいただけたらうれしいです!

→ 株式会社キカガクの採用情報は こちらから

株式会社キカガク

Discussion