Lambda関数(Go)でSlack通知

## はじめに
CICDの一環でGoのLambdaからSlack通知をする仕組みを構築したのでその備忘録を残す。
（CICDという事でリリース作業を想定したSlack通知を作ってみた。また、[AWS ChatbotでSlackからLambda関数(Go)を呼び出す](https://qiita.com/yuta-katayama-23/items/da16e8760bec47d7fd26)の続きで構築した。）

https://github.com/yuta-katayama-23/Go/commit/bcdea5c74a439b1d64e1defe4cec1d30497baba6

## Lambdaの実装
今回はhttp POSTを自分でやるのではなく、[slack-go（Slack API）](https://github.com/slack-go/slack)を利用する

### Slack Appの作成・Tokenの発行
`slack-go`を使うにあたってはSlack Appと認証のためのTokenが必要になるので、それらを作成・発行する
そのやり方は[こちら](https://qiita.com/kou_pg_0131/items/56dd81f2f4716ca292ef)が分かりやすいのでそれを参照

### slack-goのclientを使って通知の実装
`github.com/slack-go/slack`を依存関係に加える（importする）

```
go get package github.com/slack-go/slack
```

コマンドの実行により、`go.mod`と`go.sum`にそれぞれ依存関係が追記される
※`go.mod(Go Modules)`を利用せず、GOPATHモード(go getしたものが$GOPATH/srcに入りそれを参照する)の方式の場合は、`go get github.com/slack-go/slack`

```golang
package main

import (
   // 省略
   "fmt"
   "os"
   "strings"
   "github.com/slack-go/slack"
)

var Config = struct {
	// 省略
}{}

type Event struct {
	// 省略
}

func HandleRequest(ctx context.Context, event Event) (string, error) {
	configor.Load(&Config, "config.yaml")

	// 省略

	res, err := slackNotification(event)
	fmt.Println("res", res)
	fmt.Println("err", err)

	return fmt.Sprintf("Module %s", event.Modules), nil
}

func slackNotification(event Event) (string, error) {
	client := slack.New(os.Getenv("SLACK_API_TOKEN"))

	headerText := slack.NewTextBlockObject("mrkdwn", "<!channel>\nこれより *"+event.TargetEnv+"環境* リリース作業を実施致します。\n完了後、通知致します。", false, false)
	headerSection := slack.NewSectionBlock(headerText, nil, nil)

	complete := slack.NewTextBlockObject("mrkdwn", "*完了予定*\n15分", false, false)
	target := slack.NewTextBlockObject("mrkdwn", "*対象環境*\n"+event.TargetEnv, false, false)
	module := slack.NewTextBlockObject("mrkdwn", "*対象サービス*\n"+strings.Join(event.Modules, ", "), false, false)
	fieldSlice := make([]*slack.TextBlockObject, 0)
	fieldSlice = append(fieldSlice, complete)
	fieldSlice = append(fieldSlice, target)
	fieldSlice = append(fieldSlice, module)
	fieldsSection := slack.NewSectionBlock(nil, fieldSlice, nil)

	_, _, err := client.PostMessage(os.Getenv("SLACK_CHANNEL"), slack.MsgOptionBlocks(headerSection, fieldsSection))
	if err != nil {
		fmt.Printf("%s\n", err)
		return fmt.Sprintf("Fail slack notification\nError message is \"%s\"", err), nil
	}
	return "Success slack notification", nil
}

func main() {
	lambda.Start(HandleRequest)
}
```

ソースコード全体は[はじめに](#はじめに)を参照
Slackのメッセージを作るにあたって参考になるのは以下

- https://github.com/slack-go/slack/tree/master/examples<br>slack-goでのメッセージの例が載っている
- [Formatting text for app surfaces](https://api.slack.com/reference/surfaces/formatting)<br>Slack公式のメッセージ内容をどういう風に作るか書かれている<br>メンションの仕方については[ここ](https://api.slack.com/reference/surfaces/formatting#special-mentions)

`os.Getenv(・・・)`は環境変数でLambdaの「設定＞環境変数」に以下のように設定している
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/0eca3c89-57ef-dd52-ad76-64be4def7fb3.png)

実際にSlackに通知されたメッセージは以下のようになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/88825307-4910-6586-01db-22ba38e36eaf.png)

## 参考文献
- [【Go】slack-go を使用して Slack API を叩く](https://zenn.dev/kou_pg_0131/articles/slack-go-usage)