GitHub ActionsでSlack通知をcurlで

## はじめに

GitHub ActionsでSlack通知を行いたいという場面では、以下のようなサードパーティー製を使う事が多い。

- [slack-notify](https://github.com/marketplace/actions/slack-notify)
- [github-action-for-slack](https://github.com/marketplace/actions/github-action-for-slack)
- [Slatify](https://github.com/marketplace/actions/slatify)
- [action-slack](https://github.com/marketplace/actions/action-slack)

ただ、Enterpriseでそういったものを使うのが憚られる（承認が必要…などの）際にはcurlで通知できると便利。
（自分のメモ用としても残しておこうと思います。）

## curlでSlack通知
以下のように書く事で実現できる。

```yaml:slack-notification.yaml
name: slack notification test

on:
  push:
    branches:
      - '**'
  workflow_dispatch:
    
jobs:  
  build:
    runs-on: ubuntu-latest
    steps:            
      - name: Slack Notification
        if: always()
        run: |
          if [ '${{ job.status }}' = 'success'　]; then
            COLOR="good"
          else
            COLOR="danger"
          fi

          jq -n --arg jobLink '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}' --arg color "${COLOR}" '{
            attachments: [{
              pretext: "結果 ${{ job.status }}",
              color: $color,
              title: $jobLink,
              title_link: $jobLink,
              text: "hogehoge"
            }]
          }' | curl ${{ secrets.SLACK_WEBHOOK_URL }} -X POST -H 'Content-Type: application/json' -d @-
```

一部詳細を見ていく。

### if: always()
```
if: always()
```
実際には、Slack通知の前にはCI・CDの各stepsが実行される。
それらの実行結果が何であれSlack通知は実行したいので`always()`を指定している。

### bashのif文
```
if [ '${{ job.status }}' = 'success']; then
  COLOR="good"
else
  COLOR="danger"
fi
```
Slack通知する際に分かりやすくするために、attachmentsを使用する。
ただ、結果の通知で変わるのがcolorだけの場合、`success`・`failure`のそれぞれを実装したくない・・・。
DRY原則的にも望ましい形にするため`job.status`の結果でcolorが変わるようにしている。
※attachmentsの雰囲気掴みには[こちら](https://qiita.com/daikiojm/items/759ea40c00f9b539a4c8)

### jqの部分
```
jq -n --arg jobLink '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}' --arg color "${COLOR}"
```
| キーワード | 意味 |
|:-:|---|
| -n | null（空）を無視する |
| --arg  | jq実行時に変数として受け渡しをするためのオプション <br> --arg foo barとすると、$fooで値「bar」をバインドできる <br> 値は文字列として扱われるので、--arg foo 123だと"123"としてバインドされる|

[jq](https://stedolan.github.io/jq/manual/)はコマンドライン上でJSONを操作（filtering,整形など）ができるツール。
今回はjqを使ってJSONを生成して、それを後の工程で標準入力として渡している。

### curlの部分
```
... | curl ${{ secrets.SLACK_WEBHOOK_URL }} -X POST -H 'Content-Type: application/json' -d @-
```
| キーワード | 意味 |
|:-:|---|
| ${{secrets.SLACK_WEBHOOK_URL}} | GitHub上のsecretsで設定したIncoming Webhook URL <br> https://{server_url}/{repo}/settings/secrets/actions |
| @- | 標準入力から取り込む時に使うoption <br> ex) "処理" &#124; curl http://hoge.com -X POST -d @- |

ここでは[Incoming Webhook URL](https://api.slack.com/messaging/webhooks#posting_with_webhooks)を用いてSlack通知を実現する。
※Incoming Webhooksでのメッセージ送信については[ここ](https://api.slack.com/messaging/webhooks)

## Slack側の設定
### Slackアプリを作成する
[Create a Slack app](https://api.slack.com/messaging/webhooks#getting_started__1.-create-a-slack-app-if-you-dont-have-one-already)にアクセスし、`Create a Slack app`をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/639a4c85-f883-5b25-81e5-d16819e81a91.png)
するとslack apiのサイトにリダイレクトする。
リダイレクトすると以下のポップアップが表示されるので、`App Name`・`Workspace`をそれぞれ入力・選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/bcbe53ff-159b-da82-0511-5c4fb359054a.png)

### Incoming Webhooksを有効化する
前の工程でslackアプリを作成すると、アプリの設定画面にリダイレクトする。
設定画面でIncoming Webhooksを有効化するために、以下の`Incoming Webhooks`をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/f745c153-5f05-997e-abfe-3801a55ac13f.png)

### Incoming Webhooksを作成する
Incoming Webhooksの設定画面に遷移するので、`off`から`on`に変更する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/65e177de-a78c-2991-6ef8-77c21d6dd103.png)

`on`にすると以下のように`Add New Webhook to Workspace`というボタンが表示されるので、それをクリックしそこからチャンネルとの紐づけ（権限）を設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/394a7921-93ca-64ac-63fc-0449a041be21.png)

以下の画面が表示されるので通知先のチャンネルを選択し、`許可する`をクリックして設定を完了させる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/cb0e5033-8dee-7590-41d7-34a831b9a552.png)

### Incoming Webhook URLを利用して通知をテストしてみる
通知先のチャンネルを指定すると、`Incoming Webhooks`の設定画面上で`Webhook URL`が追加されているのが確認できる。
このURLを使ってチャンネルへ通知を行える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/08b09ded-fb05-87dc-8634-40aac76f757f.png)

実際にコマンドプロンプトから送ってみると…

```
curl -X POST -H "Content-type: application/json" --data "{\"text\":\"Hello, World!\"}" https://hooks.slack.com/services/…
```
| コマンドプロンプト | slack |
|:-:|:-:|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/3bc6fd19-393c-a645-ba90-411d4dc908f5.png)  | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/1d474412-52fb-f1f9-96d5-70205b8670c7.png) |

ちゃんと通知できている事が確認できた！
後は、GitHub Actionsで実際にyamlを記載しパイプラインを実行すればOK！

## 参考文献
- [GitHub Actions でSlackに通知するいくつかの方法を比較してみた](https://furusax0621.hatenablog.com/entry/2020/03/29/193336)