issues_data as $error) { $is_error = $error->severity === Config::REPORT_ERROR; $is_warning = $error->severity === Config::REPORT_INFO; if ($is_error) { $errors++; } elseif ($is_warning) { $warnings++; } else { // currently this never happens continue; } $tests++; $fname = $error->file_name; if (!isset($ndata[$fname])) { $ndata[$fname] = [ 'errors' => $is_error ? 1 : 0, 'warnings' => $is_warning ? 1 : 0, 'failures' => [], ]; } else { if ($is_error) { $ndata[$fname]['errors']++; } else { $ndata[$fname]['warnings']++; } } if ($is_error || ($this->show_info && $is_warning)) { $ndata[$fname]['failures'][] = $error; } } $dom = new DOMDocument('1.0', 'UTF-8'); $dom->formatOutput = true; $schema = 'https://raw.githubusercontent.com/junit-team/'. 'junit5/r5.5.1/platform-tests/src/test/resources/jenkins-junit.xsd'; $suites = $dom->createElement('testsuites'); $suites->setAttribute('failures', (string) $errors); $suites->setAttribute('errors', '0'); $suites->setAttribute('name', 'psalm'); $suites->setAttribute('tests', (string) $tests); $suites->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); $suites->setAttribute('xsi:noNamespaceSchemaLocation', $schema); $dom->appendChild($suites); if (!count($ndata)) { $testcase = $dom->createElement('testcase'); $testcase->setAttribute('name', 'psalm'); $suites->appendChild($testcase); } else { foreach ($ndata as $file => $report) { $this->createTestSuite($dom, $suites, $file, $report); } } return $dom->saveXML(); } /** * @param array{ * errors: int, * warnings: int, * failures: list * } $report */ private function createTestSuite(DOMDocument $dom, DOMElement $parent, string $file, array $report): void { $totalTests = $report['errors'] + $report['warnings']; if ($totalTests < 1) { $totalTests = 1; } $testsuite = $dom->createElement('testsuite'); $testsuite->setAttribute('name', $file); $testsuite->setAttribute('tests', (string) $totalTests); $testsuite->setAttribute('failures', (string) $report['errors']); $testsuite->setAttribute('errors', '0'); $failuresByType = $this->groupByType($report['failures']); foreach ($failuresByType as $type => $data) { foreach ($data as $d) { $testcase = $dom->createElement('testcase'); $testcase->setAttribute('name', "{$file}:{$d->line_from}"); $testcase->setAttribute('classname', $type); $testcase->setAttribute('assertions', (string) count($data)); $failure = $dom->createElement('failure'); $failure->setAttribute('type', $type); $failure->nodeValue = $this->dataToOutput($d); $testcase->appendChild($failure); $testsuite->appendChild($testcase); } } $parent->appendChild($testsuite); } /** * @param list $failures * * @return array> */ private function groupByType(array $failures) { $nfailures = []; foreach ($failures as $failure) { $nfailures[$failure->type][] = $failure; } return $nfailures; } /** * @param IssueData $data */ private function dataToOutput(IssueData $data): string { $ret = ''; if ($this->show_snippet) { $ret = "snippet: {$data->snippet}\n"; } $ret .= <<message} type : {$data->type} selected_text : {$data->selected_text} line : {$data->line_from} column_from : {$data->column_from} column_to : {$data->column_to} SNIPPET; return $ret; } }