🔔

GitHub API / Slack API / AWS Lambda + EventBridge

2023/10/03に公開

GitHub API を使用して Contributions やコミット数を取得し、Slack に通知する sh スクリプトを書く。
LambdaはCustom Amazon Linux2をRuntimeに使用する。
また、EventBridgeを使用して定期的に実行させる。

Prerequisites

  • GitHub のアクセストークンを発行しrepouserのスコープに許可を付与する。トークンはここから作成できる。
  • Slack のアプリを作成し任意のチャンネルに追加する。また OAuth のトークンを控えておく。アプリはここから作成できる。

以下の解説ではLambda Functionの環境変数に下記の4つを登録している。

GITHUB_TOKEN=your_github_token
GITHUB_USERNAME=your_github_username
SLACK_TOKEN=your_slack_token
SLACK_GITHUB_CHANNEL=your_slack_channel_name

ローカルで使用する場合は.zshrcに登録しておくとよい。

cat << EOF >> ~/.zshrc

#github
export GITHUB_TOKEN=your_github_token
export GITHUB_USERNAME=your_github_username
#slack
export SLACK_TOKEN=your_slack_token
export SLACK_GITHUB_CHANNEL=your_slack_channel_name
EOF

GitHub からデータを取得する

Contributions の情報は GitHub API v4(GraphQL)で取得できる。
GraphQL API の Explorerから実際のデータをもとに試すことができる。

エンドポイントにhttps://api.github.com/graphqlを指定し、クエリを POST する。

response=$(curl -H "Authorization: bearer $GITHUB_TOKEN" -X POST -d '{"query":"query { user(login: \"'$GITHUB_USERNAME'\") { name contributionsCollection(from: \"'$from_date'\", to: \"'$to_date'\") { commitContributionsByRepository(maxRepositories: 100) { repository { name } contributions { totalCount } } contributionCalendar { totalContributions } } } }"}' https://api.github.com/graphql)

ここでは取得日の範囲は先週(日曜 00:00〜土曜日 23:59)とした。なお最大の日付範囲は1年以内である。

from_date=$(date -d "last Sunday - 1 week" +"%Y-%m-%dT00:00:00Z")
to_date=$(date -d "last Saturday" +"%Y-%m-%dT23:59:59Z")

なお、もしMacOSで実行する場合はdateのオプションは下記のように記述する。

from_date=$(date -v-sunday -v-1w +"%Y-%m-%dT00:00:00Z")
to_date=$(date -v-saturday +"%Y-%m-%dT23:59:59Z")

jq を使った JSON データの解析

API のレスポンスから必要なデータを抽出するために、jq を利用する。ローカルで実行する場合はjqは brew 等でインストールしておく。

brew install jq

LambdaのLinux環境でjqを使用するために、最新版のjqをダウンロードし実行権限を付与した上で、zipに固める。
LambdaでLayerを新しく作成し、このjq_layer.zipをアップロードする。RuntimeにはCustom runtime on Amazon Linux 2を選択する。

mkdir bin
cd bin
curl -L https://github.com/stedolan/jq/releases/download/jq-1.7/jq-linux64 -o jq
chmod +x jq
cd ..
zip -r jq_layer.zip bin

Layerが作成できたらLambdaに追加しておく。

取得したレスポンスから下記の3つのデータを抜き出す。
commitContributionsByRepositoryの返り値は空配列の場合があるので、// 0としてデフォルトを設定しておくとよい。

total_contributions=$(echo $response | jq -r '.data.user.contributionsCollection.contributionCalendar.totalContributions')
total_commits=$(echo $response | jq -r '.data.user.contributionsCollection.commitContributionsByRepository | map(.contributions.totalCount) | add // 0')
total_repositories=$(echo $response | jq -r '.data.user.contributionsCollection.commitContributionsByRepository | length')

もし、このスクリプトをローカルで(例えば)CronJobから使用する場合は、jqコマンドが参照されないため、/usr/local/bin/jqという風にフルパスを指定する必要がある。

Slack への通知

取得した情報を Slack に送信する。
改行コード\nが、そのままだと\\nとしてエスケープされてしまうため、replace する必要がある。

temp="*Last week's contributions:*\ntotal contributions: \`$total_contributions\`, commits: \`$total_commits\`, repositories: \`$total_repositories\`"
text=$(echo $temp | sed -e 's/\\n/\'$'\n''/g')

エンドポイントにhttps://slack.com/api/chat.postMessageを指定して POST する。
$SLACK_GITHUB_CHANNELには先ほど作成したアプリのボットを追加したチャンネル名を入れる。

curl -d "text=$text" -d channel="$SLACK_GITHUB_CHANNEL" -H "Authorization: Bearer $SLACK_TOKEN" -X POST https://slack.com/api/chat.postMessage > /dev/null

これで実行すれば slack に通知が来る。

./function.sh

Lambda Functionへのアップロード

下記のファイルに実行権限を付与する。

chmod +x function.sh bootstrap

これらをzipに固めてLambdaにアップロードする。またはS3等にアップロードしてURLを指定する。

zip function.zip function.sh bootstrap

定期実行の設定

EventBridgeを設定することで、Lambdaを定期的に実行することができる。
例えば、毎週月曜の9:00AMに実行する場合、Cron expressionは下記のように設定する。

0 9 ? * 2 *

ローカルで簡易的にCronJob を設定し、このスクリプトを毎週月曜日に実行させる場合はcrontabに記述する。

crontab -e

crontab のエディタが立ち上がるので編集する。
CronJob実行時に.zshrcの環境変数を読み込み、スクリプトのディレクトリに移動して実行する。

# 毎週月曜日の9:00AMに実行する場合
0 9 * * 1 . ~/.zshrc; cd /path/to/directory && ./function.sh

まとめ

参考までにソースコードを github に置いています。

AWS Lambda版
https://github.com/kazuhoishida/lambda-github-contributions-slack-notifier

ローカル(CronJob)版
https://github.com/kazuhoishida/github-contributions-slack-notifier

Discussion