From a03b79b1ee4b1415b7485f0867bbb9c266158c37 Mon Sep 17 00:00:00 2001 From: Lukas Hettwer Date: Thu, 25 Feb 2021 15:05:16 +0100 Subject: [PATCH] Extend by the Code Climate output format The Code Climate format is used in the GitLab CI/CD to show errors in the merge request page. The simple JSON format is not sufficient for this. --- README.md | 1 + src/Application.php | 1 + src/Manager.php | 2 + src/Output.php | 75 +++++++++++++++++++++++ src/Settings.php | 5 ++ tests/Output.phpt | 95 ++++++++++++++++++++++++++++++ tests/Settings.parseArguments.phpt | 8 +++ 7 files changed, 187 insertions(+) create mode 100644 tests/Output.phpt diff --git a/README.md b/README.md index e5c762f..eb546e9 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ It is strongly recommended for existing users of the (unmaintained) - `--no-progress` Disable progress in console output. - `--checkstyle` Output results as Checkstyle XML. - `--json` Output results as JSON string (requires PHP 5.4). +- `--gitlab` Output results for the GitLab Code Quality widget (requires PHP 5.4), see more in [Code Quality](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html) documentation. - `--blame` Try to show git blame for row with error. - `--git ` Path to Git executable to show blame message (default: 'git'). - `--stdin` Load files and folder to test from standard input. diff --git a/src/Application.php b/src/Application.php index f4002e0..27a7f9d 100644 --- a/src/Application.php +++ b/src/Application.php @@ -87,6 +87,7 @@ private function showOptions() --no-colors Disable colors in console output. --no-progress Disable progress in console output. --json Output results as JSON string. + --gitlab Output results for the GitLab Code Quality Widget. --checkstyle Output results as Checkstyle XML. --blame Try to show git blame for row with error. --git Path to Git executable to show blame message (default: 'git'). diff --git a/src/Manager.php b/src/Manager.php index 63091b1..96553d0 100644 --- a/src/Manager.php +++ b/src/Manager.php @@ -82,6 +82,8 @@ protected function getDefaultOutput(Settings $settings) switch ($settings->format) { case Settings::FORMAT_JSON: return new JsonOutput($writer); + case Settings::FORMAT_GITLAB: + return new GitLabOutput($writer); case Settings::FORMAT_CHECKSTYLE: return new CheckstyleOutput($writer); } diff --git a/src/Output.php b/src/Output.php index c51d11b..974dde8 100644 --- a/src/Output.php +++ b/src/Output.php @@ -85,6 +85,81 @@ public function writeResult(Result $result, ErrorFormatter $errorFormatter, $ign } } +class GitLabOutput implements Output +{ + /** @var IWriter */ + protected $writer; + + /** + * @param IWriter $writer + */ + public function __construct(IWriter $writer) + { + $this->writer = $writer; + } + + public function ok() + { + + } + + public function skip() + { + + } + + public function error() + { + + } + + public function fail() + { + + } + + public function setTotalFileCount($count) + { + + } + + public function writeHeader($phpVersion, $parallelJobs, $hhvmVersion = null) + { + + } + + public function writeResult(Result $result, ErrorFormatter $errorFormatter, $ignoreFails) + { + $errors = array(); + foreach ($result->getErrors() as $error) { + $message = $error->getMessage(); + $line = 1; + if ($error instanceof SyntaxError) { + $line = $error->getLine(); + } + $filePath = $error->getFilePath(); + $result = array( + 'type' => 'issue', + 'check_name' => 'Parse error', + 'description' => $message, + 'categories' => 'Style', + 'fingerprint' => md5($filePath . $message . $line), + 'severity' => 'minor', + 'location' => array( + 'path' => $filePath, + 'lines' => array( + 'begin' => $line, + ), + ), + ); + array_push($errors, $result); + } + + $string = json_encode($errors) . PHP_EOL; + $this->writer->write($string); + } +} + class TextOutput implements Output { const TYPE_DEFAULT = 'default', diff --git a/src/Settings.php b/src/Settings.php index 3e03a71..40cb8b1 100644 --- a/src/Settings.php +++ b/src/Settings.php @@ -13,6 +13,7 @@ class Settings const FORMAT_TEXT = 'text'; const FORMAT_JSON = 'json'; + const FORMAT_GITLAB = 'gitlab'; const FORMAT_CHECKSTYLE = 'checkstyle'; /** @@ -179,6 +180,10 @@ public static function parseArguments(array $arguments) $settings->format = self::FORMAT_JSON; break; + case '--gitlab': + $settings->format = self::FORMAT_GITLAB; + break; + case '--checkstyle': $settings->format = self::FORMAT_CHECKSTYLE; break; diff --git a/tests/Output.phpt b/tests/Output.phpt new file mode 100644 index 0000000..95814a5 --- /dev/null +++ b/tests/Output.phpt @@ -0,0 +1,95 @@ +writeResult($result, new ErrorFormatter(), true); + + $result = (array) json_decode($writer->getLogs()); + + for ($i = 0; $i < count($result) && $i < count($errors); $i++) { + $message = $errors[$i]->getMessage(); + $filePath = $errors[$i]->getFilePath(); + $line = 1; + if ($errors[$i] instanceof SyntaxError) { + $line = $errors[$i]->getLine(); + } + Assert::equal($result[$i]->type, 'issue'); + Assert::equal($result[$i]->check_name, 'Parse error'); + Assert::equal($result[$i]->categories, 'Style'); + Assert::equal($result[$i]->severity, 'minor'); + Assert::equal($result[$i]->description, $message); + Assert::equal($result[$i]->fingerprint, md5($filePath . $message . $line)); + Assert::equal($result[$i]->location->path, $filePath); + Assert::equal($result[$i]->location->lines->begin, $line); + } + } + + public function getGitLabOutputData() + { + return array( + array( + 'errors' => array() + ), + array( + 'errors' => array( + new SyntaxError('foo/bar.php', "Parse error: syntax error, unexpected in foo/bar.php on line 52") + ) + ), + array( + 'errors' => array( + new JakubOnderka\PhpParallelLint\Error('foo/bar.php', "PHP Parse error: syntax error, unexpected ';'") + ) + ), + array( + 'errors' => array( + new SyntaxError('foo/bar.php', "Parse error: syntax error, unexpected in foo/bar.php on line 52"), + new JakubOnderka\PhpParallelLint\Error('foo/bar.php', "PHP Parse error: syntax error, unexpected ';'") + ) + ), + ); + } +} + +class TestWriter implements IWriter +{ + /** @var string */ + protected $logs = ""; + + /** + * @param string $string + */ + public function write($string) + { + $this->logs .= $string; + } + + public function getLogs() + { + return $this->logs; + } +} + +$testCase = new OutputTest; +$testCase->run(); diff --git a/tests/Settings.parseArguments.phpt b/tests/Settings.parseArguments.phpt index 0a83673..a669195 100644 --- a/tests/Settings.parseArguments.phpt +++ b/tests/Settings.parseArguments.phpt @@ -103,6 +103,14 @@ class SettingsParseArgumentsTest extends Tester\TestCase Assert::equal(Settings::FORMAT_JSON, $settings->format); } + public function testGitLabOutput() + { + $commandLine = './parallel-lint --gitlab .'; + $argv = explode(" ", $commandLine); + $settings = Settings::parseArguments($argv); + Assert::equal(Settings::FORMAT_GITLAB, $settings->format); + } + public function testCheckstyleOutput() { $commandLine = './parallel-lint --checkstyle .';