追記
Slackにも通知できるようにした記事を書きました。
目的
複数人でgitの共有リポジトリにpushするようになると、コンフリクトの可能性や同僚の進捗などが気になることがあります。その際には変更の度に何らかのお知らせが届くと嬉しいですよね。今回はChatworkを使ったpushの通知機能を実装してみます。
仕様
今回は下記のような状況を想定しています。
- gitを使ってソースコードを管理している。
- GitHubなどの外部サービスを使わずに、自前のサーバー中にgit共有リポジトリを置いている。
- Chatworkを利用している。
gitリポジトリに誰かがpushしたことを検知して、Chatworkの特定のチャットルームにコミット・メッセージを投稿します。あなたが管理しているリポジトリはおそらく1つや2つではないでしょうから、メッセージにはリポジトリ名とpushしたブランチ名が含まれるようにします。
githooks
古くからバージョン管理システムには様々なタイミングでプログラムを実行させる機構、通称 hooks と呼ばれる仕組みが有りました。当然gitにもhooksの仕組みが備わっています。gitのhooksはクライアントサイドフックとサーバーサイドフックに大別され、今回の目的ではサーバーサイドフックを利用します。サーバーサイドフックには下記の4種類があります。
pre-recieve
post-recieve
pre-update
post-update
フック名はフックを掛けるアクションと実行されるタイミングで構成されています。上記のフック名では、 pre と post はそれぞれ該当するアクションの前後に実行されることを示しています。それでは recieve と update が示しているアクションは何なのでしょうか? recieve と update は双方ともにpushされたタイミングで呼び出されます。その違いはPro Git Bookに端的に示されています。
複数のブランチへのプッシュがあったときに
pre-receive
が実行されるのは一度だけですが、update はブランチ単位でそれぞれ一度ずつ実行されます。
今回の仕様では、ブランチ名を取得してブランチごとに投稿する必要が有り、また特にpushを拒否したりする必要はないため、post-update
を使用します。
参考
Chatwork API
Chatworkはクラウド型ビジネスチャットサービスで、複数人でのリアルタイムコミュニケーションを実現するためのツールです。また、API Tokenを申請すればWeb APIを利用することもでき、今回のような通知先として機能することができます。ただし、このAPIはまだベータ版という扱いらしく、申請してから許可が出るまで非常に時間がかかるので、思い立ったらすぐに申請しましょう。
参考
post-update
今回の仕様を満たすようなhooksスクリプトを作成しました。下記のBashスクリプトを適当に修正して、通知対象としたいすべてのリモートリポジトリの $REPOSITORY_ROOT/hooks/
に置きます。実行権限をつけることも忘れないでください。
#!/bin/bash
set -eu
API_TOKEN="<CHANGE_THIS>"
ROOM_ID="<CHANGE_THIS>"
REPOS=$(basename $(pwd))
REPOS=${REPOS%.*}
BRANCH=$(git rev-parse --symbolic --abbrev-ref $1)
MSG=$(git log -1 --pretty=format:"%h - %an : %s" $BRANCH)
BODY="(${REPOS}) [${BRANCH}] ${MSG}"
if [[ "$BRANCH" = 'master' ]]; then
BODY="[info][title]PUSHED INTO \`master\` BRANCH!!![/title]${BODY}[/info]"
fi
curl -X POST -H "X-ChatWorkToken: ${API_TOKEN}" -d "body=${BODY}" "https://api.chatwork.com/v1/rooms/${ROOM_ID}/messages" > /dev/null 2>&1
exit 0
curl -LO https://gist.githubusercontent.com/artifactsauce/9480292/raw/post-update
vi post-update # 変数を修正
chmod 755 post-update
scp ./post-update $REMOTE_HOST:$REPOSITORY_ROOT/hooks/
$REPOSITORY_ROOT
と$REMOTE_HOST
はそれぞれ、リポジトリの最上位ディレクトリとリモートリポジトリを置いてあるホストの名前を示す任意の値とします。
次項以降でこのスクリプトの内容を解説します。
設定値
このスクリプトを正常に動作させるためには、冒頭の3つの変数の値を修正する必要があります。
まずはChatworkに投稿するための設定です。投稿ユーザーのAPIトークンと、投稿先のチャットルームのIDを設定します。
API_TOKEN="<CHANGE_THIS>"
ROOM_ID="<CHANGE_THIS>"
もう一つ、リポジトリ名を設定します。ハードコーディングしてありますが、上位ディレクトリの名前を動的に取得するという方法でも良いでしょう。
REPOS="<CHANGE_THIS>"
ブランチ名の取得
post-updateは引数を1つ受け取ります。それはリモート側のリポジトリの参照名(例:refs/heads/master
)です。まずはこの値からブランチ名を取得します。
BRANCH=$(git rev-parse --symbolic --abbrev-ref $1)
メッセージの作成
取得した値からメッセージ・ボディーを作成します。メッセージはpushしたブランチの最後のコミットメッセージに、リポジトリ名およびブランチ名を付加したものとします。
MSG=$(git log -1 --pretty=format:"%h - %an : %s" $BRANCH)
BODY="(${REPOS}) [${BRANCH}] ${MSG}"
メッセージ・ボディーはもちろんご自由ですが、こんな感じになっていると嬉しいんじゃないでしょうか。master
にpushしたときだけ、強調されるようにしてみましょう。
if [[ "$BRANCH" = 'master' ]]; then
BODY="[info][title]PUSHED INTO \`master\` BRANCH!!![/title]${BODY}[/info]"
fi
投稿
最後にこの内容でWeb APIを通して投稿します。
curl -X POST -H "X-ChatWorkToken: ${API_TOKEN}" -d "body=${BODY}" "https://api.chatwork.com/v1/rooms/${ROOM_ID}/messages" > /dev/null
標準出力の内容がpush時に表示されるので/dev/null
に吐き出しておくことをお勧めします。