Skip to content

Instantly share code, notes, and snippets.

@s-shin
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save s-shin/3974b0df3ef69d54d49b to your computer and use it in GitHub Desktop.
Save s-shin/3974b0df3ef69d54d49b to your computer and use it in GitHub Desktop.
Git pre-commit sample for PHP
#!/usr/bin/env perl
use strict;
use warnings;
use Term::ANSIColor;
use Term::ReadLine;
my $term = Term::ReadLine->new('pre-commit');
BEGIN {
# STDOUTに吐いても良い気もするが、pre-commit.sampleがSTDERRに吐いているので
# このスクリプトでも原則STDERRに出力を行うことにする。
sub print_err { print STDERR @_ }
}
# ### PHP ###
# 参考:
# * http://blog.manaten.net/entry/645
# * https://github.com/FriendsOfPHP/PHP-CS-Fixer
# phpcsコマンドのチェック
my $is_phpcs_installed = not system('hash phpcs 2>/dev/null');
unless ($is_phpcs_installed) {
print_err colored('*** You should install PHP_CodeSniffer. ***', 'bold on_yellow');
print_err q{
URL: https://github.com/squizlabs/PHP_CodeSniffer
RUN: composer g require "squizlabs/php_codesniffer=*"
};
}
# php-cs-fixerコマンドのチェック
my $is_php_cs_fixer_installed = not system('hash php-cs-fixer 2>/dev/null');
unless ($is_php_cs_fixer_installed) {
print_err colored('*** You should install PHP Coding Standards Fixer. ***', 'bold on_yellow');
print STDERR q{
URL: http://cs.sensiolabs.org/
RUN: composer g require fabpot/php-cs-fixer
};
}
# stagedなPHPファイルの取得
my @modified_php_files = split /\n/,
`git diff-index --name-only --cached --diff-filter=ACMR HEAD | grep -e '\\.php\$'`;
exit unless @modified_php_files;
# 'php -l'によるコンパイルエラーチェック
my @compiling_results;
foreach my $php_file (@modified_php_files) {
# リダイレクトの順番は意図的(標準エラーを取得)。
my @compiling_result = `php -l $php_file 2>&1 1>/dev/null`;
# $?は直近のコマンド戻り値
if ($?) {
push @compiling_results, {
file => $php_file,
error => join("\n", @compiling_result),
};
}
}
if (@compiling_results) {
print_err colored('*** PHP Compilation Error! ***', 'bold on_red');
print_err "\n";
foreach my $result (@compiling_results) {
print_err '# ' . $result->{file}, "\n";
print_err $result->{error}, "\n";
}
exit 1;
}
# コミットを中断させるなら1にする。
my $reject_commit = 0;
# php-cs-fixerによる自動修正。
# phpcsより先に基本的な修正をしてしまう。
# 修正した時は自動修正が問題ないか確認できるようコミットを中断する。
if ($is_php_cs_fixer_installed) {
# php-cs-fixerコマンドは複数ファイルを同時に処理できない…
my @fixed_files;
foreach my $php_file (@modified_php_files) {
my @result = `php-cs-fixer fix --level=psr2 $php_file`;
if ($?) {
my $file = $result[0];
$file =~ s/^[ ]+\d\) (.*)$/$1/;
chomp $file;
push @fixed_files, $file;
}
}
if (@fixed_files) {
print_err colored('*** Some codes are automatically fixed! ***', 'bold on_red'), "\n";
print_err "\n";
print_err 'Automodified files:', "\n";
print_err " $_\n" foreach (@fixed_files);
print_err "\n";
print_err colored('Please check these changes and commit them.', 'bold'), "\n\n";
$reject_commit = 1;
}
}
# phpcsによるコーディングスタイルチェック
if ($is_phpcs_installed) {
my $files = join ' ', @modified_php_files;
my @phpcs_result = `phpcs --standard=PSR2 --encoding=utf-8 --report=full $files`;
if ($?) {
print_err colored('*** You should review the coding style! ***', 'bold on_yellow'), "\n";
print_err @phpcs_result, "\n";
# 修正を促す
unless ($reject_commit) {
my $input = $term->readline('Fix them? (Y/n) ');
$reject_commit = 1 if !$input || lc($input) ne 'n';
print_err "\n";
}
}
}
if ($reject_commit) {
print_err 'This commit is aborted.', "\n";
}
print_err "\n";
exit $reject_commit;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment