はじめに

PHP ファイルを Git リポジトリに登録(commit)する時に、PHP-CS-Fixer で自動整形を必須にする方法を調べた。

.git/hooks/pre-commit でも実現できるが、できればチームメンバー内で共有したい(git clone (してゴニョゴニョ)するだけで使えるようにしたい)ので、もう少し突っ込んで調べてみた。

TL;DR

  • husky + lint-staged + php-cs-fixer でコミット時の自動整形を実現可能
  • husky を使うと、package.json で クライアントサイドの Git hooks(pre-commit など)を利用できる
  • lint-staged を使うと、ファイル種別ごとにコマンドを実行できる
  • husky + lint-staged で、*.php の commit 時に php-cs-fixer を実行する
この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. セットアップ
      1. インストール
      2. package.json 変更
      3. .gitignore 変更
    2. 検証
    3. 複数ファイルでも動作できるようにする
  5. まとめ
  6. その他・メモ
  7. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G95

$ node -v
v12.7.0

$ npm -v
6.10.3

$ npm v husky
husky@3.0.5 | MIT | deps: 11 | versions: 127

$ npm v lint-staged
lint-staged@9.2.5 | MIT | deps: 14 | versions: 106

$ php -v
PHP 7.1.23 (cli) (built: Feb 22 2019 22:19:32) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

$ composer -V
Composer version 1.9.0 2019-08-02 20:55:32

$ composer show friendsofphp/php-cs-fixer
versions : * v2.15.3

詳細

検証に使ったリポジトリ: 17number/php-auto-format-with-husky-example

セットアップ

インストール

husky, lint-staged のインストール(npm)

1
$ npm i -D husky lint-staged

friendsofphp/php-cs-fixer のインストール(composer)

1
$ composer require --dev friendsofphp/php-cs-fixer

package.json 変更

  • pre-commit フックで lint-staged を実行するようにして、
  • lint-staged.php ファイルに対して php-cs-fixer fix で整形し、
  • 整形後のファイルを git add で commit 前にステージングする
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   "devDependencies": {
"husky": "^3.0.5",
"lint-staged": "^9.2.5"
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "*.php": [
+ "vendor/bin/php-cs-fixer fix",
+ "git add"
+ ]
}
}

.gitignore 変更

php-cs-fixer を実行すると、.php_cs.cache が生成されるので、.gitignore に追加

1
$ echo .php_cs.cache >> .gitignore

検証

適当なサンプルコードで動作を検証する。

1
2
<?php
if(true){echo true;}else{echo false;}

上記内容で sample.php を作成し git add でステージング。git diff --cached で見ると以下の状態、紛うことなきクソコード。

1
2
3
4
5
6
7
8
diff --git a/sample.php b/sample.php
index 5b2e1eb..e06f327 100644
--- a/sample.php
+++ b/sample.php
@@ -1,2 +1,2 @@
<?php
-if(true){echo true;}
+if(true){echo true;}else{echo false;}

このまま git commit -m でコミットすると、huskylint-stagedphp-cs-fixer と動作して、整形されたコードがコミットされる。

1
2
3
4
5
6
7
$ git commit -m "chore: do php-cs-fixer on pre-commit"
husky > pre-commit (node v12.7.0)
↓ Stashing changes... [skipped]
→ No partially staged files found...
✔ Running tasks...
[master 345c35a] chore: do php-cs-fixer on pre-commit
1 file changed, 5 insertions(+), 1 deletion(-)

実際にコミットされたファイルは下記、(中身は無いが) php-cs-fixer による恩恵を何も意識せずに受けれていることが分かる。

1
2
3
4
5
6
<?php
if (true) {
echo true;
} else {
echo false;
}

複数ファイルでも動作できるようにする

これで万事 OK かと思ったが、そうはいかなかった。

試しに複数ファイルをコミットしてみると For multiple paths config parameter is required. と怒られてしまう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: fuga.php
new file: hoge.php


$ git commit -m "multiple files"
husky > pre-commit (node v12.7.0)
↓ Stashing changes... [skipped]
→ No partially staged files found...
❯ Running tasks...
❯ Running tasks for *.php
✖ vendor/bin/php-cs-fixer fix
git add

✖ vendor/bin/php-cs-fixer fix found some errors. Please fix them and try committing again.

In ConfigurationResolver.php line 581:

For multiple paths config parameter is required.

fix [--path-mode PATH-MODE] [--allow-risky ALLOW-RISKY] [--config CONFIG] [--dry-run] [--rules RULES] [--using-cache USING-CACHE] [--cache-file CACHE-FILE] [--diff] [--diff-format DIFF-FORMAT] [--format FORMAT] [--stop-on-violation] [--show-progress SHOW-PROGRESS] [--] [<path>...]
husky > pre-commit hook failed (add --no-verify to bypass)

複数ファイルをコミット(して php-cs-fixer による整形)するためには、コンフィグファイルを用意してオプションを追加する必要がある。

Config file を参考に、以下の内容で .php_cs.dist を作成。ひとまずデフォルトルールで動作させたいので、setRules はコメントアウトする。

1
2
3
4
5
6
7
8
9
10
<?php
$finder = PhpCsFixer\Finder::create()
->exclude('')
->in(__DIR__)
;
$rules = []; // 必要に応じて設定
return PhpCsFixer\Config::create()
//->setRules($rules) // 必要に応じて設定
->setFinder($finder)
;

package.json を修正して、コンフィグファイルを指定する。

1
2
3
4
5
6
7
     "lint-staged": {
"*.php": [
- "vendor/bin/php-cs-fixer fix",
+ "vendor/bin/php-cs-fixer --config=.php_cs.dist fix",
"git add"
]
}

コミットしてみる。

1
2
3
4
5
6
7
8
9
$ git commit -m "chore: multiple file test"
husky > pre-commit (node v12.7.0)
↓ Stashing changes... [skipped]
→ No partially staged files found...
✔ Running tasks...
[master e36f73f] chore: multiple file test
2 files changed, 4 insertions(+)
create mode 100644 fuga.php
create mode 100644 hoge.php

複数ファイルでも問題なく動作するようになった。

まとめ

  • husky + lint-staged + php-cs-fixer でコミット時の自動整形を実現可能
  • husky を使うと、package.json で クライアントサイドの Git hooks(pre-commit など)を利用できる
  • lint-staged を使うと、ファイル種別ごとにコマンドを実行できる
  • husky + lint-staged で、*.php の commit 時に php-cs-fixer を実行する

その他・メモ

今回の記事は以下の2サイトの内容を(部分的に)組み合わせただけ、先人に感謝。

(今回は php-cs-fixer しか使っていないが) 以下の参考サイトにも出てくる通り、php -l でのシンタックスチェックなどもう少し厳密なチェックをすると良さそう。

PHP 以外でも普通に使えると思う。

参考文献

関連記事

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list