GitHub Pull Request BuilderでPRに連動したCI環境

# 背景

とあるプロジェクトでソースコードの管理をBitbucketからGithubへ移行することになり、新環境で使用するCI環境を設定することになった。
新環境では旧環境を踏襲するため、Jenkins+GitHub Pull Request BuilderでPRに連動してテストが流れるCI環境を構築するが、作業にあたり調査したことなどを残す。

## 本資料の対象者

* GithubのPRに紐づけたJenkinsジョブを作成したい人
* PRに連動してテストを実行したい人
* ビルド手順(テスト内容)については自分で書ける人

:::note warn
すでに環境が用意されている前提のため、
この資料ではJenkinsやGitHub Pull Request Builderのインストール手順等を載せていません。
:::

## Jenkins

オープンソースで、CI/CDなどを実現するツール。
Gitなどのバージョン管理ツールをサポートしており、ジョブという単位でシェルスクリプトやバッチコマンドなどを実行することができる。
構築後の設定などはWebブラウザ経由でGUIによる管理ができるのも特徴の一つ。
(アイコンのJenkinsおじさんが癒しポイント?)

## Github Pull Request Builder

Jenkinsのプラグインの一つ。
GithubのPull Requestに連動し、JenkinsジョブやPipelineを実行するための機能を提供し、Github Commit Status APIを使用してテスト結果を記録している。

### 使用できる環境変数
| enviroment | memo |
| ------ | ------ |
| ghprbActualCommit | ビルド実行起因となったコミットID |
| ghprbActualCommitAuthor | ビルド実行起因となったコミットしたユーザ |
| ghprbActualCommitAuthorEmail | ビルド実行起因となったコミットしたユーザのEmailアドレス |
| ghprbPullDescription | PullRequestの説明欄 |
| ghprbPullId | PullRequestのID |
| ghprbPullLink | PullRequestへのリンク |
| ghprbPullTitle | PullRequestのタイトル |
| ghprbSourceBranch | PullRequestのマージ元ブランチ名 |
| ghprbTargetBranch | PullRequestのマージ先ブランチ名 |
| sha1 | PRが自動マージされる場合は`/origin/pr/4/merge`<br>  それ以外は`/origin/pr/4/head` |

# Jenkinsジョブの作成

JenkinsでGithub Pull Request Builderを用いてジョブを作成していく。
開発者の使用環境に合わせ、構築手順を複数のステップに分割した。

## 使用環境
| Package | Version |
|---------|---------|
| Jenkins | 2.319.2 |
| Github Pull Request Builder | 1.42.2 |

## Githubと連携させる

まずGithubからソースコードを取得し、これを使って特定の処理を行うJenkinsジョブを作成する。
この設定でビルドの最初に`git clone`してくるので、テスト内で`git clone`する処理が不要になる。
(またこの章の設定は自動化されておらず、開発者が手動でビルド(実行)する設定)

### 設定 - ソースコード管理タブ

`Git`を選択し、各設定を行っていく
![jenkins_ソースコード管理.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2763745/ec29363c-547e-cc4c-b9e6-aedbf39dbfb7.png)

* `リポジトリ`の項目
  * リポジトリURLに入力
    * `git clone`などに使用するURLを記載する
      :o: `https://github.com/hello/world.git`, `git@github.com:hello/world.git`
      :x: `https://github.com/hello/world`
  * リモートブランチを参照するための設定
    * `Refspec`
      * `+refs/pull/:refs/remotes/origin/pr/`
      * 本設定がない場合、`git checkout`に失敗することがある
```
 > git fetch --tags --progress -- git@github.com:hello/world.git +refs/pull/*:refs/remotes/origin/pr/* # timeout=10
 > git rev-parse origin/${ghprbSourceBranch}^{commit} # timeout=10
 > git rev-parse ${ghprbSourceBranch}^{commit} # timeout=10
ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job.
Finished: FAILURE
```
  * 必要な場合は認証情報を選択
    * リポジトリへのアクセスに必要な場合のみ
* ビルドするブランチ
  * ビルドしたいブランチを指定  
    `master` などを設定
  * tagやコミットID、環境変数などで設定可能

