【GitHub Actions + CI/CD】AIがワークフローエラーの解決方法を教えてくれる仕組みを作ってみた

# はじめに
GitHub ActionsでCI/CDを実現できるようになった今、pushする度にワークフローがエラーとなることが多々あります。
エラーが起きる度に原因を調べたり、AIに聞いたりしていたのですが、段々と面倒になってると感じていました。
そこで、GitHub Actionsの`ai-inference`を使用して、エラーの原因と解消方法を自動で教えてもらうことはできないかと考え、AIと相談しながら実際に作成してみました。

https://github.com/actions/ai-inference

# 作成したワークフロー

CI/CDワークフロー（test-deploy.yml）が失敗した際に、エラーログを取得し、AIが自動で解析、ジョブの概要欄にて原因と解決方法を表示してくれます。

https://github.com/asa129/addiless-alcohol-app/actions/workflows/ai-failure-check.yml

<details><summary><b>ai-failure-check.yml</b></summary>

```yml:ai-failure-check.yml
name: AI Failure check

on:
  workflow_run:
    workflows: "Test and Deploy"
    types:
      - completed

jobs:
  on-success:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      - name: success
        run: |
          echo "trigger build workflow success"
  on-failure:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'failure' }}
    permissions:
      actions: read
      contents: read
      models: read
    steps:
      - name: failure
        run: |
          echo "trigger build workflow failed"

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Get error info
        id: get-error
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          echo "::error::ワークフロー失敗"
          echo "branch: ${{ github.event.workflow_run.head_branch }}"

          # ワークフローの実行IDを取得
          RUN_ID=${{ github.event.workflow_run.id }}
          echo "RUN_ID: $RUN_ID"

          # ワークフロー情報を環境変数に保存
          echo "WORKFLOW_NAME=${{ github.event.workflow_run.name }}" >> $GITHUB_ENV
          echo "BRANCH_NAME=${{ github.event.workflow_run.head_branch }}" >> $GITHUB_ENV
          echo "COMMIT_SHA=${{ github.event.workflow_run.head_sha }}" >> $GITHUB_ENV

          # ジョブの一覧を取得
          JOBS=$(gh api repos/${{ github.repository }}/actions/runs/${RUN_ID}/jobs --jq '.jobs')

          # 失敗したジョブのログを取得
          echo "FAILED_LOGS<<EOF" >> $GITHUB_ENV

          for job in $(echo "$JOBS" | jq -r '.[] | select(.conclusion == "failure") | .id'); do
            echo "=== Job ID: $job ===" >> $GITHUB_ENV
            gh api repos/${{ github.repository }}/actions/jobs/${job}/logs >> $GITHUB_ENV 2>&1 || echo "ログの取得に失敗しました" >> $GITHUB_ENV
            echo "" >> $GITHUB_ENV
          done

          echo "EOF" >> $GITHUB_ENV

      - name: Run AI check
        id: ai-check
        uses: actions/ai-inference@v1
        with:
          model: "openai/gpt-4o"
          prompt: |
            あなたは、エラー解決のプロです。初心者に向けてわかりやすくなぜエラーになったのか、どうすればエラーを解決できるかを教えてください。
            以下の形式で簡潔に（全体で10行以内）説明してください。
            エラーの内容は以下です。

            **失敗したワークフロー:**
            - ワークフロー名: ${{ env.WORKFLOW_NAME }}
            - ブランチ: ${{ env.BRANCH_NAME }}
            - コミットSHA: ${{ env.COMMIT_SHA }}
            - 使用技術: Vite, Supabase, Firebase

            **エラーログ:**
            ```
            ${{ env.FAILED_LOGS }}
            ```

            **回答形式フォーマット:**
            【原因】1-2行で説明
            【解決方法】具体的な手順を1-2個
            【予防策】1つだけ

      - name: Save AI response to summary
        if: always()
        run: |
          # GitHub Actionsのサマリーに出力（Web UIで確認可能）
          echo "## 分析結果" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo '${{ steps.ai-check.outputs.response }}' | base64 | base64 -d >> $GITHUB_STEP_SUMMARY

```
</details>


