CircleCI の Webhook を使ってみた


この記事は [CircleCI Advent Calendar 2021](https://qiita.com/advent-calendar/2021/circleci) の22日目の記事です。

こんにちは。CircleCI カスタマーサクセスチームのChisatoです。
今回は Webhook について紹介します。
初めてのQiita投稿なので、温かい目で読んでいただければ幸いです。

##Webhook でできること

[Webhook](https://circleci.com/docs/ja/2.0/webhooks/#)を使うと、管理先のプラットフォームでCircleCIからの情報（イベント）を受け取れます。
[こちら](https://circleci.com/blog/using-circleci-webhooks/)のブログ では、「API が "プル" なのに対して、Webhook は "プッシュ" である」と表現しています。 APIとは異なり、イベント発生時に CircleCI が連携先サービスに情報を送信するためです。

[Webhookのユースケース](https://circleci.com/docs/ja/2.0/webhooks/#use-cases)は下記引用のとおりいろいろあります。
>- カスタム ダッシュボードを作成して、ワークフローやジョブのイベントの可視化または分析を行う。
- インシデント管理ツール（例：Pagerduty）にデータを送信する。
- Airtable などのツールを使ってデータを取得・可視化する。
- Slack などのコミュニケーション アプリにイベントを送信する。
- ワークフローがキャンセルされた場合に Webhook を使ってアラートを送信し、API を使ってそのワークフローを再実行する。
- ワークフローやジョブが完了したら内部通知システムをトリガーし、アラートを送信する。
- 独自の自動化ブラグインやツールを作成する。


##Airtable にジョブの完了を送信

[Airtable](https://www.airtable.com/product)とは、「チームのコラボレーションを加速させるローコードプラットフォーム」です。さまざまなアプリとの連携が簡単にできます。
ここでは、CircleCIのジョブが完了するとテーブルに記録されるように設定します。
[こちら](https://circleci.com/docs/2.0/webhooks-airtable/)のドキュメンテーションページを参考にしました。

###６つのステップ
####１．[Airtable](https://www.airtable.com) のアカウント作成
####２．Base の作成
####３．テーブルのコラム部分の設定 

テーブルのコラムのタイトル部分をダブルクリックして、フィールドタイプを"Single ilne text"にセットします。
各コラムのタイトルを "ID", "Job Name", "Status", "Happened At"とします。
<img width="500" alt="![Screen Shot 2021-12-21 at 20.00.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/0f274b93-bbce-9ddd-65b5-7c931be32dc9.png">

####４．Automations の設定
右上の "Automations" をクリックして、"Create a custom automation" を選択します。
TRIGGER のタイプを "When webhook received" として、生成されたURLをコピーします。
<img width="500" alt="![Screen Shot 2021-12-21 at 14.33.49.png]" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/8a9c8176-79f5-66b7-7772-6436d37136d6.png">
次に、ACTIONSのタイプを "Create record" とします。
Tableを選択し、各フィールドに、対応するコラムとwebhookのデータを選択します。
TestをRunして動作確認したら、画面上部のトグルを ON にします。
<img width="500" alt="![Screen Shot 2021-12-21 at 21.32.29.png]" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/dc830dde-5da0-8dff-9856-c6b6e95b87d0.png">

####５．CircleCI の Webhook の設定
CircleCI のUIで、Webhook を送信したいプロジェクトのページに移動します。
"Project Settings" ページ左側の最下部にある "Webhooks" を選択します。
”Add Webhook” を選択し、Webhook名と、先ほどコピーした Airtable のURLを入力します。
イベントのうち、"Job Completed"を選択して、"Add Webhook" をクリックします。
<img width="500" alt="![Screen Shot 2021-12-21 at 14.44.33.png]" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/38e5dae9-4429-b798-7748-10b3e8441987.png">

####６．ジョブ完了後の動作確認
ジョブを走らせてみると、テーブルに記録されていることが確認できました。
<img width="500" alt="![Screen Shot 2021-12-21 at 21.46.19.png]" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/19aa10a6-de0f-bfd8-f9be-77952434799c.png">
ほほう。なかなかいいじゃない。
その後Slackに通知するなどして遊んでみましたが、簡単で楽しかったです。

##ngrok との連携

ngrok..。 んぐ.. 。えぬじー..？
[公式ドキュメント](https://ngrok.com/docs)で確認すると、en-grok と発音することがわかりました。
ngrok は、トンネリングを用いて、ローカルサーバーをセキュアにインターネットに公開できるサービスです。

###５つのステップ

####１．ngrokのセットアップ
[こちら](https://dashboard.ngrok.com/get-started/setup)を参考にngrokを設定しました。
セットアップの `ngrok http 80` の部分でいきなり躓いたのですが、ngrok.yml に `web_addr: localhost:8080` と追記することで通信できました。
また、いきなりブログ記事のプロジェクトに挑むのではなく、自分の既存のプロジェクトから Webhook を ngrok に 連携できることを確認してからブログ記事に進みました。

####２．Personal API Token の生成
いよいよ、ブログ記事のプロジェクトに進みます。
サンプルプロジェクトのNode.jsサーバーが `localhost:8080` を向いていたため、変更しました。
今回はステップ４で Signature のバリデーションを行いたいので、[Personal API Token](https://circleci.com/docs/ja/2.0/managing-api-tokens/?utm_source=google&utm_medium=sem&utm_campaign=sem-google-dg--japac-en-dsa-maxConv-auth-brand&utm_term=g_-_c__dsa_&utm_content=&gclid=Cj0KCQiAk4aOBhCTARIsAFWFP9G2M3YHSwSJs1NRRwOl3q-NM8ehrFTY3tXdIguQd9_CIW02GLs3KSwaArj7EALw_wcB#) を生成しました。

####３．Webhook の設定
Airtable のステップ５と同じ要領で Webhook を作成します。
今回はngrok で作成されたURLを追加し、先ほど生成した API Token を追加します。
（ngrok は無料プランだと新しい通信のたびにURLが更新されるようです。URLが更新されたときは、Webhook の Receiver URL を合わせて更新します。）

####４．Signature のバリデーション設定
単純に Webhook を設定すると、「ウェブ上のどこからでも、エンドポイントのアドレスを知る相手からはイベントを受信できる」状態になっています。
Personal API Token を用いた設定を追加することで、「CircleCI Webhookからの情報しか受信しないように設定」できます。
詳細はこちらの[ブログ記事](https://circleci.com/blog/using-circleci-webhooks/)を参照ください。

Signature のバリデーション設定で躓いたので、CircleCI の Solutions Engineer の Tadashiさんに助けていただきました。
[こちら](https://github.com/CircleCI-Public/webhooks-consumer-sample/blob/main/server.js#L38-L51)の "const key" の部分を自分の token 名に変更します。
<img width="400" alt="![Screen Shot 2021-12-21 at 23.04.42.png]" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/491b9f87-01ca-26af-59e3-aa30e89b5955.png">

####５．動作確認
Tadashiさんがいい感じにやってくださったおかげで、無事に[こちらのプロジェクト](https://github.com/CircleCI-Public/webhooks-consumer-sample)についてもイベントを受信することができました。
<img width="400" alt="![Screen Shot 2021-12-21 at 23.05.44.png]" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/1e5d93ac-c64f-e6b2-e67e-ba39fa6855d7.png">

##まとめ
今回 Webhook を使ってみて、その設定方法の簡単さと、できることの多さに感動しました。特に、 Airtable との連携からSlackに通知するまでの流れがスムーズで心地よかったです。 

このブログ記事をチェックしてくださったエンジニアの方から、「通常のGithubのコミットであれば、誰がいつワークフロー実行しているとかわかるのでいいなーと思いました。
[https://circleci.com/docs/2.0/webhooks/#vcs](https://circleci.com/docs/2.0/webhooks/#vcs)」とコメントいただきました。
なるほど、まだまだ奥が深そうなWebhook。お客様にたくさん活用いただけるよう、勉強をがんばります。

###ブログを書いた感想
こちらのアドベントカレンダーには、軽い気持ちで参加しました。
参加して間もなく、他の方々の素晴らしい記事を拝読して、自分がとても軽い気持ちで参加してしまったことに気づきました。
「何てことしてくれたんだよ、自分。そもそも書けることあるの？」と自分を責めました。
しかし、そのあとすぐに、自分が CircleCI を大好きな理由の１つを思い出しました。
それは、”社員の皆さんがとても優しく協力的なところ” です。
「調べてもわからなかったら、質問しよう。。」

そして、前述の Signature に関して Tadashi さん（Solutions Engineer）とJasur さん（DevOps Customer Engineer）に質問しながら、記事を書き終えることができました。しかも、お二人とも質問への回答のみならず、実際の動作が確認できるまで付き合ってくださいました。ありがとうございます。

2021年は、いつもお世話になっている方々への感謝の気持ちで締めたいと思います。
いつも優しくご指導いただき、ほんとうにありがとうございます。
日に日に寒くなってきている年末ですが、皆さんのおかげで、私の心の中はぽかぽかと温かいです。
2022年は、「我以外皆我師」の言葉を胸に精進したいと思います。

最後までお読みいただきありがとうございました。
どうぞ良いお年をお迎えください。

#####参考
[Webhookの概要（CircleCI ドキュメンテーション）](https://circleci.com/docs/ja/2.0/webhooks/#)
[Creating integrations, dashboards, notifications, and more using CircleCI webhooks（CircleCI Blog）](https://circleci.com/blog/using-circleci-webhooks/)
[CircleCI webhooks with Airtable（CircleCI ドキュメンテーション）](https://circleci.com/docs/2.0/webhooks-airtable/)
[Airtable](https://www.airtable.com)
[ngrok Documentaion](https://ngrok.com/docs)