CodePipelineからSlackに通知する整理

# 参考リンク

1. [ひたすら楽してCodePipelineのイベントをslackに通知する ｜ DevelopersIO](https://dev.classmethod.jp/cloud/aws/notify-codepipeline-events-to-slack/)
2. [AWS のリソースを監視して Slack に通知する方法 (または cloudwatch-alarm-to-slack の使い方) - Qiita](https://qiita.com/megane42/items/bfba43d6a04727b02b1d)

# 手順

参考リンクに従った結果、微妙に異なる状況だったので整理

## 1. Incoming webhookをつくる
Slack管理画面で登録する

## 2. KMSでキー発行

以下など実行して発行。出力の"KeyId"を記録

```
aws kms create-key --description "codepipeline-slack"
```

## 3. Serverless Application Repositoryでアプリ作成

参考リンク2と同様に**"cloudwatch-alarm-to-slack"**という雛形を選択。
こちらはNode.js版で、参考リンク1ではpython版を使ってる。中身はたぶんほぼ同等。

参考リンク2にあるように、環境変数まわりがバグってるっぽいのでいったんkmsEncryptedHookUrlParameterとslackChannelParameterは適当な値を入れて登録する。

参考リンク2にある[鍵のユーザーを設定する](https://qiita.com/megane42/items/bfba43d6a04727b02b1d#%E9%8D%B5%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)は必要なかった。

参考リンク2の[環境変数を設定](https://qiita.com/megane42/items/bfba43d6a04727b02b1d#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92%E8%A8%AD%E5%AE%9A)のように設定する。

## 4. Lambda Functionを編集する

CodePipelineのイベント用に編集する。

参考リンク1をjsにすると以下

```js
function processEvent(event, callback) {
    const message = JSON.parse(event.Records[0].Sns.Message);

    const region = message.region
    const pipelineName = message.detail.pipeline
    const stageName = message.detail.stage
    const state = message.detail.state

    const slackMessage = {
        channel: slackChannel,
        text: `State ${stageName} (Pipeline ${pipelineName}) is now ${state} : https://${region}.console.aws.amazon.com/codepipeline/home?region=${region}#/view/${pipelineName}`,
    };

    postMessage(slackMessage, (response) => {
        if (response.statusCode < 400) {
            console.info('Message posted successfully');
            callback(null);
        } else if (response.statusCode < 500) {
            console.error(`Error posting message to Slack API: ${response.statusCode} - ${response.statusMessage}`);
            callback(null);  // Don't retry because the error is due to a problem with the request
        } else {
            // Let Lambda retry
            callback(`Server error when processing message: ${response.statusCode} - ${response.statusMessage}`);
        }
    });
}
```

attachmentを利用してもうちょっと見やすくすると以下など

```js
const stateColor = {
    'STARTED': '#e0e0e0',
    'SUCCEEDED': '#2196f3',
    'FAILED': '#f44336'
}

function processEvent(event, callback) {
    const message = JSON.parse(event.Records[0].Sns.Message);

    const region = message.region
    const pipelineName = message.detail.pipeline
    const stageName = message.detail.stage
    const state = message.detail.state
    const exeId = message.detail['execution-id']
    
    const attachment = {
        title: `${state} ${stageName} on ${pipelineName}`,
        title_link: `https://${region}.console.aws.amazon.com/codepipeline/home?region=${region}#/view/${pipelineName}`,
        color: stateColor[state],
        fields: [
            {
                title: "Execution ID",
                value: exeId,
                short: false
            }
        ]
    }

    const slackMessage = {
        channel: slackChannel,
        attachments: [attachment]
    };

    postMessage(slackMessage, (response) => {
        if (response.statusCode < 400) {
            console.info('Message posted successfully');
            callback(null);
        } else if (response.statusCode < 500) {
            console.error(`Error posting message to Slack API: ${response.statusCode} - ${response.statusMessage}`);
            callback(null);  // Don't retry because the error is due to a problem with the request
        } else {
            // Let Lambda retry
            callback(`Server error when processing message: ${response.statusCode} - ${response.statusMessage}`);
        }
    });
}
```

## 5. CloudWatchイベントルール作成

参考リンク1のように登録する