![github.com_asa129_addiless-alcohol-app_actions_runs_15256956232.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/c980ef82-f6c8-4055-b45a-2345ef1ea153.png)


## 実際の流れ
#### ①ワークフローエラー発生
test-deploy.yml実行時、project_testジョブでテストが失敗しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/9df3a0f4-643b-4cee-a2ea-964d7d7dbde7.png)

#### ②AIにてワークフローエラー解析
test-deploy.yml実行後、ai-failure-check.ymlのワークフローが自動で起動、エラーログを取得します。

#### ③分析した結果の表示
AI分析した結果（原因と対処方法）が概要欄に表示されます。

![github.com_asa129_addiless-alcohol-app_actions_runs_15256956232.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/c980ef82-f6c8-4055-b45a-2345ef1ea153.png)

# 作成の過程
## 1. ワークフロー実行後をトリガーとする新規ワークフローの作成
ワークフローの完了をトリガーに別のワークフローを実行するために、`workflow_run`を使用しました。

https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run

```yml:ai-failure-check
name: AI Failure check

on:
  workflow_run:
    workflows: "Test and Deploy"
    types:
      - completed

jobs:
  on-success:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      - name: success
        run: |
          echo "trigger build workflow success"
  on-failure:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'failure' }}
    steps:
      - name: failure
        run: |
          echo "trigger build workflow failed"
```

`workflows`：トリガーにするワークフロー名
`types:- completed`：ワークフロー実行後を指定

`${{ github.event.workflow_run.conclusion == 'success' }}`：ワークフローの実行結果を取得

**動作確認**

下記の画像はtest-deploy.yml(ワークフロー名:Test and Deploy)実行後です。
`job名変えたよ`のコメントでpush後、エラーなくワークフローが完了しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/88acd6eb-3a1f-4829-8b4b-d939379cdabd.png)

その後、ai-failure-check.yml(ワークフロー名:AI Failure check)の結果を確認、Test and Deployがエラーなく完了しているため、`on-success`ジョブが実行されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/46475b2b-3b1b-4ebb-8731-0c24432533a1.png)

コンソールにもメッセージが表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/120b09d9-d3ac-4855-b249-7942e87647f2.png)


## 2. エラーログ取得とAI解析の実装

1.で作成したワークフロー失敗時に実行されるジョブ(`on-failure`)にて、以下を追加しました。
* `permissions`：ワークフローが他のリソースなどにアクセスする際の権限設定
* `steps`

`steps`は以下を追加
1. `failure`：コンソールに失敗した旨を表示
1. `Checkout code`：チェックアウトとリポジトリのアクセス許可
1. `Get error info`：エラーログの取得
1. `Run AI check`：AIの分析
1. `Save AI response to summay`：分析結果を表示

