GitHubのpush以外のWebHookイベントからCodePipelineを発火させる


# まえがき

AWS完結でCI/CD環境を構築する時、よくお世話になるのがCodePipelineやCodeBuildですね。

CodePipelineとGitHubはWebhookで連携が可能になり、pushを検知→発火ということが出来るようになりました。
(以前はポーリングによる定期監視以外に連携する方法がなかった)
しかし、開発チームの運用フローによっては「pushした瞬間じゃなくて、GitHub上で**releaseしてタグ切った瞬間にCodePipelineが発火してほしい**」ということもあると思うので、ここではWebhookに一工夫加えて、任意のGitHubイベントからCodePipelineを発火させる方法について書いていきます。


# 本題

とりあえずどんなイベントでも発火できますが、今回はreleaseイベントを発火させる例を紹介します。
また、時々登場する `--region "ap-northeast-1"` は環境によって読み替えて下さい。

## CodePipelineの設定

作成段階で特別な操作はありません。
CodePipeline作成時、GitHubに接続する段階で、任意のリポジトリとブランチを選択※し、
普通に変更検出でwebhookを使用するオプションで最後までパイプラインを作りきります。

(※最終的に監視したいのがリリースイベントの場合は、masterを選ぶ)


![スクリーンショット 2018-09-30 19.19.31.png](https://qiita-image-store.s3.amazonaws.com/0/128115/02aacf33-0068-d379-9d22-82c540629c66.png)


## webhookの設定変更(GitHuｂ側)

パイプラインを作成後、GitHubのリポジトリにwebhookが一つ登録されます。
こいつの発火イベントをいじりましょう。

WebhooksのEdit画面に入り
![スクリーンショット 2018-09-30 19.23.35.png](https://qiita-image-store.s3.amazonaws.com/0/128115/169d33c9-5d68-ee17-28ae-fd20b8141246.png)

pushイベントのみをトリガーにする設定になっているのでこいつをselect individual eventsにして
![スクリーンショット 2018-09-30 19.26.22.png](https://qiita-image-store.s3.amazonaws.com/0/128115/f1a3356a-a34b-0437-2c18-56bf9b3a8e08.png)

Pushesを外し、Releasesにチェックを入れて保存
![スクリーンショット 2018-09-26 19.29.00.png](https://qiita-image-store.s3.amazonaws.com/0/128115/64c903e1-19e3-b426-ce09-e888188a43c1.png)

## webhook設定の調査（AWS側）

何となく、上記だけでうまくいくと思うじゃないですか。僕はそう思ってました。
しかし何回リリースをしてもCodePipelineが無反応なので
ずっと:no_mouth:こんな顔でしたよ、ええorz

調べた結果、GitHubからは確かに設定したwebhookエンドポイントにPOSTは飛んでるんですが、
webhook側にフィルターが掛かっていてPush以外のイベントが弾かれているようでした。

というわけで、AWS側のエンドポイントの設定を見てみましょう。
これについてはコンソールに存在しない設定なのでcliで行います。

以下コマンドで、現在の設定を取ってきます

```bash
aws codepipeline list-webhooks --region "ap-northeast-1"
```

その情報の中に、以下のような場所がありますね。

```json
"filters": [
    {
      "jsonPath": "$.ref", 
      "matchEquals": "refs/heads/{Branch}"
    }
```

このfilterはPOSTされたwebhookのPayloadを確認していて、これに合致しないものは破棄されてしまいます。


ここでGitHubがwebhook投げるときの話に戻るんですが、PushのときとReleaseのときでは、飛んでいくPayloadに結構差異があります。
(GitHubのwebhook設定ページ下部に実際に飛んだwebhookの内容が一覧表示されているので、確認してみて下さい)


Push →上記フィルターが、 `"ref": refs/heads/master` にマッチしていますね。
![スクリーンショット 2018-09-30 19.44.27.png](https://qiita-image-store.s3.amazonaws.com/0/128115/0a386be6-3779-558f-7aa3-e33b9c82daee.png)

Release → そもそも"ref"キーすら存在しません。
![スクリーンショット 2018-09-30 19.48.03.png](https://qiita-image-store.s3.amazonaws.com/0/128115/308f9818-b372-cd57-a1b2-85574fd7f23a.png)


上記の情報で何となく分かったと思いますが、CodePipelineがReleaseで正しく反応できるようにするには、このフィルターをReleaseに存在するPayloadで書き換えてあげれば良いわけです。

## webhook設定の変更（AWS側）

(webhookをCLIでアップデートする際に必要な情報は以下URLに記載されているので合わせて確認して下さい)
https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-webhooks-update.title.html

では、実際に書き換えましょう。

まずは、先程のコマンドで再度既存の情報を確認します

```bash
aws codepipeline list-webhooks --region "ap-northeast-1"
```

そしてcliを実行しているローカルマシンに以下のようなjsonファイルを作成します。
基本的に、filters以外の情報は上記コマンドの"definition"以下の情報を丸々コピーして下さい。
filterには、releasesに存在するPayloadの情報を使用します。

```json
{"webhook": 
  {"name": "上記コマンドの結果からコピー",
   "targetPipeline": "上記コマンドの結果からコピー",
   "targetAction": "上記コマンドの結果からコピー(多分Sourceのハズ)",
   "filters": [
    {
      "jsonPath": "$.action", 
      "matchEquals": "published"
    }
   ],
   "authentication": "GITHUB_HMAC",
   "authenticationConfiguration": {"SecretToken":"上記コマンドの結果からコピー"}
  }
}
```

作成したファイルを使用してwebhookを更新します。
例ではコマンドを実行しているディレクトリにwebhook_config.jsonがあることを想定してます。

```bash

aws codepipeline put-webhook --cli-input-json file://webhook_config.json --region "ap-northeast-1"
```

## 動作確認

GitHubで実際にリリースしてみます。
GitHubのWebhook発火設定と、filterの更新がうまく行っていればCodePipelineが発火するはずです。


# あとがき

この方法を使えばfilterさえ適切にイジればGitHubのあらゆるアクションでCodePipelineを発火できるようになります。別にApiGatewayやらLambdaやらで、自前でWebhookを受け付ける機構を作ればいくらでも迂回は出来るんですが、それだけのためにいろんなサービスにちょこっとずつCodePipeline連携のための仕組みが乗っかるのはなんか気持ち悪いので…

あと、CLIでしかできない操作を含んでいるので、大きなチームで作業してるときはドキュメント残すなりで用法用量を守って安全運転お願いします。