概要
git
に用意されているフック機能を使ってコミット直前に静的テストを行えるようにしてみる。
キーワードは、
- pre-commit : gitのhook機能でコミット直前の処理を定義できる
- PHP Lint : PHP標準のシンタックスチェック機能
- phpmd : PHPの静的コード解析ツール
の3つになります。
実行環境
- CentOS 7.6
- PHP 7.2.24
ディレクトリ構成
検証用に作成したディレクトリ構成になります。
app:
├─.gitignore
├─composer.json
├─composer.lock
├─test_success.php
├─test_error.php
│
├─vendor
│
└─git_template
└─hooks
└─pre-commit
主なのだけ説明
-
test_success.php
、test_error.php
検証用のテストコードです。 -
git_template
pre-commit
を各々の開発環境に適用するために、設定ファイルを格納する。 -
composer.json
、vender
phpmd
を使うためのパッケージ設定ファイルです。
pre-commitについて
「pre-commit」とは、gitの特定のアクションが発生した時にカスタムスクリプトを叩くことが出来るGitフックという機能の一部で、pre-commitを設定することによりコミット直前のイベントを定義することが出来ます。
他にpush、rebase、merge時のイベントなども定義できます。詳細はこちら。
設定関連ファイルを作成
- phpmdを使うので composer.jsonを作成
{
"require": {
"phpmd/phpmd" : "@stable"
}
}
- コミット直前にしたい処理を記述した"git_template/hooks/pre-commit"を作成
#!/bin/sh
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
exec 1>&2
EXIT_CODE=0
error_check() {
if [ $1 -gt 0 ]; then
EXIT_CODE=$1
fi
}
cecho () {
str=$1
color=$2
echo -e "\033[0;${color}m${str}\033[0;39m"
}
cecho '##########################' 32
cecho '# Checking PHP syntax... #' 32
cecho '##########################' 32
echo ''
for CHECK_FILE in `git diff-index --name-status ${against} -- | grep -E '^[AUM].*\.php$' | cut -c3-`; do
cecho "check... ${CHECK_FILE}" 32
php -l ${CHECK_FILE}
error_check $?
done
echo ''
cecho '################' 32
cecho '# Run phpmd... #' 32
cecho '################' 32
for CHECK_FILE in `git diff-index --name-status ${against} -- | grep -E '^[AUM].*\.php$' | cut -c3-`; do
cecho "check... ${CHECK_FILE}" 32
vendor/bin/phpmd ${CHECK_FILE} text codesize,design,naming,unusedcode,controversial
error_check $?
done
if [ ${EXIT_CODE} -gt 0 ]; then
cecho 'Commit Failed...' 31
else
cecho 'Pre commit check all green!!' 32
fi
echo ''
exit ${EXIT_CODE}
処理の詳細は省きますが、やってることは
① git
の差分ファイルを取得
② phpのLint
で検証
③ phpmd
で検証。例では「codesize,design,naming,unusedcode,controversial
」が検証ルールです。
それぞれのルールは以下のような感じです。 ※抜粋
- codesize:循環的複雑度などコードサイズ関連部分を検出するルール
- controversial:キャメルケースなど議論の余地のある部分を検出するルール
- design:ソフトの設計関連の問題を検出するルール
- naming:長すぎたり、短すぎたりする名前を検出するルール
- unusedcode:使われていないコードを検出するルール
④ ②③で問題が発生していた場合コミットを中止
な流れです。
…まぁエラソーに書いてますが、ソースは9割がたネットで拾ったやつです。
pre-commitはgit管理対象外の場所にいるのでなんとかする
なんとかなってないかもです。
完全に自動化する方法があれば良いのですが、今回は思いつかなかったのでcomposerを利用しました。
git hooksは.git/hooks
に予約語名称で保存する必要があるので、「pre-commit
」という名称のファイルを設置します。
ってことでcomposer.jsonを以下の用に変更して、git_template
配下のpre-commit
ファイルをコピーできるようにします。
{
"require": {
"phpmd/phpmd" : "@stable"
},
"scripts": {
"post-install-cmd": [
"@setting_git"
],
"setting_git": [
"cp -rf git_template/hooks .git/ ",
"chmod a+x .git/hooks/pre-commit"
]
}
}
これでcomposer install
またはcomposer setting_git
でhooksファイルを更新出来るようになりました。
※post-install-cmd
はcomposer
が特定の処理で勝手に呼び出してくれるイベントです。他にも たくさんあります
検証環境の準備
ここまでで
- composer.json
- git_template/hooks/pre-commit
の2ファイルが出来たので、git初期化およびパッケージのインストールをしていきます。
## git初期化
git init
## パッケージインストール(ここでpre-commitのコピーも行われます。)
composer install
検証用のコードを作成
- エラー無:test_success.php
<?php
class MdTest
{
public function testFunction()
{
print "md test dayo!!";
}
}
$hoge = new MdTest();
$hoge->testFunction();
- エラー有:test_error.php
<?php
class MdTest
{
public function test_function($un_used)
{
print "md test dayo!!";
}
}
$hoge = new MdTest();
$hoge->test_function()
実行結果は以下な感じです。
php test_success.php
> md test dayo!!
php test_error.php
> PHP Parse error: syntax error, unexpected end of file in /home/vagrant/tmp/test/test_error.php on line 12
とまぁ当然test_error.phpの方はエラーになります。
エラーの状態と正常な状態それぞれでcommitしてみる
まずはエラーの状態で、
addして、
git add test_error.php
git add test_success.php
commit!
git commit -m "test dayo"
結果
##########################
# Checking PHP syntax... #
##########################
check... test_error.php
PHP Parse error: syntax error, unexpected end of file in test_error.php on line 12
Errors parsing test_error.php
check... test_success.php
No syntax errors detected in test_success.php
################
# Run phpmd... #
################
check... test_error.php
/home/vagrant/tmp/test2/test_error.php:5 Avoid unused parameters such as '$un_used'.
/home/vagrant/tmp/test2/test_error.php:5 The method test_function is not named in camelCase.
/home/vagrant/tmp/test2/test_error.php - Unexpected end of token stream in file: /home/vagrant/tmp/test2/test_error.php.
Commit Failed...
想定通りエラーになり、コミットが取り消されました。
エラー内容はざっくり
- 【Lint】12行目にシンタックスエラーがあるよ!
- 【phpmd】5行目に$un_usedっていう使ってない変数があるよ!
- 【phpmd】5行目の
test_function
がキャメルケースになってないよ!
なので、修正します。
<?php
class MdTest
{
public function testFunction($unUsed)
{
print "md test dayo!!{$unUsed}\n";
}
}
$hoge = new MdTest();
$hoge->testFunction(' tukatteruyo!!');
これで再度add,commit!!
git add test_error.php
git commit -m "test dayo"
結果
##########################
# Checking PHP syntax... #
##########################
check... test_error.php
No syntax errors detected in test_error.php
check... test_success.php
No syntax errors detected in test_success.php
################
# Run phpmd... #
################
check... test_error.php
check... test_success.php
Pre commit check all green!!
オールグリーン!上手くいきました。
参考URL