From 8870baedd173e893953e6a5c0d05a3507a461b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 16:40:21 +0100 Subject: [PATCH 01/17] phpstan - add suggested tool --- bin/ci.sh | 2 +- bin/suggested-tools.sh | 4 ++-- composer.json | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/ci.sh b/bin/ci.sh index fc9ca746..17b788e1 100755 --- a/bin/ci.sh +++ b/bin/ci.sh @@ -1,3 +1,3 @@ #!/bin/sh -./phpqa --verbose --report --tools phpcs:0,phpmd:0,phpcpd:0,parallel-lint:0,phpmetrics,phploc,pdepend \ No newline at end of file +./phpqa --verbose --report --tools phpcs:0,phpmd:0,phpcpd:0,parallel-lint:0,phpstan:0,phpmetrics,phploc,pdepend \ No newline at end of file diff --git a/bin/suggested-tools.sh b/bin/suggested-tools.sh index ebe40766..4f35585e 100755 --- a/bin/suggested-tools.sh +++ b/bin/suggested-tools.sh @@ -9,8 +9,8 @@ mode="$1" if [ $mode = "install" ] then echo "Installing suggested tools" - composer require jakub-onderka/php-parallel-lint jakub-onderka/php-console-highlighter + composer require jakub-onderka/php-parallel-lint jakub-onderka/php-console-highlighter phpstan/phpstan else echo "Removing suggested tools" - composer remove jakub-onderka/php-parallel-lint jakub-onderka/php-console-highlighter + composer remove jakub-onderka/php-parallel-lint jakub-onderka/php-console-highlighter phpstan/phpstan fi diff --git a/composer.json b/composer.json index a2626f9b..5897a235 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ }, "suggest": { "jakub-onderka/php-parallel-lint": "Check PHP syntax", - "jakub-onderka/php-console-highlighter": "Colored output in parallel-lint" + "jakub-onderka/php-console-highlighter": "Colored output in parallel-lint", + "phpstan/phpstan": "PHP Static Analysis Tool - discover bugs in your code without running it!" }, "require-dev": { "phpunit/phpunit": "~4.8", From b224e04d0aecfdd16bcdf27c8884413788f1bce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 16:45:40 +0100 Subject: [PATCH 02/17] phpstan - show version in phpqa tools Unofrtunately there is no version :( PHPStan - PHP Static Analysis Tool --- src/CodeAnalysisTasks.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CodeAnalysisTasks.php b/src/CodeAnalysisTasks.php index 01666d82..f23e78b7 100644 --- a/src/CodeAnalysisTasks.php +++ b/src/CodeAnalysisTasks.php @@ -44,6 +44,8 @@ trait CodeAnalysisTasks 'hasOnlyConsoleOutput' => true, 'composer' => 'jakub-onderka/php-parallel-lint', ), + 'phpstan' => array( + ), ); /** @var Options */ private $options; From 73da4529b6073974c897236dd61139893d9b7710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 16:58:06 +0100 Subject: [PATCH 03/17] phpstan - analyze directories, load level from .phpqa.yml --- .phpqa.yml | 3 +++ src/CodeAnalysisTasks.php | 15 ++++++++++++++- src/Config.php | 2 +- src/RunningTool.php | 2 +- tests/Config/ConfigTest.php | 1 + tests/RunningToolTest.php | 1 + 6 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.phpqa.yml b/.phpqa.yml index 0f966aa5..4e2be05d 100644 --- a/.phpqa.yml +++ b/.phpqa.yml @@ -8,6 +8,9 @@ phpcpd: minLines: 5 minTokens: 70 +phpstan: + level: 0 + # paths are relative to .phpqa.yml, so don't copy-paste this section if you don't have custom templates report: phploc: app/report/phploc.xsl diff --git a/src/CodeAnalysisTasks.php b/src/CodeAnalysisTasks.php index f23e78b7..e11371c8 100644 --- a/src/CodeAnalysisTasks.php +++ b/src/CodeAnalysisTasks.php @@ -45,6 +45,9 @@ trait CodeAnalysisTasks 'composer' => 'jakub-onderka/php-parallel-lint', ), 'phpstan' => array( + 'optionSeparator' => ' ', + 'internalClass' => 'PHPStan\Analyser\Analyser', + 'hasOnlyConsoleOutput' => true, ), ); /** @var Options */ @@ -82,7 +85,7 @@ public function ci( 'buildDir' => 'build/', 'ignoredDirs' => 'vendor', 'ignoredFiles' => '', - 'tools' => 'phploc,phpcpd,phpcs,pdepend,phpmd,phpmetrics,parallel-lint', + 'tools' => 'phploc,phpcpd,phpcs,pdepend,phpmd,phpmetrics,parallel-lint,phpstan', 'output' => 'file', 'config' => '', 'report' => false, @@ -258,6 +261,16 @@ private function parallellint() ); } + private function phpstan() + { + return array( + 'analyze', + 'ansi' => '', + 'level' => $this->config->value('phpstan.level'), + $this->options->getAnalyzedDirs(' '), + ); + } + private function buildHtmlReport() { foreach ($this->usedTools as $tool) { diff --git a/src/Config.php b/src/Config.php index 4918fc5e..07637577 100644 --- a/src/Config.php +++ b/src/Config.php @@ -56,7 +56,7 @@ private function get($path, $extractor) { foreach ($this->configs as $dir => $config) { $value = $this->findInConfig($config, $path); - if ($value) { + if ($value !== null) { return $extractor($value, $dir); } } diff --git a/src/RunningTool.php b/src/RunningTool.php index db8fe61e..46aa02d0 100644 --- a/src/RunningTool.php +++ b/src/RunningTool.php @@ -43,7 +43,7 @@ public function isInstalled() public function buildOption($arg, $value) { - if ($value) { + if ($value || $value === 0) { return "--{$arg}{$this->optionSeparator}{$value}"; } else { return "--{$arg}"; diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 7a7636ad..54984e1c 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -11,6 +11,7 @@ public function testLoadDefaultConfig() assertThat($config->value('phpcpd.minTokens'), is(greaterThan(0))); assertThat($config->value('phpcs.standard'), is(nonEmptyString())); assertThat($config->path('phpmd.standard'), is(nonEmptyString())); + assertThat($config->value('phpstan.level'), identicalTo(0)); } public function testBuildAbsolutePath() diff --git a/tests/RunningToolTest.php b/tests/RunningToolTest.php index 40dc7dea..4735cdae 100644 --- a/tests/RunningToolTest.php +++ b/tests/RunningToolTest.php @@ -11,6 +11,7 @@ public function testBuildOptionWithDefinedSeparator() $tool = new RunningTool('tool', ['optionSeparator' => ' ']); assertThat($tool->buildOption('option', ''), is('--option')); assertThat($tool->buildOption('option', 'value'), is('--option value')); + assertThat($tool->buildOption('option', 0), is('--option 0')); } public function testMarkSuccessWhenXPathIsNotDefined() From 7a7efc610cfb70047c91d1cd7384f9456f50fd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 17:46:02 +0100 Subject: [PATCH 04/17] phpstan - exclude directories, load bootstrap Works without extra config phpqa --report --output cli --tools phpstan --analyzedDirs src,tests --ignoredDirs=vendor Needs bootstrap phpqa --report --output cli --tools phpstan --analyzedDirs ./ --ignoredDirs=vendor --- .phpqa.yml | 4 ++++ src/CodeAnalysisTasks.php | 22 ++++++++++++++++++++++ src/IgnoredPaths.php | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/.phpqa.yml b/.phpqa.yml index 4e2be05d..b6a025fb 100644 --- a/.phpqa.yml +++ b/.phpqa.yml @@ -10,6 +10,10 @@ phpcpd: phpstan: level: 0 + # paths are relative to CWD (current working directory) !!! +# bootstrap: vendor/autoload.php +# autoload: +# - tests # paths are relative to .phpqa.yml, so don't copy-paste this section if you don't have custom templates report: diff --git a/src/CodeAnalysisTasks.php b/src/CodeAnalysisTasks.php index e11371c8..e08058d1 100644 --- a/src/CodeAnalysisTasks.php +++ b/src/CodeAnalysisTasks.php @@ -263,10 +263,32 @@ private function parallellint() private function phpstan() { + $neonFile = $this->options->isSavedToFiles ? $this->options->rawFile('phpstan.neon') : (getcwd() . '/phpstan.neon'); + $createAbsolutePaths = function (array $relativeDirs) { + return array_values(array_filter(array_map( + function ($relativeDir) { + return realpath(getcwd() . '/' . trim($relativeDir, '"')); + }, + $relativeDirs + ))); + }; + + file_put_contents( + $neonFile, + \Nette\Neon\Neon::encode([ + 'parameters' => [ + 'bootstrap' => $this->config->value('phpstan.bootstrap'), + 'autoload_directories' => $createAbsolutePaths($this->config->value('phpstan.autoload') ?: $this->options->getAnalyzedDirs()), + 'excludes_analyse' => $createAbsolutePaths($this->options->ignore->phpstan()), + ] + ]) + ); + return array( 'analyze', 'ansi' => '', 'level' => $this->config->value('phpstan.level'), + 'configuration' => $neonFile, $this->options->getAnalyzedDirs(' '), ); } diff --git a/src/IgnoredPaths.php b/src/IgnoredPaths.php index 6a5fd196..be4d2be4 100644 --- a/src/IgnoredPaths.php +++ b/src/IgnoredPaths.php @@ -50,6 +50,11 @@ public function parallelLint() return $this->ignore(' --exclude ', ' --exclude ', ''); } + public function phpstan() + { + return $this->ignoreBoth; + } + private function ignore($before, $dirSeparator, $after, $fileSeparator = null) { if ($fileSeparator) { From fb7b94d855351d6355997ee73b1bdea1e7f2a25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 18:00:36 +0100 Subject: [PATCH 05/17] phpstan - use dummy or used-defined config + append excluded files --- .gitignore | 3 ++- .phpqa.yml | 6 ++---- app/phpstan.neon | 13 +++++++++++++ src/CodeAnalysisTasks.php | 23 ++++++++++++++++------- 4 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 app/phpstan.neon diff --git a/.gitignore b/.gitignore index 753c56e6..dd4791cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /nbproject/ /vendor/ -/build/ \ No newline at end of file +/build/ +phpstan.neon diff --git a/.phpqa.yml b/.phpqa.yml index b6a025fb..b60544da 100644 --- a/.phpqa.yml +++ b/.phpqa.yml @@ -10,10 +10,8 @@ phpcpd: phpstan: level: 0 - # paths are relative to CWD (current working directory) !!! -# bootstrap: vendor/autoload.php -# autoload: -# - tests + # https://github.com/phpstan/phpstan#configuration + # standard: app/phpstan.neon # paths are relative to .phpqa.yml, so don't copy-paste this section if you don't have custom templates report: diff --git a/app/phpstan.neon b/app/phpstan.neon new file mode 100644 index 00000000..e32948b1 --- /dev/null +++ b/app/phpstan.neon @@ -0,0 +1,13 @@ +# Required config for analyzing root directory (RobotLoader. throws Nette\InvalidStateException: Ambiguous class) +# phpqa --report --output cli --tools phpstan --analyzedDirs ./ --ignoredDirs=vendor +# +# .phpqa.yml +# phpstan.standard: +# standard: app/phpstan.neon +# +# %rootDir% == vendor/phpstan/phpstan/ + +parameters: + bootstrap: %rootDir%/../../../vendor/autoload.php + autoload_directories: + - %rootDir%/../../../tests diff --git a/src/CodeAnalysisTasks.php b/src/CodeAnalysisTasks.php index e08058d1..baf29b0e 100644 --- a/src/CodeAnalysisTasks.php +++ b/src/CodeAnalysisTasks.php @@ -273,15 +273,24 @@ function ($relativeDir) { ))); }; + $defaultConfig = $this->config->path('phpstan.standard'); + if (file_exists($defaultConfig)) { + $params = \Nette\Neon\Neon::decode(file_get_contents($defaultConfig))['parameters'] + ['excludes_analyse' => []]; + } else { + $params = [ + 'autoload_directories' => $createAbsolutePaths($this->options->getAnalyzedDirs()), + 'excludes_analyse' => [], + ]; + } + + $params['excludes_analyse'] = array_merge( + $params['excludes_analyse'], + $createAbsolutePaths($this->options->ignore->phpstan()) + ); + file_put_contents( $neonFile, - \Nette\Neon\Neon::encode([ - 'parameters' => [ - 'bootstrap' => $this->config->value('phpstan.bootstrap'), - 'autoload_directories' => $createAbsolutePaths($this->config->value('phpstan.autoload') ?: $this->options->getAnalyzedDirs()), - 'excludes_analyse' => $createAbsolutePaths($this->options->ignore->phpstan()), - ] - ]) + \Nette\Neon\Neon::encode(['parameters' => $params]) ); return array( From b82577a41a4dfe523b5278ed142cce23c3354306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 18:23:26 +0100 Subject: [PATCH 06/17] phpstan - add custom config for .travis (bin/ci.sh) --- .phpqa.yml | 2 +- bin/ci.sh | 2 +- tests/.travis/.phpqa.yml | 4 ++++ {app => tests/.travis}/phpstan.neon | 8 ++++---- 4 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 tests/.travis/.phpqa.yml rename {app => tests/.travis}/phpstan.neon (57%) diff --git a/.phpqa.yml b/.phpqa.yml index b60544da..b267ee53 100644 --- a/.phpqa.yml +++ b/.phpqa.yml @@ -11,7 +11,7 @@ phpcpd: phpstan: level: 0 # https://github.com/phpstan/phpstan#configuration - # standard: app/phpstan.neon + # standard: tests/.travis/phpstan.neon # paths are relative to .phpqa.yml, so don't copy-paste this section if you don't have custom templates report: diff --git a/bin/ci.sh b/bin/ci.sh index 17b788e1..45c6fce2 100755 --- a/bin/ci.sh +++ b/bin/ci.sh @@ -1,3 +1,3 @@ #!/bin/sh -./phpqa --verbose --report --tools phpcs:0,phpmd:0,phpcpd:0,parallel-lint:0,phpstan:0,phpmetrics,phploc,pdepend \ No newline at end of file +./phpqa --verbose --report --config tests/.travis --tools phpcs:0,phpmd:0,phpcpd:0,parallel-lint:0,phpstan:0,phpmetrics,phploc,pdepend diff --git a/tests/.travis/.phpqa.yml b/tests/.travis/.phpqa.yml new file mode 100644 index 00000000..72d0ab24 --- /dev/null +++ b/tests/.travis/.phpqa.yml @@ -0,0 +1,4 @@ +phpstan: + level: 4 + # https://github.com/phpstan/phpstan#configuration + standard: phpstan.neon diff --git a/app/phpstan.neon b/tests/.travis/phpstan.neon similarity index 57% rename from app/phpstan.neon rename to tests/.travis/phpstan.neon index e32948b1..52d92389 100644 --- a/app/phpstan.neon +++ b/tests/.travis/phpstan.neon @@ -1,9 +1,5 @@ # Required config for analyzing root directory (RobotLoader. throws Nette\InvalidStateException: Ambiguous class) # phpqa --report --output cli --tools phpstan --analyzedDirs ./ --ignoredDirs=vendor -# -# .phpqa.yml -# phpstan.standard: -# standard: app/phpstan.neon # # %rootDir% == vendor/phpstan/phpstan/ @@ -11,3 +7,7 @@ parameters: bootstrap: %rootDir%/../../../vendor/autoload.php autoload_directories: - %rootDir%/../../../tests + ignoreErrors: + - '#Call to an undefined method Edge\\QA\\CodeAnalysisTasks::[a-zA-Z0-9_]+\(\)#' + - '#Call to an undefined method Prophecy\\Prophecy\\ObjectProphecy::[a-zA-Z0-9_]+\(\)#' + - '#Access to an undefined property DOMDocument::\$documentElement.#' From 2b12e966bb81dce0dd434f1dce6258fad9b004f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 18:23:48 +0100 Subject: [PATCH 07/17] phpstan - fix coding standard --- src/CodeAnalysisTasks.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CodeAnalysisTasks.php b/src/CodeAnalysisTasks.php index baf29b0e..120bda84 100644 --- a/src/CodeAnalysisTasks.php +++ b/src/CodeAnalysisTasks.php @@ -263,7 +263,6 @@ private function parallellint() private function phpstan() { - $neonFile = $this->options->isSavedToFiles ? $this->options->rawFile('phpstan.neon') : (getcwd() . '/phpstan.neon'); $createAbsolutePaths = function (array $relativeDirs) { return array_values(array_filter(array_map( function ($relativeDir) { @@ -275,7 +274,9 @@ function ($relativeDir) { $defaultConfig = $this->config->path('phpstan.standard'); if (file_exists($defaultConfig)) { - $params = \Nette\Neon\Neon::decode(file_get_contents($defaultConfig))['parameters'] + ['excludes_analyse' => []]; + $params = \Nette\Neon\Neon::decode(file_get_contents($defaultConfig))['parameters'] + [ + 'excludes_analyse' => [] + ]; } else { $params = [ 'autoload_directories' => $createAbsolutePaths($this->options->getAnalyzedDirs()), @@ -288,6 +289,8 @@ function ($relativeDir) { $createAbsolutePaths($this->options->ignore->phpstan()) ); + $neonFile = $this->options->isSavedToFiles ? + $this->options->rawFile('phpstan.neon') : (getcwd() . '/phpstan.neon'); file_put_contents( $neonFile, \Nette\Neon\Neon::encode(['parameters' => $params]) From 139efdf5b50c3d134bee4c59aa2090a1d7511c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Draho=C5=A1?= Date: Wed, 21 Dec 2016 18:31:53 +0100 Subject: [PATCH 08/17] phpstan - fix h1, don't show progressbar in report --- app/report/cli.html.twig | 4 ++-- src/CodeAnalysisTasks.php | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/report/cli.html.twig b/app/report/cli.html.twig index fdb77726..6c68bd40 100644 --- a/app/report/cli.html.twig +++ b/app/report/cli.html.twig @@ -1,5 +1,5 @@ -

Parallel Lint

-
{{ process.getOutput() }}{{ process.getErrorOutput() }}
+

{{ tool }}

+
{{ process.getOutput() }}