```yml:ai-failure-check.yml
name: AI Failure check

on:
  workflow_run:
    workflows: "Test and Deploy"
    types:
      - completed

jobs:
  on-success:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      - name: success
        run: |
          echo "trigger build workflow success"
  on-failure:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'failure' }}
    permissions:
      actions: read
      contents: read
      models: read
    steps:
      - name: failure
        run: |
          echo "trigger build workflow failed"

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Get error info
        id: get-error
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          echo "::error::ワークフロー失敗"
          echo "branch: ${{ github.event.workflow_run.head_branch }}"

          # ワークフローの実行IDを取得
          RUN_ID=${{ github.event.workflow_run.id }}
          echo "RUN_ID: $RUN_ID"

          # ワークフロー情報を環境変数に保存
          echo "WORKFLOW_NAME=${{ github.event.workflow_run.name }}" >> $GITHUB_ENV
          echo "BRANCH_NAME=${{ github.event.workflow_run.head_branch }}" >> $GITHUB_ENV
          echo "COMMIT_SHA=${{ github.event.workflow_run.head_sha }}" >> $GITHUB_ENV

          # ジョブの一覧を取得
          JOBS=$(gh api repos/${{ github.repository }}/actions/runs/${RUN_ID}/jobs --jq '.jobs')

          # 失敗したジョブのログを取得
          echo "FAILED_LOGS<<EOF" >> $GITHUB_ENV

          for job in $(echo "$JOBS" | jq -r '.[] | select(.conclusion == "failure") | .id'); do
            echo "=== Job ID: $job ===" >> $GITHUB_ENV
            gh api repos/${{ github.repository }}/actions/jobs/${job}/logs >> $GITHUB_ENV 2>&1 || echo "ログの取得に失敗しました" >> $GITHUB_ENV
            echo "" >> $GITHUB_ENV
          done

          echo "EOF" >> $GITHUB_ENV

      - name: Run AI check
        id: ai-check
        uses: actions/ai-inference@v1
        with:
          model: "openai/gpt-4o"
          prompt: |
            あなたは、エラー解決のプロです。初心者に向けてわかりやすくなぜエラーになったのか、どうすればエラーを解決できるかを教えてください。
            以下の形式で簡潔に（全体で10行以内）説明してください。
            エラーの内容は以下です。

            **失敗したワークフロー:**
            - ワークフロー名: ${{ env.WORKFLOW_NAME }}
            - ブランチ: ${{ env.BRANCH_NAME }}
            - コミットSHA: ${{ env.COMMIT_SHA }}
            - 使用技術: Vite, Supabase, Firebase

            **エラーログ:**
            ```
            ${{ env.FAILED_LOGS }}
            ```

            **回答形式フォーマット:**
            【原因】1-2行で説明
            【解決方法】具体的な手順を1-2個
            【予防策】1つだけ

      - name: Save AI response to summary
        if: always()
        run: |
          # GitHub Actionsのサマリーに出力（Web UIで確認可能）
          echo "## 分析結果" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo '${{ steps.ai-check.outputs.response }}' | base64 | base64 -d >> $GITHUB_STEP_SUMMARY

```

### permissions

`permissions`：ワークフローがGitHubのリソースやAPIにアクセスする際の権限を設定する

```yml
permissions:
      actions: read
      contents: read
      models: read
```


**公式ドキュメントより引用**
>permissions を使用して GITHUB_TOKEN に付与された既定のアクセス許可を変更し、必要に応じてアクセスを追加または削除することで、必要最小限のアクセスのみを許可することができます。
read (該当する場合)、write、または none のいずれかのアクセス レベルを割り当てることができます。
>>`actions`:GitHub Actions を操作します。
`contents`:リポジトリの内容を操作します。
`models`:GitHub Models を使用して AI 推論応答を生成します。たとえば、models: read は、GitHub Models 推論 API を使用するアクションを許可します。


https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token

### steps
#### name: failure
コンソール上に`trigger build workflow failed`を表示する

```yml
    steps:
      - name: failure
        run: |
          echo "trigger build workflow failed"
```

#### name: Checkout code
チェックアウトとリポジトリのアクセスをできるようにする

```yml
      - name: Checkout code
        uses: actions/checkout@v4
```

**READMEより引用**
>このアクションは$GITHUB_WORKSPACE配下のリポジトリをチェックアウトし、ワークフローがリポジトリにアクセスできるようにします。

https://github.com/actions/checkout

#### name: Get error info

:::note info
以下の方法は、ログを全て取得するため、ログの出力が大きいとエラーになります。
解決方法を下記にまとめていますのでご参照ください。
:::


https://qiita.com/asa129/items/adc4a8e7782e89d4d524



`id`:ステップの一意な識別子

```yml
- name: Get error info
        id: get-error
```


https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsid

`env`:ワークフロー内で使用できる変数を定義

