はじめに
LINE NotifyでCodeCommitへのコミット時の通知をカスタムメッセージでLINEグループに送信するよう設定してみました。業務ではLINEを使う機会がほぼないですが、個人開発時にはLINE通知の方が色々と便利だと思って、導入してみたというのがきっかけでした。
やりたいこと
構成は非常にシンプルです。
- CodeCommitにコードをpushする
- コミット通知がSNS経由でLambdaに送信される
- Lambda関数でユーザーのLINE Notifyトークンを使い、コミット情報をnotify-apiのエンドポイントにpostリクエストを送信する
- コミット情報がLINE Notifyの公式アカウントによって、特定のLINEグループに送信される
ちなみに、以前LINEグループにメッセージを送信する際にMessaging APIを使っていましたが、グループIDを取得するのにWebhookを使ってイベントの通知を受ける必要があって、すこし面倒だったので、今回はLINE Notifyでやってみました。
事前準備
LINEグループの作成
グループに通知を送信したいので、まずdemo用のグループ「line-notify-demo」を作成しておきます。
グループ通知の場合はLINE Notifyの公式アカウントをグループに追加する必要があります。
LINE Notifyトークン取得
以下の手順でトークンを取得します。
- LINE Notify公式サイトからLineアカウントでログインする
- 「マイページ」をクリックする
- 「トークンを発行する」をクリックする
- トークン名を入力し、送信したいグループを選択し、「発行する」をクリックする
- トークンは再表示できないので、メモしておく
CodeCommitリポジトリの作成と通知の設定
「line-notify-demo」という名前でCodeCommitリポジトリを作成しておきます。
リポジトリの設定から、通知ルールを作成します。
内容に応じてトリガーイベントを選択可能ですが、今回はBranches and tagsのCreatedとUpdatedを選択します。
SSMパラメータの作成
LINE NotifyトークンをSSMパラメータストアにSecureStringで保存します。必要に応じてSecrets Managerも利用可能です。
パラメータ名に「line-notify-token」と入力し、「安全な文字列」を選択します。KMSキーはCMKを選択しますので、未作成の場合は事前作成が必要です。値のところに上記LINE Notifyトークン取得手順でメモした値を入力します。
Lambda関数の作成
IAMロールとポリシーの作成
まずLambda用のIAMロールとポリシーを作成します。
CloudWatchロググループの作成、ログの出力、SSMパラメータの取得、KMSキーを使った復号、CodeCommitコミット情報取得の権限を付与します。
- ロール名:line-notify-demo-lambda-role
- ポリシー名:line-notify-demo-lambda-policy
xxxxxxxxxxxx
のところはご自身のAWSアカウントIDに置き換えてください。kms:Decryptで許可するリソースは、ご自身のKMSキーのARN
に置き換えてください。また本demoではap-northeast-1
リージョンを使っています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:ap-northeast-1:xxxxxxxxxxxx:*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:ap-northeast-1:xxxxxxxxxxxx:log-group:/aws/lambda/line-notify-demo-lambda:*"
},
{
"Effect": "Allow",
"Action": "ssm:GetParameters",
"Resource": "arn:aws:ssm:ap-northeast-1:xxxxxxxxxxxx:parameter/line-notify-token"
},
{
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:ap-northeast-1:xxxxxxxxxxxx:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
{
"Effect": "Allow",
"Action": "codecommit:GetCommit",
"Resource": "arn:aws:codecommit:ap-northeast-1:xxxxxxxxxxxx:line-notify-demo"
}
]
}
Lambda関数の作成
次にLambda関数を作成します。
「line-notify-demo-lambda」という関数名にします。今回はPythonでコードを作成しますので、「Python3.9」を選択します。アクセス権限で「既存のロールを使用する」を選択し、上記手順で作成した「line-notify-demo-lambda-role」を選択します。
レイヤーの作成
requestsというpythonのライブラリを使いますので、Lambdaのレイヤーとして設定しておきます。以下のコマンドで該当ライブラリをダウンロードして、ZIP化します。
$ pip3 install -t python requests
$ zip -r9 layer.zip python
名前を入力し、上記手順で作成したZIPファイルをアップロードします。
「line-notify-demo-lambda」のLambda関数に戻って、Lambda関数の設定画面からレイヤーを追加します。上記手順で作成したレイヤーのARNを指定します。
環境変数の設定
Lambda関数の設定画面から以下の環境変数を追加します。PARAM_KEYは上記SSMパラメータの作成手順で作成したパラメータ名です。URLは固有のAPIエンドポイントになります。
- PARAM_KEY: line-notify-token
- REGION: ap-northeast-1
- URL: https://notify-api.line.me/api/notify
トリガーの設定
Lambda関数の設定画面からトリガーを追加します。ソースをSNSに指定し、事前準備の通知ルール作成で作成したSNSトピックを選択します。
コードの作成
ソースコードを書いていきます。
ポイントは以下になります。
- LINE NotifyトークンをSSMパラメータストアから取得する
- SNSから送られたイベントからIAMユーザー、コミットID、ブランチを取得する
- コミッター、コミットメッセージはSNSから送られたイベントに存在しないため、コミットIDをもとにcodecommitのGetCommit APIで取得する
- 取得したIAMユーザー、コミットID、ブランチ、コミッター、コミットメッセージをもとに通知用メッセージを作成し、LINE NotifyのAPIエンドポイントに対してpostリクエストを送信する
出来上がったコードは下記の通りです。
import os
import json
import boto3
import requests
REGION = os.environ["REGION"]
PARAM_KEY = os.environ["PARAM_KEY"]
URL = os.environ["URL"]
CODECOMMIT = boto3.client("codecommit")
def get_parameters(param_key):
"""SSMパラメータストアからtokenを取得
:param param_key: SSMパラメータの名前
:type: str
:returns: SSMパラメータの値
:type: str
"""
ssm = boto3.client("ssm", region_name=REGION)
response = ssm.get_parameters(
Names=[
param_key,
],
WithDecryption=True
)
return response["Parameters"][0]["Value"]
def get_commit_info(event):
"""IAMユーザー、コミットID、ブランチ、コミッター、コミットメッセージを取得
:param event: snsから送信されたpayload
:type: dict
:returns: IAMユーザー、コミットID、ブランチ、コミッター、コミットメッセージを格納したdict
:type: dict
"""
sns_info = event["Records"][0]["Sns"]
sns_info["Message"] = json.loads(sns_info["Message"])
sns_info = sns_info["Message"]["detail"]
commit_info = CODECOMMIT.get_commit(
repositoryName=sns_info["repositoryName"],
commitId=sns_info["commitId"]
)
commit_info_dict = {
"iam_user": sns_info["callerUserArn"],
"commit_id": sns_info["commitId"],
"branch": sns_info["referenceName"],
"committer": commit_info["commit"]["author"]["name"],
"commit_message": commit_info["commit"]["message"],
}
return commit_info_dict
def lambda_handler(event, context):
token = get_parameters(PARAM_KEY)
headers = {"Authorization": f"Bearer {token}"}
commit_info_dict = get_commit_info(event)
data = "\n"
for key in commit_info_dict:
data += f"{key}: {commit_info_dict[key]}\n"
payload = {"message": data.encode("utf-8")}
requests.post(URL, headers=headers, data=payload)
動作確認
では動作確認してみます。ローカルリポジトからpushする場合はCodeCommitのSSHキーかHTTPS Git認証情報が必要なので、今回はブラウザからリポジトリにファイルを作成し、コミットすることにします。
通知が来ましたね!