1
0

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.

gitの「pre-commit」を使って静的テストをする

Posted at

概要

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.phptest_error.php
    検証用のテストコードです。
  • git_template
    pre-commitを各々の開発環境に適用するために、設定ファイルを格納する。
  • composer.jsonvender
    phpmdを使うためのパッケージ設定ファイルです。

pre-commitについて

pre-commit」とは、gitの特定のアクションが発生した時にカスタムスクリプトを叩くことが出来るGitフックという機能の一部で、pre-commitを設定することによりコミット直前のイベントを定義することが出来ます。
他にpush、rebase、merge時のイベントなども定義できます。詳細はこちら

設定関連ファイルを作成

  • phpmdを使うので composer.jsonを作成
composer.json
{
    "require": {
        "phpmd/phpmd" : "@stable"
    }
}
  • コミット直前にしたい処理を記述した"git_template/hooks/pre-commit"を作成
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ファイルをコピーできるようにします。

composer.json
{
    "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-cmdcomposerが特定の処理で勝手に呼び出してくれるイベントです。他にも たくさんあります

検証環境の準備

ここまでで

  • composer.json
  • git_template/hooks/pre-commit

の2ファイルが出来たので、git初期化およびパッケージのインストールをしていきます。

## git初期化
git init

## パッケージインストール(ここでpre-commitのコピーも行われます。)
composer install

検証用のコードを作成

  • エラー無:test_success.php
test_success.php
<?php
class MdTest
{

    public function testFunction()
    {
        print "md test dayo!!";
    }
}

$hoge = new MdTest();
$hoge->testFunction();
  • エラー有:test_error.php
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がキャメルケースになってないよ!

なので、修正します。

test_error.php
<?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

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?