Cloud BuildをGitHubと連携させて、ビルド結果をSlackで通知する。

Cloud BuildがGitHubと連携できるようになっていたので、セットアップからSlack通知までの構築を試してみた。
Cloud Functionsのソースは[GitHub](https://github.com/hako1912/cloud-build-notification-slack)にもあげてます。

## 前提条件

- gcloudがインストールされていること

## Cloud BuildのGitHubアプリをインストールする

次のURLに行き、Cloud BuildのGitHubアプリを自分のGitHubアカウントにインストールする。
https://github.com/apps/google-cloud-build
インストールするとリポジトリの選択画面に遷移するので、好きなリポジトリまたはすべてのリポジトリを選択する。  
これで、選択したリポジトリをpushすると自動でCloud Buildが動くようになる。

対象のリポジトリをあとから変更したいときは次のURLから`Google Cloud Build`を選択し、`Repository access -> Save`をクリックする。
https://github.com/settings/installations/

## Slack通知用のCloud Functionを作る

新しいディレクトリを作って、その中に次のファイルを作る。

```json:package.json
{
    "name": "cloud-build-notification",
    "version": "0.0.1",
    "description": "Slack integration for Google Cloud Build, using Google Cloud Functions",
    "main": "index.js",
    "dependencies": {
        "@slack/client": "3.9.0"
    }
}
```

```javascript:index.js
const IncomingWebhook = require('@slack/client').IncomingWebhook;
const webhook = new IncomingWebhook(process.env.SLACK_WEBHOOK_URL);

// subscribe is the main function called by Cloud Functions.
module.exports.subscribe = (event, callback) => {
    const build = eventToBuild(event.data);

    // Skip if the current status is not in the status list.
    // Add additional statues to list if you'd like:
    // QUEUED, WORKING, SUCCESS, FAILURE,
    // INTERNAL_ERROR, TIMEOUT, CANCELLED
    const status = ['SUCCESS', 'FAILURE', 'INTERNAL_ERROR', 'TIMEOUT'];
    if (status.indexOf(build.status) === -1) {
        return callback();
    }

    // Send message to Slack.
    const message = createSlackMessage(build);
    webhook.send(message, callback);
};

// eventToBuild transforms pubsub event message to a build object.
const eventToBuild = (data) => {
    return JSON.parse(new Buffer(data, 'base64').toString());
}

// createSlackMessage creates a message from a build object.
const createSlackMessage = (build) => {
    let message = {
        text: `Build \`${build.id}\``,
        mrkdwn: true,
        attachments: [
            {
                title: 'Build logs',
                title_link: build.logUrl,
                fields: [{
                    title: 'Status',
                    value: build.status
                }, {
                    title: 'Branch',
                    value: build.substitutions.BRANCH_NAME
                }, {
                    title: 'Repository',
                    value: build.substitutions.REPO_NAME
                }]
            }
        ]
    };
    return message
}
```
参考:
https://cloud.google.com/cloud-build/docs/configure-third-party-notifications?hl=ja

## 作ったCloud Functionをデプロイする

デプロイする前にCloud Function用のCloud Storageを作る必要がある。
バケット名は世界中でユニークでないといけないので気をつける。
SlackのWebhook URLは[ココ](https://api.slack.com/apps?new_app=1)で新しいアプリを作成したあと、`Incoming Webhooks`から生成できる。

```bash
# ストレージバケットを作成する
BUCKET='<your storage bucket name>'
gsutil mb gs://$BUCKET

# Cloud Functionをデプロイする
SLACK_WEBHOOK_URL='<your webhook url>'
gcloud functions deploy cloud-build-notification-slack \
    --stage-bucket $BUCKET \
    --entry-point subscribe \
    --trigger-topic cloud-builds \
    --runtime nodejs8 \
    --set-env-vars SLACK_WEBHOOK_URL=$SLACK_WEBHOOK_URL
```

## リポジトリをpushして動作確認してみる

Cloud Buildは`cloudbuild.yaml`をビルド構成ファイルとして書くこともできるし、`cloudbuild.yaml`を書かなくてもDockerfileだけ置いておけばDockerイメージをビルドしてContainer Registryに保存するタスクが自動的に実行される。

今回はとりあえずシンプルにDockerfileでCIを動かしてみる。

GitHubアプリで設定した好きなリポジトリで`Dockerfile`を書いて、pushする。

```dockerfile
FROM alpine:3.9
RUN echo 'Hello world.'
```

うまく行っていれば、CIが動いてDockerイメージがContainer Registryに保存され、Slackにビルド結果の通知がくる。ちなみに、Container Registryに保存されるイメージ名は`gcr.io/<プロジェクトID>/<リポジトリ名>`になる。

<img width="467" alt="スクリーンショット 2019-08-14 17.12.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211828/448d2997-6d9f-88d0-975d-1e65dc047646.png">
できた！！

## おまけ

Cloud ConsoleからGUIで確認もできるけどCLIで確認したいときに。

Cloud Buildのビルド一覧を取得する。

```bash
gcloud builds list
```

Container Registryにあるイメージ一覧を取得する。

```bash
gcloud container images list
```

## 参考

https://medium.com/google-cloud-jp/try-github-cloudbuild-integration-5149175105fb