とあるお兄さんの雑記

基本的に技術系の内容を書きますが、何を書くかは私の気分です。

Git Hooksの活用〜git pushする前に単体テストを実行する〜

コードを書く際、自身が作成した機能は皆さん必ずテストを書いていると思います。できるだけ品質を担保するためにもテストを回して全部通ってからgit pushした方がいいわけですが。

全てのテストを回す前にgit pushしちゃった!なんてことが度々ありまして。

というわけで、テスト回すことを忘れてgit pushしたときでも、自動的にテストが回るようにするGit Hooksを使ってみました。

環境

git version 2.30.0
conda 4.11.0
MacOS Monterey 12.2.1
pytest 7.1.1
python 3.9.12

pytestというものを使っていますが、今回はGit Hooksの簡単な説明なので、pytestについての説明は省略します。

Git Hooksについて

特定のアクションが発生したときにカスタムスクリプトを叩く方法で、pushやcommit時などのアクションに対して活用することが可能です。

詳細に関しては公式をご参照ください。

公式:8.3 Git のカスタマイズ - Git フック

設定

フックの設定ファイルは各ローカルリポジトリ.git/hooks配下に置いてあります。サンプルもあるので、それをコピーして中身と名前さえ修正すればすぐに使えるようになるでしょう。

私の場合はpre-pushというファイル名で以下のようにしてみました。ファイルの作成場所は.git/hooks/配下です。

#!/bin/bash

figlet EXECUTE TEST

pytest test
result=$?

if [ $result -eq 0 ]; then
  figlet -f rectangles TEST SUCCESS
else :
  figlet -f rectangles TEST FAILED ...
  exit $result
fi

ちなみに、ファイルを作成、編集しただけでは動いてくれません。権限が必要になります。

chmod a+x .git/hooks/pre-push

解説

figletについて

ちょっとおしゃれにしたかっただけです。必要ありませんが、もしfigletを使う場合は以下のようにインストールします。

brew install figlet

ちなみにfigletを使うと以下のようになります。

figlet Hello Figlet

 _   _      _ _         _____ _       _      _
| | | | ___| | | ___   |  ___(_) __ _| | ___| |_
| |_| |/ _ \ | |/ _ \  | |_  | |/ _` | |/ _ \ __|
|  _  |  __/ | | (_) | |  _| | | (_| | |  __/ |_
|_| |_|\___|_|_|\___/  |_|   |_|\__, |_|\___|\__|
                                |___/

...ちょっとおしゃれです。

pytest test

pytest:Python単体テストフレームワークの一つです。

pytest testでtestフォルダ配下のテストファイルを実行してくれます。

その後の処理

result=$?

if [ $result -eq 0 ]; then
  figlet TEST SUCCESS
else :
  figlet TEST FAILED ...
  exit $result
fi

pytest test以後の処理ですが、まずresult=$?で直前の処理の終了ステータスを変数resultに入れています。

テストが全て通っていれば終了ステータスは0、テストが落ちていた場合は0以外の値が返ってきます。

テストが落ちてしまった場合、終了ステータスが0以外のものが返ってくるため、gitにpushされることはありません。そのため、ちゃんと正常に動いているコードだけがgitに管理されていることになります。

設定が終わったのでgit pushしてみます。すると、以下のようになることが確認できます。

$ git push origin main

 _______  _______ ____ _   _ _____ _____   _____ _____ ____ _____
| ____\ \/ / ____/ ___| | | |_   _| ____| |_   _| ____/ ___|_   _|
|  _|  \  /|  _|| |   | | | | | | |  _|     | | |  _| \___ \ | |
| |___ /  \| |__| |___| |_| | | | | |___    | | | |___ ___) || |
|_____/_/\_\_____\____|\___/  |_| |_____|   |_| |_____|____/ |_|

==================================================================== test session starts =====================================================================
platform darwin -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0
rootdir: /Users/users/workspace/~~/~~
collected 12 items

test/ch02/test_ch02.py .....                                                                                                                           [ 41%]
test/ch03/test_ch03.py .....                                                                                                                           [ 83%]
test/ch04/test_ch04.py ..                                                                                                                              [100%]

===================================================================== 12 passed in 0.32s =====================================================================

 _____ _____ _____ _____    _____ _____ _____ _____ _____ _____ _____
|_   _|   __|   __|_   _|  |   __|  |  |     |     |   __|   __|   __|
  | | |   __|__   | | |    |__   |  |  |   --|   --|   __|__   |__   |
  |_| |_____|_____| |_|    |_____|_____|_____|_____|_____|_____|_____|

まとめ

今回はGit Hooksを使って、push前に単体テストを行う処理を追加しました。CI環境が準備できていないうちは、Git hooksを一時的に使ってみるのもいいかもしれません。

今回は単体テストをやってみましたが、他の記事を見る限りmainブランチへのpushの制御など他の使い方もできそうです。

参考

公式:8.3 Git のカスタマイズ - Git フック

Git Hooksでうっかりミスを防ぎたい

figlet:コマンドラインでアスキーアートを作りたい

Gitでpushする前にテストが通る事を確認する