Skip to content
Permalink
Browse files

Add a 'sonarqube' report type (#1808)

This JSON report is suitable for import into either SonarCloud or
SonarQube as Generic Issue Data (also known as an External Issue
Report).

https://docs.sonarqube.org/latest/analysis/generic-issue/
  • Loading branch information...
lewinski authored and muglug committed Jun 18, 2019
1 parent d573a3e commit ac0a9d1514f7c3ad46dac831ec6ac144d4511e22
@@ -234,6 +234,7 @@ public static function getFileReportOptions(array $report_file_paths, bool $show
$mapping = [
'checkstyle.xml' => Report::TYPE_CHECKSTYLE,
'sonarqube.json' => Report::TYPE_SONARQUBE,
'summary.json' => Report::TYPE_JSON_SUMMARY,
'.xml' => Report::TYPE_XML,
'.json' => Report::TYPE_JSON,
@@ -11,6 +11,7 @@
use Psalm\Report\JsonReport;
use Psalm\Report\JsonSummaryReport;
use Psalm\Report\PylintReport;
use Psalm\Report\SonarqubeReport;
use Psalm\Report\TextReport;
use Psalm\Report\XmlReport;
@@ -406,6 +407,10 @@ public static function getOutput(
);
break;
case Report::TYPE_SONARQUBE:
$output = new SonarqubeReport(self::$issues_data, $report_options);
break;
case Report::TYPE_PYLINT:
$output = new PylintReport(self::$issues_data, $report_options);
break;
@@ -8,6 +8,7 @@ abstract class Report
const TYPE_PYLINT = 'pylint';
const TYPE_JSON = 'json';
const TYPE_JSON_SUMMARY = 'json-summary';
const TYPE_SONARQUBE = 'sonarqube';
const TYPE_EMACS = 'emacs';
const TYPE_XML = 'xml';
const TYPE_CHECKSTYLE = 'checkstyle';
@@ -19,6 +20,7 @@ abstract class Report
self::TYPE_PYLINT,
self::TYPE_JSON,
self::TYPE_JSON_SUMMARY,
self::TYPE_SONARQUBE,
self::TYPE_EMACS,
self::TYPE_XML,
self::TYPE_CHECKSTYLE,
@@ -0,0 +1,44 @@
<?php
namespace Psalm\Report;
use Psalm\Config;
use Psalm\Report;
/**
* JSON report format suitable for import into SonarQube or SonarCloud as
* generic (external) issue data via `sonar.externalIssuesReportPaths`.
*
* https://docs.sonarqube.org/latest/analysis/generic-issue/
*/
class SonarqubeReport extends Report
{
/**
* {{@inheritdoc}}
*/
public function create(): string
{
$report = ['issues' => []];
foreach ($this->issues_data as $issue_data) {
$report['issues'][] = [
'engineId' => 'Psalm',
'ruleId' => $issue_data['type'],
'primaryLocation' => [
'message' => $issue_data['message'],
'filePath' => $issue_data['file_name'],
'textRange' => [
'startLine' => $issue_data['line_from'],
'endLine' => $issue_data['line_to'],
// Columns in external issue reports are indexed from 0
'startColumn' => max(0, $issue_data['column_from'] - 1),
'endColumn' => max(0, $issue_data['column_to'] - 1),
],
],
'type' => 'CODE_SMELL',
'severity' => $issue_data['severity'] == Config::REPORT_ERROR ? 'CRITICAL' : 'MINOR',
];
}
return json_encode($report) . "\n";
}
}
@@ -198,7 +198,7 @@ function ($arg) use ($valid_long_options, $valid_short_options) {
Only checks methods that have changed (and their dependents)
--output-format=console
Changes the output format. Possible values: compact, console, emacs, json, pylint, xml, checkstyle
Changes the output format. Possible values: compact, console, emacs, json, pylint, xml, checkstyle, sonarqube
--find-dead-code[=auto]
--find-unused-code[=auto]
@@ -176,6 +176,91 @@ public function testJsonReport()
);
}
/**
* @return void
*/
public function testSonarqubeReport()
{
$this->analyzeFileForReport();
$issue_data = [
'issues' => [
[
'engineId' => 'Psalm',
'ruleId' => 'UndefinedVariable',
'primaryLocation' => [
'message' => 'Cannot find referenced variable $as_you',
'filePath' => 'somefile.php',
'textRange' => [
'startLine' => 3,
'endLine' => 3,
'startColumn' => 9,
'endColumn' => 16,
],
],
'type' => 'CODE_SMELL',
'severity' => 'CRITICAL',
],
[
'engineId' => 'Psalm',
'ruleId' => 'MixedInferredReturnType',
'primaryLocation' => [
'message' => 'Could not verify return type \'string|null\' for psalmCanVerify',
'filePath' => 'somefile.php',
'textRange' => [
'startLine' => 2,
'endLine' => 2,
'startColumn' => 41,
'endColumn' => 48,
],
],
'type' => 'CODE_SMELL',
'severity' => 'CRITICAL',
],
[
'engineId' => 'Psalm',
'ruleId' => 'UndefinedConstant',
'primaryLocation' => [
'message' => 'Const CHANGE_ME is not defined',
'filePath' => 'somefile.php',
'textRange' => [
'startLine' => 7,
'endLine' => 7,
'startColumn' => 5,
'endColumn' => 14,
],
],
'type' => 'CODE_SMELL',
'severity' => 'CRITICAL',
],
[
'engineId' => 'Psalm',
'ruleId' => 'PossiblyUndefinedGlobalVariable',
'primaryLocation' => [
'message' => 'Possibly undefined global variable $a, first seen on line 10',
'filePath' => 'somefile.php',
'textRange' => [
'startLine' => 15,
'endLine' => 15,
'startColumn' => 5,
'endColumn' => 7,
],
],
'type' => 'CODE_SMELL',
'severity' => 'MINOR',
],
],
];
$sonarqube_report_options = ProjectAnalyzer::getFileReportOptions([__DIR__ . '/test-sonarqube.json'])[0];
$sonarqube_report_options->format = 'sonarqube';
$this->assertSame(
$issue_data,
json_decode(IssueBuffer::getOutput($sonarqube_report_options), true)
);
}
/**
* @return void
*/

0 comments on commit ac0a9d1

Please sign in to comment.
You can’t perform that action at this time.