⚠️

GitHub ActionsのCI失敗をSlackに通知する

2024/07/11に公開

みなさん、GitHub Actionsが失敗したときの通知はどうしているでしょうか?正直なところ「こうするのがベスト!」というのがいまいちわからず、結局のところ自前で組む結論に至っている今日このごろです。

はじめに

GitHub Actionsを使用したCIプロセスでは、ジョブの失敗を迅速に検知することが重要です。が、デフォルトではこれをいい感じに設定できる方法がありません(少なくとも私は発見できていません)。本記事では、Slackを使用して失敗通知を実装する方法を説明します。

実際の作り方や詳しい画面に関しては動画でウォークスルーしているので、時間があれば見てみてください。
https://youtu.be/P7t2GD_kJeM?si=YeOSG1GpFOjuUsby

結果だけ知りたい人は下記リポジトリを参考にしてもらえたらと思います。
https://github.com/craftell/study-ci-failure-notification

Slack appの準備

動画で見る

まず、Slack appを作成し、Webhook URLを取得します。

  1. Slackの管理画面から新しいappを作成します。
  2. 「Incoming Webhooks」機能を有効にします。
  3. Webhookを追加し、通知を送信するチャンネルを選択します。
  4. 生成されたWebhook URLを保存します(これは後で使用します)。

GitHub Actionsワークフローの基本設定

動画で見る

次に、サンプルのGitHub Actionsのワークフローを設定し、意図的に途中でエラーを発生させておきます。

name: Test Job

on: push # 確認しやすくしたいのでpushしたら必ず実行させる

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Run tests
        run: |
          echo "Running tests1..."
          exit 0
  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Run tests
        run: |
          echo "Running tests2..."
          exit 1 # ←意図的に失敗させる
  job3:
    runs-on: ubuntu-latest
    needs: job2
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Run tests
        run: |
          echo "Running tests3..."
          exit 0

Slackへの通知ジョブの実装

動画で見る

失敗時にSlackに通知を送るジョブを実装します。

  1. 新しいジョブ「notify-slack」を追加します。
  2. if条件を使用して、前のジョブが失敗またはスキップされた場合にのみ実行されるようにします。
  notify-slack:
    runs-on: ubuntu-latest
    needs: job3 # job3に依存させます(job1→job2→job3は直列なので、job3だけ依存すればOK)
    if: ${{ always() && needs.job3.result == 'failure' || needs.job3.result == 'skipped' }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Slack Notification(failure)
        uses: ./.github/actions/notify-failure-to-slack
        with:
          slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
          message: 'ほげほげジョブに失敗しました!'
  1. Slack通知の部分は再利用したいので、別Actionとして作ります
  2. .github/actions/notify-failure-to-slack/action.yml に作ります
name: Notify Action Failure to Slack
description: 'Notify Slack when a workflow fails'
inputs:
  slack_webhook_url:
    description: 'Slack webhook URL'
    required: true
  message:
    description: 'Message to send to Slack'
    required: true
    default: 'Actionが失敗しました'
runs:
  using: composite
  steps:
    - name: Checkout
      uses: actions/checkout@v4
    - name: Create JSON payload # Slackへ送るJSONは独立したStepで作ります
      shell: bash
      run: |
        echo '{
          "blocks": [
            {
              "type": "rich_text",
              "elements": [
                {
                  "type": "rich_text_section",
                  "elements": [
                    {
                      "type": "emoji",
                      "name": "warning"
                    },
                    {
                      "type": "text",
                      "text": "${{ inputs.message }}"
                    },
                    {
                      "type": "emoji",
                      "name": "warning"
                    }
                  ]
                }
              ]
            },
            {
              "type": "section",
              "text": {
                "type": "mrkdwn",
                "text": "<https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}|GitHub Actions>"
              }
            }
          ]
        }' > payload-slack-content.json
    - name: Send custom JSON data to Slack workflow 
      id: slack
      uses: slackapi/slack-github-action@v1.26.0
      with:
        # 前のステップで作ったJSONを送ります
        payload-file-path: './payload-slack-content.json'
      env:
        SLACK_WEBHOOK_URL: ${{ inputs.slack_webhook_url }}
        SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

このActionを作っておくことで、ローカルからは以下のようにどのJobからも呼べるようになります。

    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Slack Notification(failure)
        uses: ./.github/actions/notify-failure-to-slack
        with:
          slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
          message: 'ほげほげジョブに失敗しました!' # カスタムメッセージに変えられる

これでCI失敗時に以下のように通知を受け取ることができ、さらに対象となるGitHub Actionsにリンクから飛ぶこともできます。

まとめ

この実装により、以下のような利点が得られます:

  1. CIジョブの失敗を迅速に検知できる
    2. 再利用可能なActionとして実装することで、複数のワークフローで簡単に使用できる

ただし、この実装にも制限事項があって、「各ワークフローに個別に通知ジョブを追加する必要がある」というものです。一箇所で全部キャッチしてくれると楽なのですが。。。その方法は見つけられていません。(どなたか知っていたら教えて下さい)

Discussion