#概要 / 目的
いつも決まった人がプルリクエストに対するコードレビューを行っていると、以下のようなデメリットがあります。
- コードレビューの属人化
- コードレビューする側とされる側がはっきり別れてしまい、フラットな関係でのチーム開発を阻害する
- コードレビューが特定の人に集中してしまい、他の重要な仕事が進みにくくなる
そこで、コードレビューをチーム内のメンバーに割り振るのですが、この割り振りを人力でやるのは非生産的なので、Hubotを使って自動化しました。
ここでの説明で前提となっているChatOpsな環境の構築方法や運用方法は以下を参考にしてください。
#Hubotによる自動アサインの概要図
#設定 / 実装
##GitHubチームの作成
GitHubのWEBコンソールからプルリクをアサインする用のチームを作成します。
このチームの中から自動で1人がアサインされる仕組みとなります。
今回は以下の2つのチームを用意しました。
- 商用ブランチへのプルリクを担当するチーム(リリース担当チーム)
- それ以外のプルリクを担当するチーム(コードレビュー担当チーム)
それぞれのチームのメンバー構成としては、
コードレビュー担当チーム => そのプロダクトに関わる全てのエンジニア
リリース担当チーム => その中でも知識や経験が比較的あるエンジニア
という想定です。
このようにチームを2つ用意することによって、以下のようなメリットがあります。
* 商用ブランチ以外へのプルリクはすべてエンジニア全員が均等に担当するので、チーム内で実装に対する認識を共有しやすく、スキルの底上げも期待できる。
* 商用リリースの際は、経験のある人のレビューを通るので、不適切なコードをリリース前に見つけられる
##Webhookの登録
次に、GitHubにあるレポジトリに対してWebhookを登録します。
Payload URLにはHubotのURLを設定します。
例えば、以下のようなURLになります。
http://your-hubot-app.com/github/pullreq-auto-assign-webhook?channel_name=%23general&review_team_id=xxxxxxxx&release_team_id=yyyyy
ここで、パラメータとしてchannel_name
とreview_team_id
とrelease_team_id
を渡しています。
これらのパラメータは、Hubotのスクリプト側で使います。
またSlackのChannel名ですが、#general
の#
を%23
のようにエンコードして渡す必要があることに注意してください。
また、Webhookを送るトリガーを選ぶことができますが、今回は「Pull Request」のみにチェックを入れます。
これで、プルリクエストを作ったり、クローズしたりすると「Payload URL」で設定したURLにWebhookが送られるはずです。
##Hubotスクリプトの実装
Webhookの設定が完了したので、今度はそれを受信する側のHubotスクリプトを用意します。
実際の実装は以下のようにしました(汚くてすいません)。
module.exports = (robot) ->
github = require("githubot")(robot)
owner = "qwintet-dev"# rewrite to your team name
unless (url_api_base = process.env.HUBOT_GITHUB_API)?
url_api_base = "https://api.github.com"
#プルリクのレビュアーをランダムで選定
_choosePullreqAssigneeAtRondom = (pullreq_author, team_id, callback) ->
url = "#{url_api_base}/teams/#{team_id}/members"
github.get url, (members, error) ->
review_candidates = []
for member, i in members
member_name = member.login
if member_name != pullreq_author
review_candidates.push member_name
if review_candidates.length == 0
robot.messageRoom channel_name, "there is no reviewer for \##{pullreq.number}"
key = Math.floor Math.random() * review_candidates.length
callback(review_candidates[key])
#GitHubでのプルリクを自動アサイン
robot.router.post "/github/pullreq-auto-assign-webhook", (req, res) ->
data = req.body
#openかreopen以外は何もしない
if data.action not in ['opened', 'reopened']
return res.end ""
url = require('url')
querystring = require('querystring')
query = querystring.parse(url.parse(req.url).query)
channel_name = query.channel_name
review_team_id = query.review_team_id #GitHub上に作っているレビュー担当のチームのID
relase_team_id = query.release_team_id #GitHub上に作っているリリース担当のチームのID
pullreq = data.pull_request
#既にassignされていたらそのまま
if pullreq.assignee
robot.messageRoom channel_name, "*\##{pullreq.number}* has already been assigned to *#{pullreq.assignee.login}*"
return res.end ""
repo = data.repository.name
#assigneeを選定
assign_team_id = if pullreq.base.ref == 'deployment/production' then relase_team_id else review_team_id #商用だけはリリース担当チームにアサイン、それ以外はレビューチームにアサイン
author = pullreq.user.login
_choosePullreqAssigneeAtRondom author, assign_team_id, (assignee) ->
url = "#{url_api_base}/repos/#{owner}/#{repo}/issues/#{pullreq.number}"
data = { "assignee": assignee }
#assigeeを設定
github.patch url, data, (issue, error) ->
if !issue?
robot.messageRoom channel_name, "Error occured on pullreq \##{pullreq.number} auto assignment"
return
body = "Assigned *\##{pullreq.number}* to *#{issue.assignee.login}*"
robot.messageRoom channel_name, body
res.end ""
GitHubからのプルリクエストのWebhookに反応して、自動アサインするHubotスクリプト
処理の大まかな流れとしては、以下のとおりです。
① Webhook側で設定したURL(/github/pullreq-auto-assign-webhook)に反応
② プルリクのアクションがopendかreopend以外は何もしない
③ 既にアサインされていたら何もしない
④ チームを指定して、ランダムで1人を選定(この時のチームは、プルリクのマージ先によって切り替える)
⑤ 選定された1人をアサインするようにGitHubAPIを叩く
⑥ アサイン完了したら、その旨をチャット(Slack)に通知
なお、このスクリプトはhubot-slack( https://github.com/tinyspeck/hubot-slack )がインストールされている必要がありますので、インストールされてない場合は、
npm install hubot-slack --save
でインストールしておいてください。
##動作確認
これですべて設定完了したので、実際にプルリクエストを作ってみてください。
以下のように、作成時に自動でアサインされれば成功です。