6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LaravelAdvent Calendar 2022

Day 8

【Laravel Pint & Git Hooks】pre-commitを使ってレビューをもっと楽にしよう

Last updated at Posted at 2022-10-25

無駄なコードレビューで疲弊していませんか?

Linterを使わないと、実装とは無関係の差分が発生しがちです。
レビューの質にも関わってくるので、この辺はコードをコミットする前に自動で直しましょう。

  • インデントの階層違い
  • if() or if ()
  • !$bool or ! $bool
  • その他諸々。。。

目標

Laravel PintGit Hooks(pre-commit)を使って、コミット前にLintを走らせる。
実装とは関係ない差分をコードレビュー前に排除して、レビューをもっと楽にする。

前提条件

  • Laravelプロジェクト作成済
  • プロジェクトがGit管理されている
  • PHPがローカル環境またはDockerコンテナ内にインストール済
  • Composerがローカル環境またはDockerコンテナ内にインストール済

手順

1. Laravel Pintインストール

公式ドキュメント曰く、最近のLaravelだと標準でインストールされているそうです。
Composer.jsonの中を確認して、laravel/pintの表記がある場合は、飛ばしてください。

composer require laravel/pint --dev

2. pre-commit用シェルスクリプト用意

.git/hooksディレクトリの中を見ると、以下のようにGit Hooksに関するサンプルスクリプトが用意されています。

スクリーンショット 2022-10-25 13.23.16.png

今回使用したいのは、pre-commit.sampleです。
しかし、.gitディレクトリはGit管理下に含めることができません。
つまり、このままではチームメンバーにpre-commitのスクリプトを使用してもらうことができません。

そこで、Git管理できるように別ディレクトリを作成してその中にpre-commitのスクリプトを作成します。

# プロジェクトのトップディレクトリにいる前提
#1. ディレクトリ作成(ディレクトリ名は何でもOK)
mkdir .githooks

#2. pre-commitシェルスクリプトをコピー
cp .git/hooks/pre-commit.sample .githooks/pre-commit

#3. 実行権限を付与
chmod +x .gihooks/pre-commit

#4. pre-commitの中身を変更
vim .githooks/pre-commit

中身は以下のように書き換えてください。

#!/bin/sh
fileList=$(git diff --diff-filter=d --cached --name-only)

phpFiles=$(echo "$fileList" | grep -E '\.(php)$')

if [ ${#phpFiles} -gt 0 ]; then
  # Lintスタート
  echo 'Start Linting with laravel/pint.'
  docker exec app ./vendor/bin/pint ${phpFiles[*]} "$@"
  # エラーがあれば、コミットさせない
  if [ $? -gt 0 ]; then
    exit 1
  fi
  # エラーがなければ、Linterが変更した差分を取り込んでコミット
  git add ${phpFiles[@]}
fi

以下の部分に関しては、Laravel/Pintが走れば何でも大丈夫です。
私の場合は、Docker内にPHPがインストールされているので、dockerコマンドにて実行しています。

docker exec app ./vendor/bin/pint ${phpFiles[*]} "$@"

3. .githooksディレクトリをHooksのコアディレクトリに指定

手順2の段階では、コミットしてもまだpre-commitスクリプトは走りません。
なぜなら、デフォルトでは.git/hooksディレクトリ内のpre-commitなどを実行するからです。

なので、今回新規作成した.githooksディレクトリの中を見るように設定を変更しましょう。

git config --local core.hooksPath .githooks

↑このコマンドを打つだけです。
.githooksの部分は、作成したディレクトリ名に合わせてください。

4. pre-commit実行確認

PHPファイルを適当に編集して、コミットしてみましょう。

//正常
    public function handle(Admin $admin): ?bool
    {
        return DB::transaction(fn () => $admin->delete());
    }

    //↓↓↓ fn()部分を編集

//エラー
    public function handle(Admin $admin): ?bool
    {
        return DB::transaction(fn() => $admin->delete());
    }
# 1. 編集したファイルをステージングに上げる
git add {編集したPHPファイル名}

# 2. コミットする
git commit -m "commit with pre-commit"

# 3. Laravel/Pintが走ることを確認
Start Linting with laravel/pint.

  ✓

  ──────────────────────────────────────────────────────────────────── Laravel  
    FIXED   ...................................... 1 file, 1 style issue fixed  
  ✓ app/Actions/DeleteAdmin.php   function_declaration  

[feature/pint 86bda9c4] pre-commit

# 4. コミット履歴確認
git log

コミット履歴に、1つ新規コミットが追加されています。
加えて、編集したファイルを確認してみると正しい記述に自動で修正されています。

手順としては、以上となります。

よくある質問

1. Git Hooksのコアディレクトリ設定は毎回手動でコマンド入力が必要?

最初のcomposer install時に自動でこのコマンドを走らせるようにしましょう。
Composer.json内のscriptsの中にコマンドを追加します。

{
  "scripts": {
     "post-install-cmd": [
        "git config --local core.hooksPath .githooks"
     ],
  }
}

こうすることで、新しいメンバーがジョインした時にも手動入力なしで即座にpre-commit適用が可能です。

2. PHPファイル以外の差分しかない場合はどうなる?

Laravel/Pintが走るのは、PHPファイルの差分がある時だけです。
.json.htmlにのみ差分がある場合は、Lint無しでコミットされます。

3. Lint実行時にエラーが起こった場合はどうなる?

Lint実行時に、エラーが起こった場合はコミットされません。
エラー内容を確認して、エラー解消してから再度コミットしてください。

参考文献

https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
https://efcl.info/2021/08/21/git-precommit-hook/
https://markus.oberlehner.net/blog/lint-only-files-with-changes-on-pre-commit/

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?