GitLabからHubot経由でChatWorkにマージリクエストのレビュー依頼を自動通知する

こんにちは。エンジニアの石田です。

今回は開発プロセス改善ネタをテーマに、GitLabからChatWorkにマージリクエストのレビュー依頼を自動通知するHubotスクリプトを作ってみました。

実際に作ったHubotスクリプトのコードと、ひと通りの導入手順を説明します。

背景

マネーフォワードのソースコード管理にはGitLabを、全社コミュニケーションにはChatWorkを利用しています(一部、HipChatやSlackも利用しています)。

私の所属開発チームでは、Git Flow(を多少簡略化したもの)で Merge Request(=GitHubでのPull Request)ベースの開発フローを採用しています。
Merge Requestは、基本的にチームメンバー全員がレビューをしています。
そして現状私の所属するチームでは、レビュー依頼をChatWorkに手入力しています。

ここで、もっと怠惰でありたい + 近頃のChatOps界隈でよく利用されているHubotで遊んでみたい、という動機でレビュー依頼を自動通知してくれるツール(Hubotスクリプト)を作ってみました。

他の実現方法

ちなみにGitLabとChatWorkを連携するには、Hubotを使う以外にも

などの方法もあります。
 
 

ツールの概要

GitLab->Hubotの連絡には、GitLabのWebHook機能を利用します。
Hubot->ChatWorkの連絡には、ChatWork APIを利用します。

開発者がマージリクエストをしてから、レビュー依頼されるまでの全体の流れは次のとおりです。
1. 開発者がGitLabにマージリクエストをする
2. GitLabはWebHook機能により、Hubotサーバにマージリクエスト情報をHTTP Postする
3. HubotはChatWork APIを利用することで、ChatWorkにメッセージを投稿する
4. メッセージを見た開発者がレビューする
 
 

ツールの導入手順

1. GitLab、ChatWorkをセットアップ

ChatWork API利用申請をしてTokenを取得します。要数日です。

GitLabの設定画面よりWebHookを追加します。
WebHookを追加するためには、Owner以上のユーザ権限が必要です。
WebHook先には次のURLを指定します。
your_gitlab_host your_group your_project your_room_idは適宜置き換えて下さい

http://<your_gitlab_host>:5000/gitlab_hook/?gitlab_group=<your_group>&gitlab_project=<your_project>&chatwork_room=<your_room_id>

リッスンポート(5000)は変更可です。その際は、後述のrun_hubot.shもあわせて変更してください。

2. サーバにHubotをインストール

(1)npmをインストールする

CentOS6.x(64bit)の場合:

$ rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
$ yum install nodejs npm --enablerepo=epel

Mac OS Xの場合:

$ brew install node

(2)Hubotをインストールする

$ npm install -g hubot coffee-script

3. Hubotプロジェクトを作成する

(1)ひな形を作成

$ cd your_hubot_projects_dir
$ hubot -c myhubot
$ cd myhubot

(2)デフォルトで入っている不要なスクリプトを削除

$ vi hubot-scripts.json

編集前:

["redis-brain.coffee", "shipit.coffee"]

編集後:

[]

(3)起動シェルスクリプト作成

$ vi run_hubot.sh
export PORT=5000 #Hubotサーバリッスンポート
bin/hubot
$ chmod +x run_hubot.sh

(4)Hubot自作スクリプト作成

$ vi scripts/gitlab2chatwork.coffee
# Description:
#   GitLab 2 ChatWork notification
#
# Dependencies:
#   "url" : ""
#   "querystring" : ""
#
# Configuration:
#   None
#
# Commands:
#   None
#
# URLS:
#   /gitlab_hook?gitlab_group=<your_group>&gitlab_project=<your_project>&chatwork_room=<your_room_id>
#
# Auther:
#   Katsunobu Ishida

