CodeCommitにcommit/pushしたらLambda経由でSlackにcommentつき通知を飛ばす

AWS CodeCommit上で管理しているリポジトリに、誰かがcommit/pushしたらSlackで通知を受け取りたいと思って試行錯誤したときのメモになります。Lambda関数はNode.jsで記述しています。

# スクリーンショット

<img width="300px" alt="screenshot.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556119/76d193ae-5005-a808-e64f-df1a12bc1973.jpeg">

※ アイコンとCodeCommitの太字はSlack Incomming Webhookのカスタマイズで変更しています。

# 前置き

* CodeCommitやLambda、Slackの細かい話は書きません。
* Lambda関数のNode.jsのサンプルコードや注意点だけを書きます。
* 以下はすべてAWS Console上からの操作です。

# 処理の流れ

CodeCommit → トリガー → Lambda → Slack Incomming WebhookのURLにPOST → Slackからスマホアプリ等に通知が飛ぶ

# Lambda関数

適当な名前でLambda関数を作成します。以下のサンプルコードをindex.jsに上書きします。`options`のIncomming WebhookのURLと、中程にあるSlack上に表示するメッセージのBlock Kitテンプレートはお好みに合わせて修正します。

```js:codeCommitToSlackWebhook
const AWS = require('aws-sdk');
const codecommit = new AWS.CodeCommit({
	region: 'ap-northeast-1'
});
const https = require('https');
//const util = require("util");
const options = {
	hostname: 'hooks.slack.com',
	path: '/services/*******/*******/*******',
	method: 'POST',
	headers: {
		"Accept" : "application/json",
		"Content-Type" : "application/json; charset=UTF-8"
	}
};

exports.handler = function(event, context) {
	let repository = event.Records[0].eventSourceARN.split(":")[5];
	let references = event.Records[0].codecommit.references;
	let funcArr = references.map((x) => {
		return new Promise((resolve,reject) => {
			let params = {
				commitId: x.commit,
				repositoryName: repository
			};
			codecommit.getCommit(params, function(err, data) {
				if (err) reject(err);
				else resolve({params:params,data:data});
			});
		});
	});
	Promise.all(funcArr)
		.then((values) => {
			//console.log(util.inspect({
			//	values:values
			//},{colors:true, depth: null}));
			return new Promise((resolve,reject) => {
				let blocks = [];
				blocks.push({
					type: 'section',
					text: {
						type: 'mrkdwn',
						text: `new commit pushed to \`${references[0].ref}\`\n\n*Repository:* "${repository}"`,
					}
				});
				let v = values.map((x) => {
					let tmp = new Date(x.data.commit.committer.date.split(' ')[0]*1000);
					tmp = `${tmp.getFullYear()}/${('0'+(tmp.getMonth()+1)).slice(-2)}/${('0'+tmp.getDate()).slice(-2)} ${('0'+tmp.getHours()).slice(-2)}:${('0'+tmp.getMinutes()).slice(-2)}:${('0'+tmp.getSeconds()).slice(-2)}`;
					return {
						type: 'section',
						fields: [
							{
								type: 'mrkdwn',
								text: '*CommitId:*\n'+x.params.commitId
							},
							{
								type: 'mrkdwn',
								text: '*Comment:*\n'+x.data.commit.message
							},
							{
								type: 'mrkdwn',
								text: '*Committer:*\n'+x.data.commit.committer.name
							},
							{
								type: 'mrkdwn',
								text: '*When:*\n'+tmp
							}
						]
					};
				});
				values = {blocks:blocks.concat(v)};
				resolve(values);
			});
		}).then((value) => {
			//console.log(util.inspect({
			//	value:value
			//},{colors:true, depth: null}));
			let req = https.request(options, (res) => {
				let body = '';
				//console.log('statusCode: '+res.statusCode);
				res.setEncoding('utf8');
				res.on('data', (chunk) => {
					body += chunk;
				});
				res.on('end',() => {
					//console.log({body:body});
					context.done(null,body);
				});
			});
			req.on('error',(e) => {
				//console.log({e:e});
				context.fail(e);
			});
			req.write(JSON.stringify(value));
			req.end();
		}).catch((err) => {
			//console.log({err:err});
			context.fail(err);
		});
};
```
# Lambdaのアクセス権限

1. Lambda アクセス権 → 実行ロール → IAMロールの設定が別ウィンドウで開く
1. 「ポリシーをアタッチします」で`AWSCodeCommitReadOnly`をアタッチ

# Lambdaのトリガー

1. Lambda 設定 → デザイナー → トリガーの追加
1. トリガーの設定 → `CodeCommit`を選択
1. リポジトリ名選択、トリガー名に`slackWebhookTrigger`など入力、ブランチ名をすべてのブランチを選択
1. 追加

# 通知のテスト

1. CodeCommit リポジトリ選択
1. 設定 → トリガー → `slackWebhookTrigger`などトリガー名のリンク
1. ページ下部 → トリガーのテスト

# Lambdaの注意点

環境変数を設定しないと通知内容に含まれる時刻がUTCになってしまいます。以下を設定します。

* Lambda 設定 → 環境変数 → キー: `TZ`、値: `Asia/Tokyo`を追加

# デバッグ

Lambda関数内のconsole.logのコメントアウトを外し、CloudWatch Logsでどこでエラーが発生しているか確認します。

# 参考URL

例: AWS Lambda 関数の AWS CodeCommit トリガーを作成する
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/how-to-notify-lambda.html

以上です。