Skip to content

Commit e29265e

Browse files
taufeksds
authored andcommitted
Add PhpStan (PHP Static Code Analyser) PreCommit Hook
Added [PhpStan](https://github.com/phpstan/phpstan) PreCommit Hook. **Example Files Change** ``` // app/foo.php <?php namespace App; class Foo { public function __construct($foo, $test) { $this->foo = $foo; } } // app/bar.php <?php namespace App; class Bar { public function __construct($foo) { $this->foo = $foo; } private function testMe() { return $this->hello; } } ``` **Example Error Messages*** ``` Running pre-commit hooks Analysing PHP codes...............................[PhpStan] FAILED Errors on modified lines: /app/bar.php:9:Access to an undefined property App\Bar::$foo. /app/bar.php:14:Access to an undefined property App\Bar::$hello. /app/foo.php:7:Constructor of class App\Foo has an unused parameter $test. /app/foo.php:9:Access to an undefined property App\Foo::$foo. ✗ One or more pre-commit hooks failed ```
1 parent 07adca8 commit e29265e

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ issue](https://github.com/brigade/overcommit/issues/238) for more details.
530530
* [NginxTest](lib/overcommit/hook/pre_commit/nginx_test.rb)
531531
* [PhpCs](lib/overcommit/hook/pre_commit/php_cs.rb)
532532
* [PhpLint](lib/overcommit/hook/pre_commit/php_lint.rb)
533+
* [PhpStan](lib/overcommit/hook/pre_commit/php_stan.rb)
533534
* [Pronto](lib/overcommit/hook/pre_commit/pronto.rb)
534535
* [PuppetLint](lib/overcommit/hook/pre_commit/puppet_lint.rb)
535536
* [PuppetMetadataJsonLint](lib/overcommit/hook/pre_commit/puppet_metadata_json_lint.rb)

config/default.yml

+8
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,14 @@ PreCommit:
498498
flags: ['--standard=PSR2', '--report=csv']
499499
include: '**/*.php'
500500

501+
PhpStan:
502+
description: 'Analyze with phpstan'
503+
enabled: false
504+
command: 'phpstan'
505+
flags: ['analyze', '--errorFormat=raw']
506+
include:
507+
- '**/*.php'
508+
501509
Pronto:
502510
enabled: false
503511
description: 'Analyzing with pronto'
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module Overcommit::Hook::PreCommit
2+
# Runs `phpstan` against any modified PHP files.
3+
# For running `phpstan` with Laravel, it requires setup with `ide_helper`.
4+
#
5+
# References:
6+
# https://github.com/phpstan/phpstan/issues/239
7+
# https://gist.github.com/edmondscommerce/89695c9cd2584fefdf540fb1c528d2c2
8+
class PhpStan < Base
9+
MESSAGE_REGEX = /^(?<file>.+)\:(?<line>\d+)\:(?<message>.+)/
10+
11+
def run
12+
messages = []
13+
14+
result = execute(command, args: applicable_files)
15+
16+
unless result.success?
17+
messages += result.stdout.lstrip.split("\n")
18+
end
19+
20+
return :pass if messages.empty?
21+
22+
extract_messages(
23+
messages,
24+
MESSAGE_REGEX
25+
)
26+
end
27+
end
28+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
require 'spec_helper'
2+
3+
describe Overcommit::Hook::PreCommit::PhpStan do
4+
let(:config) { Overcommit::ConfigurationLoader.default_configuration }
5+
let(:context) { double('context') }
6+
subject { described_class.new(config, context) }
7+
8+
before do
9+
subject.stub(:applicable_files).and_return(%w[sample.php])
10+
end
11+
12+
context 'when phpstan exits successfully' do
13+
before do
14+
sample_output = ''
15+
16+
result = double('result')
17+
result.stub(:success?).and_return(true)
18+
result.stub(:stdout).and_return(sample_output)
19+
result.stub(:status).and_return(0)
20+
subject.stub(:execute).and_return(result)
21+
end
22+
23+
it { should pass }
24+
end
25+
26+
context 'when phpstan exits unsuccessfully' do
27+
let(:result) { double('result') }
28+
29+
before do
30+
result.stub(:success?).and_return(false)
31+
result.stub(:status).and_return(2)
32+
subject.stub(:execute).and_return(result)
33+
end
34+
35+
context 'and it reports a warning' do
36+
before do
37+
sample_output = [
38+
'/sample1.php:14:Call to an undefined static method Sample1::where()',
39+
'/sample2.php:17:Anonymous function has an unused use $myVariable.'
40+
].join("\n")
41+
result.stub(:stdout).and_return(sample_output)
42+
end
43+
44+
it { should fail_hook }
45+
end
46+
end
47+
end

0 commit comments

Comments
 (0)