GITLAB_URL = 'http://example.com'
CHATWORK_TOKEN = 'your_chatwork_token'
CHATWORK_TARGET_USERS = '[To:0000000][To:0000000][To:0000000]'
CHATWORK_IMG_PREVIEW_TAG = '[preview id=00000000 ht=113]'
CHATWORK_API_URL = 'https://api.chatwork.com/v1'
url = require 'url'
querystring = require 'querystring'

module.exports = (robot) ->
  say = (room, message) ->
    robot.http("#{CHATWORK_API_URL}/rooms/#{room}/messages")
      .headers
        'Content-Type': 'application/x-www-form-urlencoded'
        'X-ChatWorkToken': CHATWORK_TOKEN
      .post('body=' + message) (err, r, body) ->
        robot.logger.error "Chatwork error:#{err}, body:#{body}" if err?

  merge_request = (gitlab_group, gitlab_project, chatwork_room, hook) ->
    attr = hook.object_attributes
    switch attr.state
      when 'opened'
        gitlab_project_path = "#{GITLAB_URL}/#{gitlab_group}/#{gitlab_project}/merge_requests/#{attr.iid}"
        say chatwork_room, """
          #{CHATWORK_TARGET_USERS}
          [info][title]Hubot:マージリクエスト[/title]レビューおねがいします!!!(bow)
          #{gitlab_project_path}
          Target Branch: #{attr.target_branch}
          Title: #{attr.title}
          #{CHATWORK_IMG_PREVIEW_TAG}[/info]
        """
      # when 'closed'
      # when 'merged'

  robot.router.post "/gitlab_hook", (req, res) ->
    hook = req.body
    room = req.params.room
    kind = hook['object_kind'] || 'push'
    q = querystring.parse(url.parse(req.url).query)
    robot.logger.info "gitlab_hook: kind=#{kind}, gitlab_group=#{q.gitlab_group}, gitlab_project=#{q.gitlab_project}, chatwork_room=#{q.chatwork_room}"
    switch kind
      when 'merge_request' then merge_request q.gitlab_group, q.gitlab_project, q.chatwork_room, hook
      # when 'push'
      # when 'issue'
    res.send 200

gitlab2chatwork.coffee内冒頭の定数
– GITLAB_URL
– CHATWORK_TOKEN
– CHATWORK_TARGET_USERS
– CHATWORK_IMG_PREVIEW_TAG

を適宜編集してください。

CHATWORK_IMG_PREVIEW_TAGは、ChatWorkの画像プレビューのためのタグです。開発チームメンバーがコードレビューをしたくなるような画像にします。
なおプレビュータグを利用するためには、事前にチャット内に画像投稿をする必要があります。そのメッセージ内の「[preview id=xxx ht=150]」のような文字列がプレビュータグです。
これをコピー&ペーストすることで、以降プレビュータグを利用できるようになります。

4. Hubotを実行

$ ./run_hubot.sh

これで準備完了です。

実際にGitLabにマージリクエストすると、ChatWorkに下記のようなレビュー通知が届きます。

[To:0000000][To:0000000][To:0000000]
[info][title]Hubot:マージリクエスト[/title]レビューおねがいします!!!(bow)
http://example.com/your_groupe/your_project/merge_requests/00
Target Branch: develop
Title: TEST
[preview id=00000000 ht=113][/info]

 
 

雑感

今回社内環境に合わせる形でHubotとChatWorkを連携させましたが、そういった制約条件がなければ現状ではChatWorkよりもHipChatやSlackと連携させるほうが楽しそうです。
チャットのメッセージ一覧を取得するAPIがChatWorkに未実装のため、Hubotとユーザとの双方向のコミュニケーションが取りづらいためです。
とはいえChatWorkは国産サービスでもあるので、メッセージ一覧取得APIの実装を心待ちにしつつ、1ユーザとして陰ながら応援しております!
 
 

参考

最後に

マネーフォワードでは、新しい事にチャレンジできるエンジニアを募集しています!
みなさまのご応募お待ちしております!

マネーフォワード採用サイト
https://recruit.moneyforward.com/

Wantedly
https://www.wantedly.com/companies/moneyforward

Pocket