Cloud Buildは同じGCP製品だけあって非常にシンプルにFirebase(WEBしかやったことない)のデプロイを行えますが、ビルド成功、失敗時の通知機能はついてません。
Circle CIのように標準ではついていないので、下記の公式ドキュメントのように自分でFunctionsの関数作って行うのが一般的のようです。
https://cloud.google.com/cloud-build/docs/configure-third-party-notifications?hl=ja
でも今回はFirebaseを使ったプロジェクトだったため、Firebase Functions + TypeScriptで行いたいのでTypeScriptの勉強も兼ねて作ってみました。
Firebaseのプロジェクトについては省略
Cloud Functions に TypeScript を使用する | Firebase
公式のと違う点は、終了時にビルドにかかった時間を知りたかったので追加した点。
メッセージは面倒だったのでただのテキストにしてます。
Webook URL
Slack側でWebhookのURLを発行します。
slack.com
発行したURLはFirebaseなのでprocess.envは使わずconfigを使って格納しています。
詳しくは下記
環境の構成 | Firebase
事前に下記のコマンドでセットしておきます。
firebase functions:config:set slack.webhook_url="https://hooks.slack.com/services/***/***/***"
必要なパッケージ
slackの他、ビルド時間を計算するためにdate-fnsを使用しているのでインストールします。
npm install @slack/webhook date-fns
ソース
まだいろいろ改善の余地があるけど動いたやつ。
WORKINGはQUEUEDの後にすぐ来るのでスキップしてます。
swich文やめようかな。
slack.ts
import { pubsub, config } from 'firebase-functions' import { IncomingWebhook } from '@slack/webhook' import { differenceInSeconds, parseISO } from 'date-fns' const WEBHOOK_URL = config().slack.webhook_url const webhook = new IncomingWebhook(WEBHOOK_URL) function createMessage (data: any): string { const status = data.status const repoName = data.substitutions?.REPO_NAME const startTime = data.startTime const finishTime = data.finishTime const buildSeconds = differenceInSeconds(parseISO(finishTime), parseISO(startTime)) const logUrl = data.logUrl switch (status) { case 'QUEUED': return `${status}, repo: ${repoName}` case 'SUCCESS': case 'FAILURE': case 'INTERNAL_ERROR': case 'TIMEOUT': case 'CANCELLED': return `${status}, repo: ${repoName}, buildtime: ${Math.floor(buildSeconds / 60)}min ${buildSeconds % 60}sec \n${logUrl}` case 'WORKING': default: return '' } } export async function notifySlack (message: pubsub.Message): Promise<void> { const body = message.data ? Buffer.from(message.data, 'base64').toString() : null if (!body) { console.log('body is null') return } const data = JSON.parse(body) const text = createMessage(data) if (!text) { console.log(`${data.status} skipped`) return } await webhook.send({ text: text }) }
↑notifySlackをindex.tsで読み込んでonPublish()に渡します。
topic名'cloud-builds'はCloud Buildを有効にすると勝手にできるやつなので変えることはなさそうなので直書きしてます。
index.tsの抜粋
import { pubsub } from 'firebase-functions' import { notifySlack } from './slack' //ほかのやつ export const notifyBuild = pubsub.topic('cloud-builds').onPublish(notifySlack)
できたやつ
こんな感じで通知が来るようになりました
プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発
- 作者:Boris Cherny
- 発売日: 2020/03/16
- メディア: 単行本(ソフトカバー)