Amazon API Gateway+AWS Lambdaを利用してGitBucketのイベントをChatWorkに通知する

# はじめに

GitBucketの新着イベントをChatWorkに通知するため、Amazon API Gateway+AWS Lambdaを利用してサーバーレスに連携する仕組みを実装した。
https://github.com/tokada/gitbucket-chatwork

ここではAWS環境の設定を含めた手順を記載する。

## 関数パッケージの準備

https://github.com/tokada/gitbucket-chatwork からコードを取得し、ローカルでnpmパッケージを含めたzipファイルを作成する。

```
git clone https://github.com/tokada/gitbucket-chatwork.git
cd gitbucket-chatwork
npm install request ejs
zip -r gitbucket-chatwork.zip *
```

# AWS環境の設定手順

## Lambda関数の作成

「AWS Lambda > 関数の作成」 から、以下のように関数を作成する。

<img width="627" alt="2017-12-5_21-0-55_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/04763ef2-d1b6-fb8e-5453-7d912caf2b16.png">

- 名前
  - 任意（postChatWorkMessageなど）
- ランタイム
  - Node.js 6.10
- ロール
  - Lambda用のロールがない場合は、「Basic Edge Lambda アクセス権限」を付与したロールを作成する

## Lambda関数コードの設定

### 関数コード

ローカルで作成した「gitbucket-chatwork.zip」をアップロードして関数コードを作成する。

<img width="817" alt="2017-12-5_21-8-26_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/d55ec8c4-937f-02b1-c36c-130160ea7bdb.png">

- コード エントリ タイプ
  - .ZIPファイルをアップロード
- ランタイム
  - Node.js 6.10
- ハンドラ
  - index.handler（デフォルト値）
- 関数パッケージ
  - ファイルダイアログで gitbucket-chatwork.zip を選択

### 環境変数

環境変数CHATWORK_TOKEN（ChatWorkのAPIキー）とCHATWORK_ROOM_ID（/#!ridNNNNNNNNで示される投稿先の部屋ID）を設定する。

<img width="820" alt="2017-12-5_21-13-23_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/1bf7c2ff-7ae9-423b-1c5a-2932a7d55c64.png">

### 関数コードの確認

「保存」をクリックすると設定が保存される。

関数コードのコードエントリタイプを「コードをインラインで編集」に切り替えると、アップロードされたコードを確認、編集することができる。

<img width="818" alt="2017-12-5_21-16-51_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/f548429d-bbdb-1733-eeed-96ea6baf3027.png">

## Lambda関数コードのテスト

「テストイベントの設定」から、GitBucketのPushイベントを再現するテストイベントを作成する。

<img width="628" alt="2017-12-5_21-24-0_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/b23a54bf-08a0-7470-9e07-d8cec01f3d53.png">

作成例

- イベント名
  - myPushEvent
- ペイロード

```
{
  "httpMethod": "POST",
  "headers": null,
  "queryStringParameters": null,
  "pathParameters": null,
  "stageVariables": null,
  "body": "{\"pusher\":{\"name\":\"myname\",\"email\":\"myname@example.com\"},\"sender\":{\"login\":\"myname\",\"email\":\"myname@example.com\",\"type\":\"User\",\"site_admin\":true,\"created_at\":\"2015-07-22T21:27:26Z\",\"url\":\"http://gitbucket:8080/api/v3/users/myname\",\"html_url\":\"http://gitbucket:8080/myname\",\"avatar_url\":\"http://gitbucket:8080/myname/_avatar\"},\"ref\":\"refs/heads/master\",\"before\":\"ccc0e52c82bf666e2920c44e7b5ffc13b11d5948\",\"after\":\"4d3671004ed03ab75dd3396c55313d36b57e2bbb\",\"commits\":[{\"id\":\"4d3671004ed03ab75dd3396c55313d36b57e2bbb\",\"message\":\"\\\"テスト\\\"<pre>myrepos</pre>\\n\",\"timestamp\":\"2017-12-05T06:42:03Z\",\"added\":[],\"removed\":[],\"modified\":[\"README.md\"],\"author\":{\"name\":\"myname\",\"email\":\"myname@example.com\",\"date\":\"2017-12-05T06:42:03Z\"},\"committer\":{\"name\":\"myname\",\"email\":\"myname@example.com\",\"date\":\"2017-12-05T06:42:03Z\"},\"url\":\"http://gitbucket:8080/myname/myrepos/commit/4d3671004ed03ab75dd3396c55313d36b57e2bbb\"}],\"repository\":{\"name\":\"myrepos\",\"full_name\":\"myname/myrepos\",\"description\":\"\",\"watchers\":0,\"forks\":0,\"private\":true,\"default_branch\":\"master\",\"owner\":{\"login\":\"myname\",\"email\":\"myname@example.com\",\"type\":\"User\",\"site_admin\":true,\"created_at\":\"2015-07-22T21:27:26Z\",\"url\":\"http://gitbucket:8080/api/v3/users/myname\",\"html_url\":\"http://gitbucket:8080/myname\",\"avatar_url\":\"http://gitbucket:8080/myname/_avatar\"},\"forks_count\":0,\"watchers_count\":0,\"url\":\"http://gitbucket:8080/myname/myrepos\",\"http_url\":\"http://gitbucket:8080/git/myname/myrepos.git\",\"clone_url\":\"http://gitbucket:8080/git/myname/myrepos.git\",\"html_url\":\"http://gitbucket:8080/myname/myrepos\"},\"compare\":\"http://gitbucket:8080/myname/myrepos/commit/4d3671004ed03ab75dd3396c55313d36b57e2bbb\",\"head_commit\":{\"id\":\"4d3671004ed03ab75dd3396c55313d36b57e2bbb\",\"message\":\"\\\"テスト\\\"<pre>myrepos</pre>\\n\",\"timestamp\":\"2017-12-05T06:42:03Z\",\"added\":[],\"removed\":[],\"modified\":[\"README.md\"],\"author\":{\"name\":\"myname\",\"email\":\"myname@example.com\",\"date\":\"2017-12-05T06:42:03Z\"},\"committer\":{\"name\":\"myname\",\"email\":\"myname@example.com\",\"date\":\"2017-12-05T06:42:03Z\"},\"url\":\"http://gitbucket:8080/myname/myrepos/commit/4d3671004ed03ab75dd3396c55313d36b57e2bbb\"}}",
  "isBase64Encoded": false
}
```
ここで、ペイロードには後述のAmazon API Gateway Lambda統合プロキシから送られる形式で値が設定されている。
bodyには、元のGitBucket Webhooksで送信されるPushEventのapplication/json形式リクエストペイロードが文字列にエンコードされている。

