よこなのへたのよこずき

noteもよろしくね

GitHub Actionsが特定のイベントでfailした時だけSlackに通知する

ちょっと前に取り組んだのでメモしておきます。GitHub Actionsの話ばっかり書いている…

2つの実現方法

GitHub Actionsの結果をSlackに通知する方法は2つあります。

ざっくりいうと視点が逆という感じなんですが、それぞれにpros/consがあります。

  • GitHub integration for Slack
    • メリット: 導入がめちゃくちゃ楽。Slackでsubscribeコマンドを打つだけで成形されたメッセージを受け取れる
    • デメリット: Actionsの結果による制御ができない(つら)。失敗だけ通知するとか、結果に応じてチャンネルを変えるとか無理
  • Slack app
    • メリット: 自分でGitHub Actionsのyamlを書いて細かい制御ができる
    • デメリット: GitHub integrationに比べると導入が面倒

GitHub integration for Slackを使う場合の設定

前述の通り細かい制御は不可能なので、こっちはタイトルとずれた内容になります(タイトル通りのことは後半に)。

  1. Slackにインテグレーションを追加する
  2. /github subscribe <organization>/<repository> workflows:{name:"<workflow name>" event:<events> branch:"<branch>"}を実行する
  3. 不要な更新も追加されてしまったらunscribeする

例えば上記は

/github subscribe ihcomega56/github-actions-failure-test workflows:{name:“Integration Tests” event:“schedule”,“push” branch:“main”}

としています。これは

  • ihcomega56/github-actions-failure-testリポの
  • Integration Testsワークフローが
  • 定期実行(schedule)またはmainへのpushにより

実行された場合、結果を通知せよと言っています。

そして、上の画像のようにインテグレーションくんがissueやPRなどの更新もすべてキャッチしようとしてしまったら、要らないものは外します。ワークフローの通知以外は不要だとすると、

/github unsubscribe ihcomega56/github-actions-failure-test issues pulls commits releases deployments

を叩くと、スペース区切りで指定した機能はまとめてオフになります。

設定値の詳細はぜひ公式へ: github.com

ということで、これだけで見た目もいい感じのメッセージが受け取れるようになるのでお手軽便利です。1実行につき、ワークフローが走り始めた時・終わった時の2回通知が来ます。

ちなみにこの拡張のリポジトリはコントリビューションを受け付けておらず、機能改善したい際はお願いすることだけが許されています。通知を失敗時だけにしたいよ!というissueも既に存在するので、欲しい方はいいねしましょう!!!!!

github.com

もうひとつ補足として、(un)subscribeはチームの誰が実行してもいいと思います。SlackとGitHubに十分な権限*1さえあれば、Aさんが登録したものをBさんが解除みたいなことも出来るため、チームリーダーやadminっぽい人に頼まなくて大丈夫なはずです。

Slack appを使う場合の設定

自分のチームでは結果に応じてチャンネルを振り分けたいということになったので設定ファイルを書きました。

github.com (↑最終的には1つ目の方法に変わったのでマージされてないけど、実際のPR)

ポイントを抜粋すると、GitHub Actionsに下記のようなステップたちを追加します。日本語のコメントはこのブログ用に解説としてつけたものです。
※インデントは左に詰めてあるのでこのままだと動きません

# トリガーたち。これらのうち、定期実行およびmainへの更新時のみ通知したい
# (例えばPRのオープン時とかは要らない。通知されなくともマージするまで何度も見るので)
on:
  schedule:
    # scheduled at 3PM and 3AM daily
    - cron: '0 3,15 * * *'
  pull_request:
    types:
      - opened
      - synchronize
      - reopened
      - ready_for_review
      - closed
# Send the result to Slack when a PR is merged and tests were executed regularly
- name: Notify success
  # 成功した && 定期実行かmain更新がされた場合、下記を走らせる
  if: ${{ success() && contains(fromJson('["push", "schedule"]'), github.event_name) }}
  uses: slackapi/slack-github-action@v1.23.0
  with:
    # 成功通知用のチャンネルIDをsecretsに追加しておく
    channel-id: ${{ secrets.CHANNEL_ID_FOR_MESSAGES }}
    # If https://github.com/slackapi/slack-github-action/issues/84 is fixed, payload.json can be shared among the following two steps (DRY).
    payload: |
      {
        "text": "Integration tests finished successfully.",
        "attachments": [{
        "title": ":white_check_mark: ${{ github.workflow }} #${{ github.run_number }}",
        "title_link": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
        "color": "#36a64f"
        }]
      }
  env:
    SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

- name: Notify failure
  # 失敗した && 定期実行かmain更新がされた場合、下記を走らせる
  if: ${{ failure() && contains(fromJson('["push", "schedule"]'), github.event_name) }}
  uses: slackapi/slack-github-action@v1.23.0
  with:
    # 失敗通知(アラート)用のチャンネルIDをsecretsに追加しておく
    channel-id: ${{ secrets.CHANNEL_ID_FOR_ALERTS }}
    payload: |
      {
        "text": "Integration tests failed. Check the following workflow and fix it.",
        "attachments": [{
        "title": ":x: ${{ github.workflow }} #${{ github.run_number }}",
        "title_link": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
        "color": "#ff0000"
        }]
      }
  env:
    SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

(なんかyamlの解析うまくいってなくて表示おかしいかもw)

補足すると

  • github.event_namepush, pull_requestなどイベントによる振り分けに使える。1つだけならイコール==でいけるが、複数の場合は上記のようにfromJsonなどと書く(参考: 公式docたち GitHub Actions のワークフロー構文 - GitHub Docs, 式 - GitHub Docs
  • Slackにメッセージを送るのは公式のアクションを使っている
  • SlackのチャンネルIDはチャットのURLから取れる。ブラウザで希望のチャンネルにアクセスするとhttps://app.slack.com/client/<スペースのID>/<チャンネルのID>ってなってるので、最後のスラッシュ以降をコピペすればOK。他にもっと良い取得方法があるのかもしれないけど
  • payloadでSlackのレイアウトを指定する。結構複雑なこともできるけど、今回は極めてシンプルに結果とActionsへのリンクだけ埋め込んでいる
  • bot tokenをSlackのコンソールで生成する。READMEにも説明があるので、参考スクショだけ貼っておく…↓*2

設定をいじりたいbotをクリックするとこの画面に辿り着けるよ!

ここまで設定するとこんな感じで結果が送られてきます!

画像にはないけどチャンネル振り分けもできました。

結論

Notify workflows only on errors · Issue #1563 · integrations/slack · GitHub が実装されれば面倒なことしなくてもすべて解決や・・・🙏

御礼

twitter.com

こちらで相談乗ってくださったよしことしろやまさんありがとうございましたー!

*1:あんまりちゃんと調べていないので「十分」とボカしておきます…例えば、GitHubはread権限だけでいいのかもしれないけど分からん

*2:私はどうもSlackで欲しいトークンとかを見つけるのが苦手なんだけど皆はどうですか…。コンソール妙にむずくない?