■git commit時にphpcsを実行
・変更した行にphpcsエラーがある場合、phpcsエラーを出力し、コミットをキャンセルします
・phpcsエラー箇所が既にコミット済みの場合はスルーします
・「PhpcsCheckIgnore.txt」に記載されたphpファイルは、phpcsチェックを行いません
■インストール
1)[プロジェクト]/.git/hooks配下に下記ファイルを格納
・commit-msg
・PhpcsCheck.php
・PhpcsCheckIgnore.txt
2)commit-msgに実行権限を付与
chmod +x commit-msg
XXXXXXXXXXXXXXXXXX
currentDir=$(cd $(dirname $0); pwd)
parentDir=${currentDir/.*/}
isError=false
for file in $(git diff --cached --name-only)
do
echo "${file}"
result=$(php ${currentDir}/PhpcsCheck.php ${parentDir} ${file} 2>/dev/null)
if [ $? -ne 0 ]; then
isError=true
fi
if [ -n "$result" ]; then
echo "${result}"
fi
done
if $isError ; then
echo "[PHPCS ERROR] has not passed"
exit 1
fi
echo "[PHPCS SUCCESS] passed all"
exit 0
<?php
@category
@package
@author @example
@license
@link
$dir = $argv[1];
$file = $argv[2];
$debugLogFile = "${dir}.git/hooks/PhpcsCheck.log";
if (checkParameter($dir, $file) === false) {
exit(1);
}
if (checkIgnore($dir, $file) === false) {
exit(0);
}
$phpcsErrorList = getPhpcsErrorList($dir, $file);
$diffList = getDiffList($dir, $file);
$phpcsErrorInfo = outputPhpcsError($file, $phpcsErrorList, $diffList);
if ($phpcsErrorInfo !== "") {
echo $phpcsErrorInfo;
exit(1);
}
exit(0);
@param
@param
@return
function checkParameter($dir, $file)
{
$ret = true;
if (file_exists("${dir}${file}") === false) {
echo "${dir}${file} は存在しないファイルパスです\n";
$ret = false;
}
debugLog("[checkParameter] dir=${dir} file=${file} ${ret}");
return $ret;
}
@param
@param
@return
function checkIgnore($dir, $file)
{
$ret = true;
$lines = file("${dir}.git/hooks/PhpcsCheckIgnore.txt");
foreach ($lines as $line) {
if (substr($line, 0, 1) === "#") {
continue;
}
if (trim($line) === $file) {
echo "${file} は除外対象のため、phpcsチェックを行いません";
$ret = false;
break;
}
}
debugLog("[checkIgnore] file=${file} ${ret}");
return $ret;
}
@param
@param
@return
function getPhpcsErrorList($dir, $file)
{
$result = array();
$command = "phpcs ${dir}${file} 2>/dev/null";
$outputs = execCommand($command);
foreach ($outputs as $output) {
if (isLineNumber($output) === true) {
$itemList = explode("|", $output);
$result[trim($itemList[0])] = $output;
}
}
debugLog("[getPhpcsErrorList] ".implode("\n", $result));
return $result;
}
@param
@param
@return
function getDiffList($dir, $file)
{
$result = array();
$command .= "git --no-pager diff --cached --no-ext-diff ";
$command .= "-U1000000 ${file} 2>/dev/null";
$outputs = execCommand($command);
$lineNumber = -1;
foreach ($outputs as $output) {
if (trim($output) === "<?php") {
$lineNumber = 0;
}
if ($lineNumber >= 0) {
if (substr($output, 0, 1) === "-") {
continue;
}
$lineNumber += 1;
if (substr($output, 0, 1) === "+") {
$result[$lineNumber] = $lineNumber;
}
}
}
debugLog("[getDiffList] ".implode(",", $result));
return $result;
}
@param
@param
@param
@return
function outputPhpcsError($file, $phpcsErrorList, $diffList)
{
$result = array();
$phpcsErrorInfo = "";
foreach ($diffList as $diff) {
if (array_key_exists($diff, $phpcsErrorList)) {
$result[] = $phpcsErrorList[$diff];
}
}
if (empty($result) === false) {
foreach ($result as $item) {
$phpcsErrorInfo .= $item."\n";
}
}
debugLog("[outputPhpcsError] ${phpcsErrorInfo}");
return $phpcsErrorInfo;
}
@param
@return
function execCommand($command)
{
$outputs = "";
$status = "";
exec($command, $outputs, $status);
debugLog("[execCommand] ${command} ${status}");
return $outputs;
}
@param
@return
function debugLog($output)
{
$date = date("Y/m/d H:i:s");
global $debugLogFile;
$ret = error_log("${date} ${output}\n", 3, $debugLogFile);
}
@param
@return
function isLineNumber($target)
{
if ($target === "") {
return false;
}
if (substr($target, 0, 1) === "-") {
return false;
}
$skipList = array("/^FOUND /", "/^Time: /", "/^FILE: /");
foreach ($skipList as $skip) {
if (preg_match($skip, $target) === true) {
return false;
}
}
return true;
}
# 除外対象ファイルを記載します(phpcsチェックを行いません)
# 例)test/app/action/Main/CRUD.php