```yml
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

**公式ドキュメントより引用**
>env：ワークフロー中のすべてのジョブのステップで使うことができる変数の map です

https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions#env

`GITHUB_TOKEN`はワークフロー開始時に自動で作成してくれます。
`${{ secrets.GITHUB_TOKEN }} `で定義し、使用します。

>各ワークフロー ジョブの開始時に、GitHub によって、ワークフローで使用する一意の GITHUB_TOKEN シークレットが自動的に作成されます。
>>${{ secrets.GITHUB_TOKEN }} を使って、GITHUB_TOKEN を使用できます。

https://docs.github.com/ja/actions/security-for-github-actions/security-guides/automatic-token-authentication

##### ワークフローの実行IDを取得

`github.event.workflow_run.~`：`workflow_run:`で指定したワークフロー情報（今回の場合は`Test and Deploy`の実行結果を格納してくれる）
`head_branch`:実行されたブランチ名
`id `:ワークフロー実行ID

```yml
        run: |
          echo "::error::ワークフロー失敗"
          echo "branch: ${{ github.event.workflow_run.head_branch }}"

          # ワークフローの実行IDを取得
          RUN_ID=${{ github.event.workflow_run.id }}
          echo "RUN_ID: $RUN_ID"
```


https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run

https://docs.github.com/ja/webhooks/webhook-events-and-payloads#workflow_run

##### ワークフロー情報を環境変数に保存

`github.event.workflow_run.~`：`workflow_run:`で指定したワークフロー情報（今回の場合は`Test and Deploy`の実行結果を格納してくれる）
`name`:ワークフロー名
`head_branch`:実行されたブランチ名
`head_sha`:コミットしたときのハッシュ値

`echo "WORKFLOW_NAME=${{ github.event.workflow_run.name }}" >> $GITHUB_ENV`

`>>`：ファイルに追記するシェルコマンド(`>`の場合は上書き)

1. `$GITHUB_ENV`ファイルを作成、`WORKFLOW_NAME=${{ github.event.workflow_run.name }}`を記載、保存
2. `WORKFLOW_NAME=${{ github.event.workflow_run.head_branch }}`を追記
3. `WORKFLOW_NAME=${{ github.event.workflow_run.head_sha }}`を追記

```yml
          # ワークフロー情報を環境変数に保存
          echo "WORKFLOW_NAME=${{ github.event.workflow_run.name }}" >> $GITHUB_ENV
          echo "BRANCH_NAME=${{ github.event.workflow_run.head_branch }}" >> $GITHUB_ENV
          echo "COMMIT_SHA=${{ github.event.workflow_run.head_sha }}" >> $GITHUB_ENV
```

##### ジョブの一覧を取得

**GitHub CLI(gh)を使ってapiを呼び出す**

`gh api repos/${{ github.repository }}/actions/runs/${RUN_ID}/jobs`

```yml
          # ジョブの一覧を取得
          JOBS=$(gh api repos/${{ github.repository }}/actions/runs/${RUN_ID}/jobs --jq '.jobs')
```

`gh`: GitHub CLIを使用するコマンド
`api`: APIを呼び出す
`repos/\\${{ github.repository }}/actions/runs/${RUN_ID}/jobs`: エンドポイント、実行したワークフローのjobを取得

https://docs.github.com/ja/github-cli/github-cli/about-github-cli

https://cli.github.com/manual/gh_api

##### 失敗したジョブのログを取得

```yml
          # 失敗したジョブのログを取得
          echo "FAILED_LOGS<<EOF" >> $GITHUB_ENV

          for job in $(echo "$JOBS" | jq -r '.[] | select(.conclusion == "failure") | .id'); do
            echo "=== Job ID: $job ===" >> $GITHUB_ENV
            gh api repos/${{ github.repository }}/actions/jobs/${job}/logs >> $GITHUB_ENV 2>&1 || echo "ログの取得に失敗しました" >> $GITHUB_ENV
            echo "" >> $GITHUB_ENV
          done

          echo "EOF" >> $GITHUB_ENV
