LGTM

Looks Good To Me

mention-bot を試した

Facebook が公開しているPull Request (PR) レビュー支援ツール.
PR を作ったとき,最適なレビューアーを見つけてきてPR 上でメンションしてくれる.

github.com

試したけど,うまくいかなかった.

ざっくり言うと

セキュリティ上の懸念があって断念した.

  1. 「ボットアカウントはGitHub の2FA をオフにしなさい」と書いてある
    • GitHub API にはないが Web UI にはある機能を使っているから
    • 自動Web ログイン と 2FA の併用がむずかしい
  2. このボット機能のためだけに,1 の状態で動くエンドポイントを持ちたくない
    • PR 作成時にWebHook でトリガーしてもらうのにエンドポイント必要
    • 得られる価値に対してリスク高い

やりたかったこ

PR レビューがコスト高になることがある

Private Repo でGitHub フローを回しており,日常的にPR レビューしている. チーム内のさまざまな事情により,ふと気づくとレビューにすごい時間を使っていることがある.

個人がレビューを嫌って押し付けあうのは避けたいが,チーム全体として効率よくレビューしたい.

日本人だし「〇〇さんレビューお願いします」って言えない

〇〇さんにお願いするのが最適な場合でも「お願いします」ってなかなか言えない.日本人だからね… 急ぎの中ちょっと待っちゃったりして,状況をすこしずつ悪くしてしまう.

また,PR がぽんっと出た瞬間「あいつが見るだろう」みたいな考えがよぎる. たぶんみんな同じことやってて そもそもの着手が遅くなり,ちょっとずつ他メンバーのタスクをブロックしちゃう.

これやめたい.

試したこ

レビューアーをランダムに決めるやつ とかもあるが, やりたいことの半分しか実現できないので mention-bot に興味を持った.

ぱっと見「WebHook トリガーにしないといけないの面倒…」と思ったが, 「PR 作ったあと チャット経由で手動キックすれば動くだろう」と,Hubot スクリプトを書いてみた.

ところが…GitHub API トークンではなくID / パスワードでログインしないと動かないことがわかった.

mention-bot の動き

ここ に書いてあるとおりだが,

  1. WebHook でPR の情報を受け取る.またはPR の情報を渡して手動で呼ぶ
  2. PR 内で,どのファイル / 行にdiff があるか探す
  3. 削除/変更があった行について,git blame でmaster ブランチでの最終更新者を探す
    • いじる行の最終更新者がレビューアーに向く という前提
  4. PR 全体で3 の頻出ランキングを作る
  5. いじるファイル内の変更しない行についても 同様にgit blame ベースのmaster 最終更新者ランキングをつくる
    • いじる行でなくても,同じファイル内の最終更新者がレビューアーに向く という前提
  6. 5 を4 のケツにくっつける
  7. 6 からPR 作成者を除いたトップ N人について,指定のコールバックを呼ぶ

問題は,git blame に相当するGitHub API がないこと. Web UI にはあるのでスクレイピングして代用しているが,これが原因でボットアカウントを2FA にできない. 場合によってはAPI も使うため, さらにトークンが必要.

あきらめた

とても便利そうなんだけれど,セキュリティ的にイマイチ という判断をした.
今回Private Repo なのでやめたが,GitHub Enterprise で社内に閉じてるとか, Public Repo であれば敷居が下がったかもしれない.

git blame をローカルでやればいいだけかもしれない.

Public Repo なら認証不要*1 なので,

var mentionBot = require('./run-mention-bot.js');
var GitHubApi = require('github');

var github = new GitHubApi({ version: '3.0.0' });

var config = {
  maxReviewers: 5,
  findPotentialReviewers: true,
  fileBlacklist: [],
  userBlacklist: [],
  requiredOrgs: []
}

mentionBot
  .guessOwnersForPullRequest(
    'https://github.com/fbsamples/bot-testing',
    98,
    'mkonicek',
    'master',
    false,
    null,
    config,
    github
  )
  .then(function(users) {
    console.log(users);
  })
  .catch(function(err) {
    console.error(err);
  });

こういう感じのが動く.

特定Organization 内からのみレビューアー候補を選びたいときは,API トークンが必要なことがある.

それでもちょっと試したいひと向け

Private Repo でちょっとだけ試す方法.
ES6 のtranspile 環境をつくるのが面倒なので,mention-bot レポジトリ内にスクリプトを置く作戦.

git clone https://github.com/facebook/mention-bot.git
cd mention-bot
npm install
npm install github --save

Web UI 認証をやめて,認証済みCookie をつかう.

# githubAuthCookies.js を書き換え

module.exports = '_octo=GHx.x.xxxxxxxxxx.xxxxxxxxxx; logged_in=yes; dotcom_user=codeout; _gat=1; _gh_sess=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; _ga=GAx.x.xxxxxxxxxx.xxxxxxxxxx; tz=Asia%2FTokyo; user_session=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

私はChrome から抜いた.

Cookie

最後にスクリプト本体.

# mention.js

var mentionBot = require('./run-mention-bot.js');
var GitHubApi = require('github');

var github = new GitHubApi({ version: '3.0.0' });
// Organization 内からのみレビューアー候補を選びたいときのみ必要
github.authenticate({
  type: 'oauth',
  token: '...token...'
});

var config = {
  maxReviewers: 5,
  findPotentialReviewers: true,
  fileBlacklist: [],
  userBlacklist: [],
  requiredOrgs: []  // レビューアー候補がprivate メンバーだと動かない
}

mentionBot
  .guessOwnersForPullRequest(
    'https://github.com/user/private_repo',
    1,          // PR Number
    'codeout',  // PR 作成者
    'master',   // blame するブランチ
    false,  // Private Repo でも false, null でOK
    null,   // Organization 縛りにするときは true, 'organization'
    config,
    github
  )
  .then(function(users) {
    console.log(users);
  })
  .catch(function(err) {
    console.error(err);
  });

実行結果

mention-bot $ time node mention.js
[ 'codeout', 'foo', 'bar', 'baz' ]
node mention.js  0.89s user 0.23s system 11% cpu 9.385 total

Organization 縛りをつけるとAPI コールが増えて遅い.

mention-bot $ time node mention.js
[ 'codeout', 'foo', 'bar' ]
node mention.js  1.01s user 0.25s system 6% cpu 18.059 total

*1:PR 上でメンションしない場合