テストイベント作成後、「テスト」をクリックすると、環境変数で設定されたChatWorkの部屋にテストメッセージが投稿され、実行結果が成功で返ればOK。

<img width="762" alt="2017-12-5_21-32-59_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/61d265bb-cdb8-7ff2-a43b-4be6708ad692.png">

<img width="1163" alt="2017-12-5_21-31-0_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/ed9ee051-97d4-fa2a-417b-074f7ad75679.png">

## APIの作成（Amazon API Gateway）

GitBucketのOutgoing WebHookで利用するAPIを作成する。

### APIの作成

Amazon API Gatewayから適当な名前でAPIを作成する。

<img width="675" alt="2017-12-5_21-59-31_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/1374bce7-471d-b3ee-a63a-4b8f72ce5fcd.png">

### リソースの作成

作成したAPIの「アクション」→「リソースの作成」から、適当な名前でリソースを作成する。

<img width="586" alt="2017-12-5_22-3-37_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/b49d3ab3-6f67-a872-bfdf-8e0e0a7d9050.png">

### メソッドの作成

作成したリソースに対して「アクション」→「メソッドの作成」からPOSTメソッドを作成し、Lambdaプロキシ統合として設定する。

<img width="741" alt="2017-12-5_22-5-16_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/9afe2d80-f464-5852-8279-00be8ed503ed.png">

- 統合タイプ
    - Lambda関数
- Lambdaプロキシ統合の使用
    - ONにする
- Lambdaリージョン
    - Lambda関数を作成したリージョン
- Lambda関数
    - 作成したLambda関数名を入力する
- デフォルトタイムアウトの使用
    - ONにする

「保存」をクリックすると、指定のLambda関数にリクエスト情報をプロキシするAPIメソッドが作成される。（統合リクエストのタイプがLAMBDA_PROXY）

<img width="913" alt="2017-12-5_22-22-26_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/bf008f53-87e4-747b-f2c9-916bf5cfc342.png">

## APIのテスト

左側の「テスト⚡」をクリックし、リクエスト本文に[Pushイベントのサンプルペイロード](https://github.com/tokada/gitbucket-chatwork/blob/master/test/payloads/push.json)を入力して「⚡テスト」をクリックする。

<img width="294" alt="2017-12-5_22-53-40_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/4db23515-692e-8780-bc54-3fb915f4b216.png">

ChatWorkにサンプルペイロードの内容が投稿され、200レスポンスが返ればOK。

<img width="762" alt="2017-12-5_21-32-59_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/fbe0e217-e2ba-0278-768f-4d569d939607.png">

<img width="414" alt="2017-12-5_22-56-34_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/fbd98a66-6fdb-001f-59c5-1158cf1112f6.png">

## APIのデプロイ

「アクション」から「APIのデプロイ」を選択し、「新しいステージ」からステージ名（dev, staging, prodなど）を設定してAPIをデプロイする。

<img width="456" alt="2017-12-5_22-59-55_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/973513b1-611a-b0c5-b93b-59bc63f99c65.png">

ステージ名を開いてリソース名「/chatwork-message」メソッド名「POST」を開くとAPIエンドポイントURLが確認できる。このURLをGitBucket側でリポジトリのWebhookに設定する。

<img width="932" alt="2017-12-5_23-2-59_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/227f16c3-e42a-2a8f-b198-df7ccfa72941.png">

## GitBucket Webhookの設定

GitBucketでリポジトリの「Settings」→「Service Hooks」→「Add Webhook」からWebhookを設定する。

<img width="769" alt="2017-12-5_23-7-22_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/22485/be78cacc-3476-6bda-fb5d-21eabcf9c381.png">

- Payload URL
    - 上記のAPIエンドポイント
- Content type
    - application/json を選択
- Security Token
    - 空欄
- Which events would you like to trigger this webhook?
    - 通知対象とするイベントを選択する

## 動作確認

該当のGitBucketリポジトリで操作を行い、ChatWorkにイベントが通知されることを確認する。

## その他

GitBucketのAPIはGitHub APIのサブセットとなっており下位互換性があるので、GitHubとの連携でも問題なく使えるはず？（未確認）

## 参考リンク

- [LambdaからChatworkにメッセージを投稿 - Qiita](https://qiita.com/tenbo07/items/5c7da35c7d0984b5350a)
- [Amazon API Gatewayが非常に便利なHTTPプロキシとして進化したらしいので使ってみた - Qiita](https://qiita.com/seiya_orz/items/4e9d8c62739399b076b7)
- [AWS Lambda Proxy Integrationを試してみた - Qiita](https://qiita.com/seiya_orz/items/2bd83204e212e35b2c6c)