CircleCI OrbsでSlackにFailedとSuccessを通知する

CircleCI Orbsを使えば、Slack通知が超簡単に実現できました。
2021.03.04

CircleCI Orbsを利用して、Slack通知を簡単に導入してみました。

おすすめの方

  • CircleCIでSlackに通知したい方

メッセージテンプレートとカスタムメッセージについて

簡単に導入できるようにメッセージテンプレートが用意されています。しかしながら、Failed時の情報が少ないため、今回は下記のメッセージを自作しました。

失敗時のSlack通知の様子

Slackにアプリを追加する

手順に従って実施します。

1. Slackアプリの作成

Slack Appsで「Create New App」を選択し、新規作成します。

Slack Appを作成する

2. Permissionsの設定

メニューの「OAuth & Permissions」を選択します。

Permissions設定をする

「Scopes」の「Bot Token Scopes」に下記を追加します。

  • chat:write
  • chat:write.public
  • files:write

Scopesを設定する

3. Slackアプリをワークスペースにインストールする

画面上部に「Install App to Workspace」があるので、押してSlackアプリをワークスペースにインストールします。

Slack Appをワークスペースにインストールする

Slack Appをワークスペースにインストールする(許可する)

「Bot User OAuth Token」が表示されるのでメモしておきます。あとでCircleCIの環境変数に設定します。

Tokenをメモしておく

SlackチャンネルのIDを取得

通知先チャンネルの「リンク」を取得します。

Slackチャンネルのリンクをコピーする

このリンクの最後尾がチャンネルIDです。下記のchannelId部分ですね。

https://xxx.slack.com/archives/channelId

channelId部分はメモしておきます。あとでCircleCIの環境変数に設定します。

CircleCIのワークフローを作成する

GitHubの任意リポジトリにCircleCIの設定ファイルを作成します。

mkdir .circleci
touch .circleci/config.yml

中身は下記とします。notify_slack_passnotify_slack_failでカスタムメッセージを作成しています。

config.yml

version: 2.1

executors:
  deploy_container:
    docker:
      - image: circleci/python:3.8.7

orbs:
  slack: circleci/slack@4.3.0

commands:
  lint_and_unit_test:
    steps:
      - run:
          name: lint and unit test
          command: |
            echo "any lint and unit test command"

  deploy:
    steps:
      - run:
          name: deploy
          command: |
            echo "any deploy command"

  e2e_test:
    steps:
      - run:
          name: e2e test
          command: |
            echo "any deploy command"

  notify_slack_pass:
    steps:
      - slack/notify:
          event: pass
          custom: |
            {
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": ":tada::tada::tada: *Success!*"
                  }
                },
                {
                  "type": "section",
                  "fields": [
                    {
                      "type": "mrkdwn",
                      "text": "*Project:*\n${CIRCLE_PROJECT_REPONAME}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*When:*\n$(TZ=Asia/Tokyo date +'%Y/%m/%d %T')"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Job:*\n${CIRCLE_JOB}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Author:*\n${CIRCLE_USERNAME}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Branch:*\n${CIRCLE_BRANCH}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Tag:*\n${CIRCLE_TAG}"
                    }
                  ]
                },
                {
                  "type": "actions",
                  "elements": [
                    {
                      "type": "button",
                      "text": {
                        "type": "plain_text",
                        "text": "View Job"
                      },
                      "url": "${CIRCLE_BUILD_URL}"
                    }
                  ]
                }
              ]
            }

  notify_slack_fail:
    steps:
      - slack/notify:
          event: fail
          custom: |
            {
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": ":japanese_ogre::japanese_ogre::japanese_ogre: *Failed* :bangbang:"
                  }
                },
                {
                  "type": "section",
                  "fields": [
                    {
                      "type": "mrkdwn",
                      "text": "*Project:*\n${CIRCLE_PROJECT_REPONAME}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*When:*\n$(TZ=Asia/Tokyo date +'%Y/%m/%d %T')"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Job:*\n${CIRCLE_JOB}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Author:*\n${CIRCLE_USERNAME}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Branch:*\n${CIRCLE_BRANCH}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Tag:*\n${CIRCLE_TAG}"
                    }
                  ]
                },
                {
                  "type": "actions",
                  "elements": [
                    {
                      "type": "button",
                      "text": {
                        "type": "plain_text",
                        "text": "View Job"
                      },
                      "url": "${CIRCLE_BUILD_URL}"
                    }
                  ]
                }
              ]
            }

jobs:
  lint_and_unit_test:
    executor: deploy_container
    steps:
      - checkout
      - lint_and_unit_test
      - notify_slack_fail

  deploy:
    executor: deploy_container
    steps:
      - checkout
      - deploy
      - notify_slack_fail

  e2e_test:
    executor: deploy_container
    steps:
      - checkout
      - e2e_test
      - notify_slack_fail
      - notify_slack_pass

workflows:
  version: 2
  release-workflow:
    jobs:
      - lint_and_unit_test:
          filters:
            tags:
              only: /.*/
      - deploy:
          filters:
            tags:
              only: /.*/
          requires:
            - lint_and_unit_test
      - e2e_test:
          filters:
            tags:
              only: /.*/
          requires:
            - deploy

通知の方針は下記としています。Job毎のSuccessが通知されるのはノイズになると考えています。

  • Success:最後のJobが成功したとき
  • Failed:いずれかのJobが失敗したとき

CircleCIが用意している環境変数は下記にあります。

CircleCIの設定を行う

プロジェクトのセットアップ

リポジトリをPushし、CircleCIで「Set Up Project」を選択します。

CircleCIでプロジェクト設定する

続いて、「Start Building」を選択します。

CircleCIでビルド開始する

SLACK_ACCESS_TOKENの設定をしてないので、失敗します。

CircleCIのJobがエラーになる

環境変数を設定

下記の環境変数を設定します。

Name Value
SLACK_ACCESS_TOKEN xoxb-xxxxx-yyyyy-zzzzz
SLACK_DEFAULT_CHANNEL channelId

CircleCIの環境変数を設定する

動作確認をする

成功時の様子

失敗したパイプラインをRerunします。

CircleCIのJobをRerunする

Slackに来た通知は下記です。

成功時のSlack通知の様子

失敗時の様子

存在しないコマンドxxxを実行させて失敗させます。

config.yml(一部)

commands:
  lint_and_unit_test:
    steps:
      - run:
          name: lint and unit test
          command: |
            echo "any lint and unit test command"
            xxx

Slackに来た通知は下記です。

失敗時のSlack通知の様子

さいごに

記載量は多くなってしまいますが、自分で任意のメッセージを作成できるのは良いですね。 ぜひお試しください。

参考