Gitでコミット前にテストを実行し、成功したらコミットされるようにする


概要

「テストの実行を忘れがちなんだけど、なんかいい手はないものか。テストコードの修正を忘れたままコミットするのも防ぎたい」と友達に相談したら、「Gitのフックを使えばいいんじゃない?」って教えてもらったので、調査した。

前置き

Git hookとは

Gitで発生するアクションに応じて、任意のシェルスクリプトを実行することができる機能。
Git フック

クライアントサイドフックとサーバーサイドフックがあって、各々用途が違うんだけど、今回はクライアントサイドフックを利用する。

Git hookのテンプレート

テンプレートが下記のディレクトリに用意されているので、そのテンプレートをコピーして使うことも可能。

テンプレートの場所
$ ls /usr/local/share/git-core/templates/hooks/
applypatch-msg.sample  post-update.sample     pre-commit.sample  pre-rebase.sample   prepare-commit-msg.sample
commit-msg.sample      pre-applypatch.sample  pre-push.sample    pre-receive.sample  update.sample

コミット前にスクリプトを実行するためには

スクリプトの設置場所

コミット前(正確にはコミットメッセージが入力される前)は pre-commit フックを利用する。
参考例ではテンプレートの pre-commit.sample.git/hooks ディレクトリにコピーして、名前を変えた。
実行権限をつけることをお忘れなく。

設置例
$ cd {your_project}/.git/hooks
$ cp /usr/local/share/git-core/templates/hooks/pre-commit.sample pre-commit
$ chmod +x pre-commit

これでコミット前(git commit 実行時)に pre-commit スクリプトが実行されるようになった。

本題

コミット前にテストを実行するためには

下記の記事を参考にカスタマイズさせていただいた。
Gitでpushする前にテストが通る事を確認する

カスタマイズしたところは下記。

  • コミット前に実行したいので、スクリプト名を pre-commit に変更した
  • configurationを追加して Debug にした
  • SDKに iphonesimulator と指定すると、Watchアプリがターゲットに含まれていた場合にテストが通らないので、SDKの指定を行わないように修正した
出力されるエラー
Testing failed:
    Target specifies product type 'com.apple.product-type.watchkit2-extension', but there's no such product type for the 'iphonesimulator' platform
** TEST FAILED **

Testing an iOS and watchOS app on a simulator

スクリプト

pre-commit
#!/bin/sh

is_workspace=false #CocoaPods等を使用している場合はtrue
project_name="YourProject.xcodeproj" #CocoaPods等を使用している場合は YourProject.xcworkspace
project_path="`pwd`/${project_name}"
scheme="YourProject" #適宜設定して下さい
destination="platform=iOS Simulator,name=iPhone 8 Plus"

if $is_workspace; then
    xcodebuild -workspace $project_path -scheme $scheme -configuration "Debug" -destination "$destination" test
else
    xcodebuild -project $project_path -scheme $scheme -configuration "Debug" -destination "$destination" test
fi

status=$?

if [ $status -eq 0 ]; then
    /usr/bin/osascript -e 'display notification "Test success!" with title "xcodebuild"'
else
    /usr/bin/osascript -e 'display notification "Test failed...orz" with title "xcodebuild"'
fi

exit $status

まとめ

Git便利。
あと、ヒューマンエラーは「起こさないように人間が気を付ける」よりも、「起きないように技術で予防する」ほうがいいよね。