diff --git a/README.md b/README.md index ba5e6617..b565602a 100644 --- a/README.md +++ b/README.md @@ -530,6 +530,7 @@ issue](https://github.com/brigade/overcommit/issues/238) for more details. * [NginxTest](lib/overcommit/hook/pre_commit/nginx_test.rb) * [PhpCs](lib/overcommit/hook/pre_commit/php_cs.rb) * [PhpLint](lib/overcommit/hook/pre_commit/php_lint.rb) +* [PhpStan](lib/overcommit/hook/pre_commit/php_stan.rb) * [Pronto](lib/overcommit/hook/pre_commit/pronto.rb) * [PuppetLint](lib/overcommit/hook/pre_commit/puppet_lint.rb) * [PuppetMetadataJsonLint](lib/overcommit/hook/pre_commit/puppet_metadata_json_lint.rb) diff --git a/config/default.yml b/config/default.yml index 2cba095b..95fcb7f1 100644 --- a/config/default.yml +++ b/config/default.yml @@ -498,6 +498,14 @@ PreCommit: flags: ['--standard=PSR2', '--report=csv'] include: '**/*.php' + PhpStan: + description: 'Analyze with phpstan' + enabled: false + command: 'phpstan' + flags: ['analyze', '--errorFormat=raw'] + include: + - '**/*.php' + Pronto: enabled: false description: 'Analyzing with pronto' diff --git a/lib/overcommit/hook/pre_commit/php_stan.rb b/lib/overcommit/hook/pre_commit/php_stan.rb new file mode 100644 index 00000000..7b2c821b --- /dev/null +++ b/lib/overcommit/hook/pre_commit/php_stan.rb @@ -0,0 +1,28 @@ +module Overcommit::Hook::PreCommit + # Runs `phpstan` against any modified PHP files. + # For running `phpstan` with Laravel, it requires setup with `ide_helper`. + # + # References: + # https://github.com/phpstan/phpstan/issues/239 + # https://gist.github.com/edmondscommerce/89695c9cd2584fefdf540fb1c528d2c2 + class PhpStan < Base + MESSAGE_REGEX = /^(?.+)\:(?\d+)\:(?.+)/ + + def run + messages = [] + + result = execute(command, args: applicable_files) + + unless result.success? + messages += result.stdout.lstrip.split("\n") + end + + return :pass if messages.empty? + + extract_messages( + messages, + MESSAGE_REGEX + ) + end + end +end diff --git a/spec/overcommit/hook/pre_commit/php_stan_spec.rb b/spec/overcommit/hook/pre_commit/php_stan_spec.rb new file mode 100644 index 00000000..58e004c4 --- /dev/null +++ b/spec/overcommit/hook/pre_commit/php_stan_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Overcommit::Hook::PreCommit::PhpStan do + let(:config) { Overcommit::ConfigurationLoader.default_configuration } + let(:context) { double('context') } + subject { described_class.new(config, context) } + + before do + subject.stub(:applicable_files).and_return(%w[sample.php]) + end + + context 'when phpstan exits successfully' do + before do + sample_output = '' + + result = double('result') + result.stub(:success?).and_return(true) + result.stub(:stdout).and_return(sample_output) + result.stub(:status).and_return(0) + subject.stub(:execute).and_return(result) + end + + it { should pass } + end + + context 'when phpstan exits unsuccessfully' do + let(:result) { double('result') } + + before do + result.stub(:success?).and_return(false) + result.stub(:status).and_return(2) + subject.stub(:execute).and_return(result) + end + + context 'and it reports a warning' do + before do + sample_output = [ + '/sample1.php:14:Call to an undefined static method Sample1::where()', + '/sample2.php:17:Anonymous function has an unused use $myVariable.' + ].join("\n") + result.stub(:stdout).and_return(sample_output) + end + + it { should fail_hook } + end + end +end