### ビルドを実行してみる

プロジェクトの先頭に戻って`ビルド実行`を選択すると、設定した環境で処理が動き始めます。
今回の例の設定だと、masterブランチを使用した処理が動きます。

## Github Pull Requestに連動させる

上記では開発者による手動実行でしたが、普段からテストを実行するには自動化が必須…
なので次はGithub上のPull Requestの作成、状態に合わせて自動で実行する環境に修正してみます。

### 設定 - Generalタブ

![jenkins_general.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2763745/7a2ed915-b8e4-21f7-7a57-fd0d8e691753.png)


* GitHub projectのProject urlにレポジトリのURLを入力
  :o: `https://github.com/hello/world`
  :x: `https://github.com/hello/world.git`, `git@github.com:hello/world.git`

### 設定 - ビルド・トリガタブ

GitHub Pull Request Builder のチェックを入れ、下記の内容を設定する
![jenkins_ビルドトリガ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2763745/402c78c0-d90c-8fb0-46d9-00ec028b9df5.png)

* 定期的に状態を見に行くための設定
  * `Crontab line`
    * cronと同じような記述
    * 例) `H/5 * * * *`
      * `H`はJenkinsがジョブを時間的に分散して実行するための設定
      * 今回の例では5分に1回チェックが走る
* PR発行者でfilterをかける
  * white list形式で設定する
    * 何も設定しないと実行されない
  * `White list`
    * ユーザ単位で設定(複数設定時は改行で区切る)
  * `List of organizations. Their members will be whitelisted.`
    * organizations単位で設定(複数設定時は改行で区切る)
  * `Build every pull request automatically without asking (Dangerous!).`
    * 全ユーザに対して許容する
    * セキュリティ的に危険なため、Private RepogitoryやPR作成者が制限されている環境での使用を推奨

## PRのコメントに連動させる

任意のタイミングでビルドしたいケースがいくつか考えられる。

* 自動実行のテストがFail
    * テスト自体が不安定
    * 環境起因によるテスト失敗
* Jenkinsで手動による再buildは使いたくない
    * Github PRにテストPassの緑マークが付かない

そこで、Github PRのコメントに任意の文字列があるとビルドする設定を追加する。


### 設定 - ビルド・トリガタブ

* `Trigger phrase`に任意の文字列を設定
  * 正規表現で設定が可能
    `test this.*` など

## 特定のブランチへのPRのみに連動させる

Github PRのうち、メインブランチへのPRだけテストしておけばいい、という場合にPRのマージ先ブランチで制限を書けることができる。
また、特定のブランチへのPRでは実行が不要、という逆の設定もできる。
さらにPRは作成したが、開発中なのでまだテストは流してほしくない、という場合の設定も紹介する。

### 設定 - ビルド・トリガタブ

* 特定のブランチのみビルド実行
  * `Whitelist Target Branches:`
    * `Add Branch`で対象のブランチを追加
    * 正規表現での設定も可能
* 特定のブランチではビルド実行しない
  * `Blacklist Target Branches:`
    * `Add Branch`で対象のブランチを追加
    * 正規表現での設定も可能
* PRのタイトルに特定の文字列がある場合にビルドを実行しない
  * `Skip build phrase`
    * 正規表現での設定も可能
    * 例) `\[WIP\].*`  
      PRのタイトルが`[WIP]`から始まる場合はビルドしない

# まとめ

JenkinsとGithubの連携のための設定を行い、Github PRに連動したテスト環境を作成することができた。
今回使用したオプション群は一部で、様々なケースに対応できるための設定がありそうだった。
使っていない設定を調査して、活用できるものがないか調べるのもよさそう。

# 参考リンク

* Jenkins公式
    * https://www.jenkins.io/
* Github Pull Request Builder
    * https://plugins.jenkins.io/ghprb/
* Pull Request Builder PluginをJenkinsに導入する
    * https://qiita.com/kompiro/items/a097b3b36aa30bc751c6
* 【Jenkins】GitHub のプルリクをトリガーにジョブをビルドする方法
    * https://baba-s.hatenablog.com/entry/2021/05/14/090000