Amplifyのデプロイ通知をSlackに通知する

Slack, Lambda, sns, amplify
2019-07-10

amplifyでdeploy完了時、メールで通知することができるが、 いちいちメールが飛んでくるのが結構邪魔になるのでそのイベントを Slackに通知するようにしたい。

具体的にはAWS AmplifyのEmail notificationsを設定するとそのメールをもとにAWSのSNSが設定されるので その設定に相乗りする形でLambdaを使ってSlackに通知を送るというものです。

SlackのIncoming WebHooksを作成

https://[YOUR_ORG].slack.com/apps から Incoming WebHooksを検索し、アプリを追加します。

新規のIncoming WebHooksを追加し、Webhook URLが発行されます。 Customize Name、Icon等は呼び出し時に上書きするでデフォルトのままで良いです。

AWS Lambdaを作成

SNSから送信されたメッセージをSlackのwebhookに送信する処理をNode.jsを使って記述します。

An image from Notion

SNSからLambdaが起動されるとき、 第一引数のeventの中身は以下のようなオブジェクトになっているので、 Sns.Messageの部分をうまくパースして各状態(開始、成功、失敗)の値を取り出します。

// eventの中身
{
  Records: [
    {
       EventSource: 'aws:sns',
       EventVersion: '1.0',
       EventSubscriptionArn: 'arn:aws:sns:ap-northeast-1:...',
       Sns: {
         Type: 'Notification',
         MessageId: '5d6ef129-e0b3....',
         TopicArn: 'arn:aws:sns:ap-northeast-1:....',
         Subject: null,
         Message: '"Build notification from the AWS Amplify Console for app: https://... Your build status is STARTED. Go to ..."',
         Timestamp: '2019-07-09T10:41:43.599Z',
         SignatureVersion: '1',
         Signature: 'MwvX3GHzK...',
         SigningCertUrl: '<https://sns.ap-northeast-1.amazonaws.com/xx.pem>',
         UnsubscribeUrl: '<https://sns.ap-northeast-1.amazonaws.com/>...',
         MessageAttributes: {}
      }
    }
  ]
}

Lambdaの関数は以下のようなします。

const https = require('https');
const AMPLIFY_STAT = {
  STARTED: 'STARTED',
  SUCCEED: 'SUCCEED',
  FAILED: 'FAILED'
};

/**
 * snsから送られてくるメッセージをparse
 */
const parseSnsMessage = (event) => {

  if (!event.Records && Array.isArray(event.Records)) {
    return {
      text: 'deploy failed!(parse failed)'
    };
  }

  if (!event.Records[0].Sns && !event.Records[0].Sns.Message) {
    return {
      text: 'deploy failed!(parse failed)'
    };
  }

  const msg = event.Records[0].Sns.Message;
  const mathcher = msg.match(/Your build status is (\\w+)./);

  let text = '';
  if (mathcher) {
    const stat = mathcher[1];
    switch (stat) {
      case AMPLIFY_STAT.STARTED:
        text = 'deploy started...';
        break;
      case AMPLIFY_STAT.SUCCEED:
        text = 'deploy succeed!';
        break;
      default:
        text = 'deploy failed!';
    }
  }

  return {
    text
  };
};

exports.handler = async(event) => {
  const { text } = parseSnsMessage(event);
  // slackのincoming hookへ送信
  const data = JSON.stringify({
    channel: '#playground',
    username: 'amplify-deploy-state',
    text,
    icon_emoji: ':smirk_cat:'
  });

  const options = {
    hostname: 'hooks.slack.com',
    port: 443,
    path: '/services/xxxx/xxxx/xxxx', // ここにwebhookのURLを設定します。
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': data.length
    }
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      res.on('data', (d) => {
        resolve({ statusCode: res.statusCode });
      });
    });

    req.on('error', (error) => {
      console.error(error);
      reject(error);
    });
    req.write(data);
    req.end();
  });
};

Lambdaの関数をテストする際はtemplateにAmazon SNS Topic Notificationがあるのでそれを利用すると便利です。

An image from Notion

SNSにLambdaを追加する

冒頭で説明した通り、Amplifyでメール通知を設定した場合、snsのtopicがつかされているのでそれを参照します。

An image from Notion

Create subscriptionから新しいSubscriptionを作成します。

An image from Notion

ProtocolにAWS Lambdaを、Endpointに先程作成したLambda関数を指定します。

通知テスト

AWS Amplifyのコンソールからredeploy等を実行すると。 通知がslackに来ることが確認できます。

An image from Notion

確認ができたらSNSについている、Emailの方のSubscriptionは削除してもらって問題ないと思います。(もし必要になったら再度つければいいと思います)

Reference

Written by Kyohei Tsukuda who lives and works in Tokyo 🇯🇵 , building useful things 🔧.