最近関わった某OSSの真似をして、GitHubプロジェクトでプルリクエスト(PR)のレビューと自動テストを必須にしたいと思い、ドキュメントを適当にググりながら設定してたのですが、書いてる内容が古かったりしてやたらこんがらがり、1日仕事になってしまいました。
ということで、自分はこう設定したというメモを残します。まぁこれもほっとくとすぐ古くなりそうですが。
やりたいことは、以下の通り。
- masterブランチPR発行時、然るべき人にレビューのリクエストが飛ぶようにする
- 同時に、Jenkinsでテストも実行される
- レビューとテスト、両方が通らないとmasterにマージできないようにする
まずはレビューを必須に
レビューを必須にするのは、GitHubだけで設定可能です。以下説明。
GitHubプロジェクトを作るところは省略します。ここでは、bonotake/rvtest
なるリポジトリをこさえたとします。
コードオーナーを設定する
現在のGitHubは、プロジェクト内のコードのそれぞれにオーナーを設定できます。これは、CODEOWNERS
なるファイルを所定の場所(以下の例では.github
以下)に置くことで有効になります。
詳しくは公式ドキュメント(英語)を参考にしてもらうとして、ここではこんな感じでファイルを書きます。こう書くと、リポジトリ内の全てのコードのオーナーにGitHubアカウントbonotake
が設定されます。ここには個人アカウントのほか、Organizationアカウントの場合はその中で作ったチームも指定できます。
そして、このファイルをmaster
ブランチにコミットしてプッシュ。
その他、一揃い必要な(PRする必要のない)ファイルは一緒に、今のうちにプッシュしときます。
以降の設定すると、master
への直接プッシュは(設定解除しない限り)基本できなくなるので。
masterブランチをプロテクトする
GitHubの、プロジェクトのページに飛んで、"Settings"をクリック。
左側のメニューから”Branches"を選びます。
Protected Branchesなる欄があるので、そこの”Choose a branch..."でmaster
を選択。
"Branch protection for master"なるページに遷移するので、そこで、
- "Protect this branch" にチェック
- サブアイテム"Require pull request reviews before merging"にチェック
- さらにその下の"Require review from Code Owners"にチェック
- とりあえず画面下の"Save changes"をクリック
これで、masterブランチに対するPRが発行されると、コードオーナーにレビューがリクエストされて、そのオーナーのうちの誰かがレビュー・承認しない限り、PRをマージできなくなります。
試しにPRしてみると、こんな感じ。
"Code owner review required"となって、bonotake にレビューがリクエストされます。
ついでにいうと、このとき bonotake にはリクエストメールが飛びます。
でbonotakeがこのPRのページを開くと、右上に"Add your review"のボタンが。
押すと、レビューが入力できるウィンドウが現れます。
コメントを入れられるフォームと、その下に3つの選択肢が出ますが、
- Comment: とりあえずコメント
- Approve: PR承認
- Request changes: PR却下
です。
ここのフォームにコメント入力すると全体へのコメントになりますけど、コードの行ごとにコメント入れることもできます。
で、承認すると、こんな感じでマージ可能に。
自動テストも必須に
こっからはJenkinsも使います。Jenkinsサーバそのもののセットアップは省略。
GitHub側:botアカウントの作成
JenkinsがアクセスするためのbotアカウントをGitHubに作成します。
そして、プロジェクトの"Settings"から、"Collaborators"メニューを選択、作ったbotアカウントをcollaboratorに追加します。
botアカウントにinvitationメールが送られるので、そっち側でログインし直してaccept、ログアウトして、元のアカウントでログインし直します。
GitHub側:Webhookの設定
"Settings"から、"Webhooks"メニューを選択。
"Add webhook"ボタンを押して、遷移してで出てきたフォームに入力していきます。
- Payload URL: "http://[Jenkinsサーバ]/ghprbhook/"を入力
- Which event would you like to trigger this webhook?: "Let me select individual events."を選択
さらに、その下に出てくる項目で、
- "Pull request"にチェック
- "Push"のチェックを外す
とします。
最後に、”Add webhook"ボタンを押します。
ここで注意なんですが、Jenkinsサーバにアカウントを設定して、ログインしないと各種操作ができない設定にしている場合、上記の設定をしてもダメな場合があります。
そのときは、最初に入れるURLを**"http://[ユーザID]:[パスワード]@[Jenkinsサーバ]/ghprbhook/"**とするとうまくいきました。
セキュリティ的にどうなの、という気がしなくもないですが、これ以外のよりセキュアな方法が見つからず…… ありました。
上では空欄にしてたんですが、Secretの欄に、適当な文字列を入れてください。長めのランダムな文字列が良いと思います。
この文字列を「合言葉」として、Jenkins側にも設定すれば、ユーザIDとパスワードをURLに直書きする必要はないです。
あと、パスワードの代わりにトークンを用いる方法もあるようです。詳しくはこちらの記事を参照。
Jenkins側:botアカウントの設定
今度はJenkinsの設定。
あらかじめ、Git plugin, GitHub plugin, GitHub Pull Request Builder plugin の3種はインストールしておきます。(「Jenkinsの管理」→「プラグインの管理」からできます。)
そして、さっき作ったbotアカウントをJenkins側に設定します。
「Jenkinsの設定」→「システムの設定」を選択し、遷移した画面の「GitHub Pull Request Builder」欄で
- GitHub Server API URL: "https://api.github.com" と入力
-
Credentials:
- 「追加」ボタン→「Jenkins」をクリック
- 現れたダイアログの「ユーザー名」「パスワード」に、さっき作ったbotのアカウント名とパスワードを入力、「追加」ボタンをクリック
- プルダウンで、botアカウントが選べるようになるので、選択。
- 「Test Credentials...」で、GitHubに接続できるか試せます。ここは省略しますが、一通り試しといたほうがいいでしょう。
- Description: なんか区別のつく文字列を。ここでは"bot"とだけ入力。
[追記]さっきGitHubのWebhookで"Secret"に文字列を入れた場合、Credentialsの欄、"Shared Secret"のところに同じ文字列を入力します。[追記終わり]
以上やって、「保存」ボタンをクリック。
Jenkins側:ジョブの設定
続いて、ジョブを作ります。とりあえず今回は「フリースタイル・プロジェクトのビルド」でジョブを作成。
ジョブの設定画面で、
- GitHub projectにチェック
- その下に現れる欄に、GitHubのURL(https://github.com/bonotake/rvtest とか)を入力
- 「ソースコード管理」で"Git"を選択
- 「リポジトリURL」欄に、リポジトリのURL(https://github.com/bonotake/rvtest.git とか)を入力
- 「高度な設定…」ボタンを押して、「Refspec」欄に "+refs/pull/*:refs/remotes/origin/pr/*" と入力
- 「ビルドするブランチ」欄を
空欄にここに${ghprbSourceBranch}
(PRのソースになってるブランチを指定)と入れます。本来は${sha1}
(PRを指定)と入れれば良いはずなんですが、僕の環境ではどうしてもうまく動きませんでした。
- 「ビルド・トリガ」で"GitHub Pull Request Builder"にチェック
- GitHub API Credentials に "https://api.github.com:bot" (コロン以降はさっきの"Description"に入れた文字列)を選択
- 更に、"Use github hooks for build triggering" にチェック。ここにチェック入れなかった場合は、cronでJenkins側から定期的にポーリングされます。さっきのGitHub側のWebhookが要らなくなる代わり、Jenkins側の負荷が多少増えるし、PR発行とJenkins起動にタイムラグが発生する場合があるので、ここではチェックを入れます。
- 「高度な設定」を開き、"White list" にPRしそうなGitHubユーザのアカウント名をあらかじめ入力。ここで指定した人からのPRでのみJenkinsが走ります。
- → あるいは、"List of organizations. Their members will be whitelisted"にOrganizationアカウントを指定すれば、そのOrganisationに所属する任意のユーザのPRからJenkinsが起動します。
- → あるいは、"Build every pull request automatically without asking (Dangerous!)."にチェックを入れれば、どんな人のPRからでもJenkinsが走るように。ただし、悪意あるユーザが変なPRをすれば、そのコードでJenkinsサーバを自由に動かせてしまうので、要注意。
- 同じく「高度な設定」、"Whitelist Target Branches:"に master と入力。これで、masterブランチに対するPRだけがJenkinsビルドの対象になります。
- 「ビルド」で「ビルド手順の追加」をクリック、「シェルの実行」を選択
- ここに、具体的に実行するテストスクリプトを入力します。詳細は割愛。各人ご自由に。
以上終わったら、「保存」をクリック。
GitHub側:実際にPRをしてみる
実はまだ設定終わってないんですけど、いっぺんPRをやってみないと先に進めないという、若干バッドノウハウ感の漂う手順が存在するので、とりあえずPRします。内容はとりあえずなんでもいいです。
うまくいくと、このPRでJenkinsが起動して、ステータスがPRの画面に表示されます。
こんな感じで、×がついてる(テスト失敗)んですが、その結果は関係なく、レビューが通っていればマージできる状態。
これを、Jenkinsのビルドが失敗すればマージできない状態にします。
GitHub側:テストを必須に
"Settings"から"Branches"メニューを開き、"Protected branches"のところ、先にmaster
が選択されてますが、その右横のEditボタンを押します。
ここで、さっきチェックしなかったRequire status checks to pass before mergingにチェック。
"Status checks found in the last week for this repository"のところ、"default"という選択肢が出てますが、これがJenkinsのビルドによるチェックです。この欄が、一回Jenkinsを起動させないと現れないので、まず先にPRをしてみる必要があるのでした。
ということで、この"default"にチェック。右横に"Required"の文字が現れます。
画面下の"Save changes"ボタンを押し、先程のPRに戻ってみると、表示がちょっと変わっています。
Administratorならマージできるんですが、基本はダメよ状態に。
ここで、ちゃんとテストの通るコミットをしなおしてやると、
無事マージできるようになりましたとさ。
[追記]
でも、テストやってるのに表示が"default"って何だかわからないし、テスト失敗してるのに"Finished."って出るのも何だか変だし……と思われるかもしれません。
その場合、ジョブの設定で「ビルド・トリガ」欄の"GitHub Pull Request Builder"以下にある"Trigger Setup..."ボタンを押して、出て来る入力フォームに以下の要領で入力してください。
- Commit Status Context: "default"の代わりに表示するジョブの名称
- Commit Status Build Result: ジョブの実行結果(SUCCESS/ERROR/FAILURE)のそれぞれに応じて表示するメッセージ(「追加」ボタンで各メッセージを追加できます)
例えばこんな感じ。
ジョブの名称を"test"にして、あと、SUCCESS/ERROR/FAILUREそれぞれにメッセージを変えて入れてます。
で、これを設定後、改めて適当にPRをし(汗)、Require status checks... のところの設定をやり直してください("default"のチェックを外し、"test"にチェックを入れる)。
ジョブごとに名称やメッセージを変えられるので、複数のジョブを定義して、複数のテストを並列実行させ、それぞれの成功を必須にする、なんてこともできます。
注意してほしいのですが、この設定はジョブ単位でやってください。システム単位でもできますが(「Jenkinsの管理」→「システムの設定」)、まともに動作しないので触らない方が無難です。
参考記事とか
-
Pull Request Builder PluginをJenkinsに導入する
- ~~ここに書かれてる「Refspec」の欄の設定が、恐らくMarkdownのエスケープミスでおかしくなってて、このままだとJenkinsがエラーを吐きます。正しくは上記。~~修正されました。
- GitHub Pull Request Builder Plugin の多すぎる設定項目を補足してみる
- Jenkinsでプルリクエストをビルドする
- gitbucketとjenkinsをGitHubPullRequestBuilderを使って連携する
- hudson - Jenkins and GitHub webhook: HTTP 403 - Stack Overflow
- About pull request reviews - GitHub User Documentation