From 0923f86a09e6fdc9e48a7ec4ce3433ff793c572b Mon Sep 17 00:00:00 2001 From: caouecs Date: Tue, 24 Apr 2018 23:05:15 +0200 Subject: [PATCH] feature: Phan Plugin --- src/Languages/lang.en.php | 1 + src/Languages/lang.fr.php | 1 + src/Languages/lang.ru.php | 1 + src/Plugin/Phan.php | 167 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 src/Plugin/Phan.php diff --git a/src/Languages/lang.en.php b/src/Languages/lang.en.php index dcba6b42..4a948e15 100644 --- a/src/Languages/lang.en.php +++ b/src/Languages/lang.en.php @@ -413,6 +413,7 @@ PHP Censor', 'package_build' => 'Package Build', 'pdepend' => 'PDepend', 'pgsql' => 'PostgreSQL', + 'phan' => 'Phan', 'phar' => 'Phar', 'phing' => 'Phing', 'php_cs_fixer' => 'PHP Coding Standards Fixer', diff --git a/src/Languages/lang.fr.php b/src/Languages/lang.fr.php index f5c0a603..acfe6d11 100644 --- a/src/Languages/lang.fr.php +++ b/src/Languages/lang.fr.php @@ -414,6 +414,7 @@ PHP Censor', 'package_build' => 'Package Build', 'pdepend' => 'PDepend', 'pgsql' => 'PostgreSQL', + 'phan' => 'Phan', 'phar' => 'Phar', 'phing' => 'Phing', 'php_cs_fixer' => 'PHP Coding Standards Fixer', diff --git a/src/Languages/lang.ru.php b/src/Languages/lang.ru.php index 2c1af274..f4b07bd3 100644 --- a/src/Languages/lang.ru.php +++ b/src/Languages/lang.ru.php @@ -397,6 +397,7 @@ PHP Censor', 'package_build' => 'Package Build', 'pdepend' => 'PDepend', 'pgsql' => 'PostgreSQL', + 'phan' => 'Phan', 'phar' => 'Phar', 'phing' => 'Phing', 'php_cs_fixer' => 'PHP Coding Standards Fixer', diff --git a/src/Plugin/Phan.php b/src/Plugin/Phan.php new file mode 100644 index 00000000..c59e1ca0 --- /dev/null +++ b/src/Plugin/Phan.php @@ -0,0 +1,167 @@ +directory = isset($options['directory']) + ? $options['directory'] + : $this->builder->buildPath; + + $this->location = $this->builder->buildPath.'phan_tmp'; + $this->ignore = isset($options['ignore']) && is_array($options['ignore']) ? $options['ignore'] : []; + + if (empty($this->ignore) && is_array($this->builder->ignore)) { + $this->ignore = $this->builder->ignore; + } + + $this->allowedWarnings = isset($options['allowed_warnings']) ? $options['allowed_warnings'] : 0; + } + + /** + * Executes Phan. + */ + public function execute() + { + if (!file_exists($this->location)) { + mkdir($this->location, (0777 & ~umask()), true); + } + + if (!is_writable($this->location)) { + throw new \Exception(sprintf('The location %s is not writable or does not exist.', $this->location)); + } + + // Find PHP files in a file + $cmd = 'find -L %s -type f -name "**.php"'; + + foreach ($this->ignore as $ignore) { + $cmd .= ' | grep -v '.$ignore; + } + + $cmd .= ' > %s'; + + $this->builder->executeCommand($cmd, $this->directory, $this->location.'/phan.in'); + + $phan = $this->findBinary('phan'); + + // Launch Phan on PHP files with json output + $cmd = $phan.' -f %s -i -m json -o %s'; + + $this->builder->executeCommand($cmd, $this->location.'/phan.in', $this->location.'/phan.out'); + + $warningCount = $this->processReport(file_get_contents($this->location.'/phan.out')); + + $this->build->storeMeta('phan-warnings', $warningCount); + + $success = true; + + if ($this->allowedWarnings != -1 && $warningCount > $this->allowedWarnings) { + $success = false; + } + + return $success; + } + + /** + * Process the Phan Json report. + * + * @param $jsonString + * + * @return int + * + * @throws \Exception + */ + protected function processReport($jsonString) + { + $json = json_decode($jsonString, true); + + if ($json === false || !is_array($json)) { + $this->builder->log($jsonString); + throw new \Exception('Could not process the report generated by Phan.'); + } + + $warnings = 0; + + foreach ($json as $data) { + $this->build->reportError( + $this->builder, + 'phan', + $data['check_name']."\n\n".$data['description'], + $this->severity($data['severity']), + $data['location']['path'] ?? '??', + $data['location']['lines']['begin'] ?? 0, + $data['location']['lines']['end'] ?? 0 + ); + + $warnings++; + } + + return $warnings; + } + + /** + * Transform severity from Phan to PHP-Censor. + * + * @param int $severity + * + * @return int + */ + protected function severity($severity) + { + if ($severity == 10) { + return BuildError::SEVERITY_CRITICAL; + } + + if ($severity == 5) { + return BuildError::SEVERITY_NORMAL; + } + + return BuildError::SEVERITY_LOW; + } +}