GitHub PRビルダーのすゝめ:自動テスト、マルチプロジェクトもできる!

はじめに

多くの方々が社内でJenkinsをCI/CDツールと利用されていることでしょう。
私たちも、GitHub Pull Request Builderというプラグインを用いて、プルリクエスト(Pull Request もしくは PR )別に自動でテストを回し、その結果を通知させるといった方法でよく使用しています。
GitHub Pull Request Builderを使ってJenkinsを実装すると、アプリケーションに対する新しいコードの変更(= プルリクエスト )が定期的にビルドおよびテストされて、結果を表示してくれます。複数の開発者が同時にアプリケーション開発をしても、テストさえうまく組み込んでおけば、コードに反映する前に機能が壊れていないか正確に確認ができて非常に便利です。

このプラグインを設定すると、プルリクエスト別に以下のようなテスト結果をGitHubからリアルタイムで確認できます。

プルリクエストまたはコミット追加時のテスト中

テストに合格!

テストに失敗

私たちも各商品をプロジェクト別にPRする際、自動テストを行うジョブを作ってよく利用しています。そうしているうちに、商品に共通で使用するモジュールを集めて管理するマルチモジュールプロジェクト(1つのネックリポジトリで複数プロジェクトを管理できる)にも、これらのジョブを作成して適用したいと考えるようになりました。

初めての試み


私たちは現在、13個の共通モジュールをプロジェクトで管理しています。
このプロジェクトのビルドとテストを行うジョブを作ろうとしたとき、最初はこのように考えました。

プルリクエストが上がってくるたびに、すべてのモジュールを回してみよう!

これをモットーにジョブを作ろうとしたところ、ビルド段階でMavenを通じてビルドとテストを進めるステップ、Invoke top-level Maven targetをいくつか作ることができました。試しに1つずつ追加してみると…


これを13回も行わなくてはいけません。また、完成したら再び入れる必要があります。13個ビルドとテストを回すのに、どれだけの時間がかかることでしょう…。ログに関しても、もしテストで文字化けしたらfailureログを探すのも一仕事です。自分が開発したモジュールでなくても、他のモジュールでテストが壊れたら、それが直るまでエラーを見続けるのかと思うと憂鬱になりました。

1つのPRに1つのモジュールだけを開発しよう!PRで最も多く変化があったモジュールだけにしよう!

そこで新しいブランチに切り替えるときのコミットと、開発の最後のコミットを比較して、変化が生じたプロジェクトをビルドしようと考えました。もちろんそれらを比較するJenkinsプラグインはないので、Execute shellを利用してスクリプト作成に取り掛かりました。

マルチモジュールの自動テストジョブスクリプト

1.コミットID取得

まず、ブランチのコミット開発の最後のコミットを取得する必要があります。Jenkins Execute shellで、基本提供している環境変数を確認してみました。

GIT_COMMIT = The commit hash being checked out.

この変数が意味するのは、開発の最後のコミットです。このgit show –pretty=format%Pを利用して当該コミットの親コミットIDを取得することができました。
(git show –pretty=formatオプション情報 https://git-scm.com/docs/pretty-formats

echo "GIT_COMMIT=${GIT_COMMIT}" # Merge Commit sha1(refs/remotes/origin/pr/PR_番号/merge)の実際のCommit ID

GIT_SHOW=`git show --pretty='format:%P' ${GIT_COMMIT}` # Merge CommitのSource CommitとTarget Commitを出力

COMMIT_IDS=(${GIT_SHOW})

2.最も変更の多いモジュールを検索

あとは最も変更の多いモジュールさえ探せばよいので、当該モジュールのディレクトリパスを引き抜くことができれば解決するような気がしました。ところが、

最も変更が多かったモジュールは、どのように判断するか?

検討が必要です。変更されたモジュールのコード量まで抽出する必要があるのか悩みましたが、最終的には変更されたファイル数で簡単に実装しよう!と決心しました。(いずれにせよ1つのプルリクエストは1つのモジュールだけを開発するのだから)
そして、マージコミットとdiffを開き、モジュールのディレクトリ名までを抽出して、最も多くのファイルが変化したモジュールを抽出しました。これはSpringに限定されたコードなので、実際の実装はプロジェクト別に異なります。

# Merge CommitとTarget Commitをdiffしてファイル名のみ抽出 -> モジュール名のみ抽出するために文字列処理(Springプロジェクトのため、srcフォルダ、pom.xml上位フォルダに指定)
GIT_DIFF=`git diff --name-only ${GIT_COMMIT}..${COMMIT_IDS[0]} | sed 's/\/src.*$//' | sed 's/\/pom.*$//'` 

IFS=$'\n' MODULES="$GIT_DIFF"
# モジュール名が最も多かった順に並べる
UNIQUE_MODULES=($(printf "%s\n" "${MODULES[@]}"  | uniq -c | sort -nr | awk '{printf "%s\n", $2}'))
# 当該モジュールをpropertiesに保存
echo MODULE=${UNIQUE_MODULES} > build.properties

3.モジュールのビルド

あとはモジュールをビルドすれば完了です!
先ほどモジュールを保存した変数を環境変数として登録するため、Inject environment variablesステップを追加します

最後に、環境変数を利用してMavenのビルドを実行するステップを追加すれば完成します。

まとめ

上記の方法から、私たちのプロジェクトでは、現在マルチモジュールでもテストをプルリクエスト別に通過させるか確認することができ、より簡単に管理できるようになりました。想定していなかった些細な部分でテスト時間が大幅にかかってしまったり、実際にマルチモジュールで管理しているする方も似たような悩みを抱えているかもしれません。ここで紹介した方法が最良の方法ではないと思いますが、少しでも参考になるとうれしいです。

TOAST Meetup 編集部

TOASTの技術ナレッジやお得なイベント情報を発信していきます
pagetop