```

`echo "FAILED_LOGS<<EOF" >> $GITHUB_ENV`:$GITHUB_ENVファイルにFAILED_LOGS<<EOFを追記
`FAILED_LOGS<<EOF`：環境変数FAILED_LOGSを設定
`<<EOF`:ヒアドキュメント、EOFという文字列が現れるまで、複数行の値として扱う
```yml
          for job in $(echo "$JOBS" | jq -r '.[] | select(.conclusion == "failure") | .id'); do
            echo "=== Job ID: $job ===" >> $GITHUB_ENV
            gh api repos/${{ github.repository }}/actions/jobs/${job}/logs >> $GITHUB_ENV 2>&1 || echo "ログの取得に失敗しました" >> $GITHUB_ENV
            echo "" >> $GITHUB_ENV
          done

          echo "EOF" >> $GITHUB_ENV
```

`$JOBS`：ジョブ一覧を格納
`jq -r '.[]`：`jq` jsonを取り扱うコマンド、`-r` オプションを直接取り扱う、`.[]`JSON配列の各要素をループして取り出す
`select(.conclusion == "failure")`:conclusionが"failure"のもののみ取得
`.id`：idだけ取り出す
取り出したものは`job`に格納

`echo "=== Job ID: $job ===" >> $GITHUB_ENV`：=== Job ID: $job ===取り出したjob(id)をGITHUB_ENVに追記

`gh api repos/${{ github.repository }}/actions/jobs/${job}/logs >> $GITHUB_ENV 2>&1 || echo "ログの取得に失敗しました" >> $GITHUB_ENV`
idのlogsをGITHUB_ENVに追記、`2>&1`は2は標準エラー出力、>&1は標準出力にリダイレクトする（エラーメッセージも通常の出力としてファイルに書き込む）
|| はOR演算子、左側のコマンドが失敗したら（false）の右側の処理を行う

` |`：YAMLの複数行記法

#### name: Run AI check

`uses`: `actions/ai-inference@v1`を指定
  `model`: AIのモデルを指定
  `prompt`:プロンプトを指定

```yml
      - name: Run AI check
        id: ai-check
        uses: actions/ai-inference@v1
        with:
          model: "openai/gpt-4o"
          prompt: |
            あなたは、エラー解決のプロです。初心者に向けてわかりやすくなぜエラーになったのか、どうすればエラーを解決できるかを教えてください。
            以下の形式で簡潔に（全体で10行以内）説明してください。
            エラーの内容は以下です。

            **失敗したワークフロー:**
            - ワークフロー名: ${{ env.WORKFLOW_NAME }}
            - ブランチ: ${{ env.BRANCH_NAME }}
            - コミットSHA: ${{ env.COMMIT_SHA }}
            - 使用技術: Vite, Supabase, Firebase

            **エラーログ:**
            ```
            ${{ env.FAILED_LOGS }}
            ```

            **回答形式フォーマット:**
            【原因】1-2行で説明
            【解決方法】具体的な手順を1-2個
            【予防策】1つだけ
```

#### name: Save AI response to summary

`if: always()`前のステップに関係なくステップを実行できる

https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#status-check-functions

`GITHUB_STEP_SUMMARY`に追加することでジョブの概要に出力することができる

https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#status-check-functions


```yml
      - name: Save AI response to summary
        if: always()
        run: |
          # GitHub Actionsのサマリーに出力（Web UIで確認可能）
          echo "## 分析結果" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo '${{ steps.ai-check.outputs.response }}' | base64 | base64 -d >> $GITHUB_STEP_SUMMARY

```

# おわりに
GitHub Actionsの新しいトリガーやGitHubCLI、シェルスクリプトなど新しい知識を得ることができました。
自分のリサーチだけでは今回の仕組みはできなかったです。AIの助けを借りながら知識を得ることができ、良い機会になりました。

# 参考

https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run

https://zenn.dev/kitoketa/articles/28675c5eb1d0fb


https://qiita.com/kite_999/items/e77fb521fc39454244e7

https://qiita.com/IY_LNX/items/ef7a1158f6084bea1bac#%E5%89%8D%E6%8F%90%E7%9F%A5%E8%AD%98

https://azukiazusa.dev/blog/actions-ai-interface-github-actions/