SHOYAN BLOG

レガシーコード向けに修正した部分だけPHP構文チェックをする仕組みを作った

修正した部分だけPHPの構文チェックをする仕組みを作ってみました。
構文に問題があればGithubのPull Requestにコメントされます。

2016-06-23_php-syntax-check

この方法のよいところは既存のソースを変えることなくPHPの構文チェックの仕組みを導入できることです。
規約に沿っていないコードが大量にあり、かつテストコードがないような環境(レガシー環境)にも導入することができます。

使用したツールは以下です。

また、packsaddleのツールはRuby製ですので、Rubyが動作する環境が必要です。

サンプルとしてGithubにphp-syntax-checkというリポジトリを作成しているので参考にしてください。

以下のスクリプトをCircleCIで実行しています。

check_syntax.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

echo "Start"
LIST=`git diff --name-only origin/master | grep -e '.php$'`

if [ -z "$LIST" ]; then
    echo "PHP file not changed."
    exit 0
fi

if [ -n "$CI_PULL_REQUEST" ]; then
    git diff --name-only origin/master \
        | grep -e '.php$' \
        | xargs vendor/bin/phpcs -n --standard=PSR2 --report=checkstyle \
        | bundle exec checkstyle_filter-git diff origin/master \
        | bundle exec saddler report \
        --require saddler/reporter/github \
        --reporter Saddler::Reporter::Github::PullRequestReviewComment
fi

仕組み

以下の3つのセクションに分類されます。

  • 対象のファイルを抽出
  • 構文チェック
  • 結果をレポート

1. 対象のファイルを抽出

以下のコマンドでmasterと差分のあるファイル名を取得します。

1
git diff --name-only origin/master

さらに grepで拡張子が .phpのファイルのみ対象にします。

1
git diff --name-only origin/master | grep -e ‘.php$'

2. 構文チェック

構文チェックツールは好きなものを使えます(CheckStyleフォーマットで出力できるものに限りますが)。
今回はPHP_CodeSnifferを使いました。

1
xargs vendor/bin/phpcs -n --standard=PSR2 --report=checkstyle

xargsは前のコマンドを引数でとるために必要です。

以下のコマンドでmasterとブランチの差分をチェックして、差分があるところのエラーを検知対象のエラーとしています。

1
bundle exec checkstyle_filter-git diff origin/master

エラーの差分の抽出にcheckstyle_filter-gitというツールを使っています。
これは、入力として渡したCheckStyle formatの文字列から、変更した内容の部分のエラーを抽出するツールです。
例えばファイルの10行目〜15行目を変更した場合、その行で発生したエラーのみを抽出します。

3. 結果をレポート

saddlerを使って結果をGithubに通知します。

1
2
3
bundle exec saddler report \
        --require saddler/reporter/github \
        --reporter Saddler::Reporter::Github::PullRequestReviewComment

注意点としては、PRを作っていないと通知でエラーとなります。

ですので、Pull Requestがあるかどうかをチェックするif文をいれています。
$CI_PULL_REQUEST はCIrcleCIの変数で、Pull Requestが作られていればこの変数にURLが格納されています。

1
2
3
if [ -n "$CI_PULL_REQUESTS" ]; then

fi

また、通知にはGITHUB_ACCESS_TOKENを発行して環境変数に登録しておく必要があります。

CircleCIの環境変数の設定については、以下を参照ください。

また、通知ではなく単に結果を出力する場合は、saddler/reporter/textを指定します。

1
2
3
bundle exec saddler report \
  --require saddler/reporter/text \
  --reporter Saddler::Reporter::Text

以下は、出力があった場合はエラーにする例です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RESULT=`git diff --name-only origin/master \
    | grep -e '.php$' \
    | xargs vendor/bin/phpcs -n --standard=custom_ruleset.xml --report=checkstyle \
    | bundle exec checkstyle_filter-git diff origin/master \
    | bundle exec saddler report \
      --require saddler/reporter/text \
      --reporter Saddler::Reporter::Text`

if [ -n "$RESULT" ]; then
    echo ""
    echo "An error has been detected,this following:"
    echo "$RESULT"
    exit 1
fi

その他

ファイルのエンコードがEUC-JPのソースコードに適用したところエラーとなりました。 リポジトリをフォークして対応しました。
1.1.0より使えるようになりました!

以下のように設定します。

Gemfile

1
gem "checkstyle_filter-git", git: "https://github.com/shoyan/ruby-checkstyle_filter-git.git", branch: "implement-exec"

iconvでgit diffの出力結果の文字コードをEUC-JP->UTF-8に変換して渡せるようにしました。

1
2
3
4
git diff --name-only origin/master \
  | grep -e '.php$' \
  | xargs phpcs -n --standard=custom_ruleset.xml --report=checkstyle \
  | bundle exec checkstyle_filter-git exec "git diff origin/master | iconv -f EUCJP -t UTF8"

PRもしているので直ることに期待です。
Mergeいただきました。

サンプルとしてGithubにphp-syntax-checkというリポジトリを作成しているので参考にしてください。

関連記事

参考リンク

よく読まれている記事

Comments