Skip to content

Commit

Permalink
Merge 657111a into 395ea6b
Browse files Browse the repository at this point in the history
  • Loading branch information
SmetDenis committed May 5, 2021
2 parents 395ea6b + 657111a commit ff1b57c
Show file tree
Hide file tree
Showing 10 changed files with 625 additions and 96 deletions.
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ At the moment it works with
* `phpmd-json` - [see example](tests/fixtures/origin/phpmd/json.json). The most detailed report of [PHPMD](https://github.com/phpmd/phpmd).
* `phpmnd` - [see example](tests/fixtures/origin/phpmnd/phpmnd.xml). I know only [PHP Magic Numbers Detector](https://github.com/povils/phpmnd).
* `psalm-json` - [see example](tests/fixtures/origin/psalm/json.json). The most detailed report of [Psalm](https://github.com/vimeo/psalm).
* `pmd-cpd` - [see example](tests/fixtures/origin/phpcpd/pmd-cpd.xml). PMD-CPD XML format. An example of tool is [Copy/Paste Detector](https://github.com/sebastianbergmann/phpcpd).
* Output formats:
* `junit` - The most popular sort of reporting.
* `tc-tests` - [Reporting for TeamCity/PhpStorm/JetBrains](https://www.jetbrains.com/help/teamcity/service-messages.html#Reporting+Tests).
Expand Down Expand Up @@ -87,7 +88,7 @@ Usage:
convert [options]
Options:
-S, --input-format=INPUT-FORMAT Source format. Available options: checkstyle, junit, phpmd-json, phpmnd, psalm-json
-S, --input-format=INPUT-FORMAT Source format. Available options: checkstyle, junit, phpmd-json, phpmnd, pmd-cpd, psalm-json
-T, --output-format=OUTPUT-FORMAT Target format. Available options: github-cli, junit, tc-inspections, tc-tests
-N, --suite-name=SUITE-NAME Set name of root suite
-I, --input-file[=INPUT-FILE] Use CLI input (STDIN, pipeline) OR use the option to define filename of source report
Expand All @@ -112,24 +113,24 @@ Options:
### Available Directions

<p align="center"><!-- Auto-created image via JBZoo\PHPUnit\CiReportConverterReadmeTest__testBuildGraphManually -->
<img src="https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggTFI7XG4gICAgY2hlY2tzdHlsZV9zcmMoXCJDaGVja1N0eWxlLnhtbFwiKTtcbiAgICBjaS1yZXBvcnQtY29udmVydGVyKChcIkNJLVJlcG9ydC1Db252ZXJ0ZXJcIikpO1xuICAgIGdpdGh1Yi1jbGlfdGFyZ2V0KFwiR2l0SHViIEFjdGlvbnMgLSBDTElcIik7XG4gICAganVuaXRfc3JjKFwiSlVuaXQueG1sXCIpO1xuICAgIGp1bml0X3RhcmdldChcIkpVbml0LnhtbFwiKTtcbiAgICBwaHBtZC1qc29uX3NyYyhcIlBIUG1kLmpzb25cIik7XG4gICAgcGhwbW5kX3NyYyhcIlBIUG1uZC54bWxcIik7XG4gICAgcHNhbG0tanNvbl9zcmMoXCJQc2FsbS5qc29uXCIpO1xuICAgIHRjLWluc3BlY3Rpb25zX3RhcmdldChcIlRlYW1DaXR5IC0gSW5zcGVjdGlvbnNcIik7XG4gICAgdGMtdGVzdHNfdGFyZ2V0KFwiVGVhbUNpdHkgLSBUZXN0c1wiKTtcblxuICAgIGNoZWNrc3R5bGVfc3JjID09PiBjaS1yZXBvcnQtY29udmVydGVyO1xuICAgIGNpLXJlcG9ydC1jb252ZXJ0ZXIgPT0+IGdpdGh1Yi1jbGlfdGFyZ2V0O1xuICAgIGNpLXJlcG9ydC1jb252ZXJ0ZXIgPT0+IGp1bml0X3RhcmdldDtcbiAgICBjaS1yZXBvcnQtY29udmVydGVyID09PiB0Yy1pbnNwZWN0aW9uc190YXJnZXQ7XG4gICAgY2ktcmVwb3J0LWNvbnZlcnRlciA9PT4gdGMtdGVzdHNfdGFyZ2V0O1xuICAgIGp1bml0X3NyYyA9PT4gY2ktcmVwb3J0LWNvbnZlcnRlcjtcbiAgICBwaHBtZC1qc29uX3NyYyA9PT4gY2ktcmVwb3J0LWNvbnZlcnRlcjtcbiAgICBwaHBtbmRfc3JjID09PiBjaS1yZXBvcnQtY29udmVydGVyO1xuICAgIHBzYWxtLWpzb25fc3JjID09PiBjaS1yZXBvcnQtY29udmVydGVyO1xuXG5saW5rU3R5bGUgZGVmYXVsdCBpbnRlcnBvbGF0ZSBiYXNpczsiLCJtZXJtYWlkIjp7InRoZW1lIjoiZm9yZXN0In19">
<img src="https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggTFI7XG4gICAgY2hlY2tzdHlsZV9zcmMoXCJDaGVja1N0eWxlLnhtbFwiKTtcbiAgICBjaS1yZXBvcnQtY29udmVydGVyKChcIkNJLVJlcG9ydC1Db252ZXJ0ZXJcIikpO1xuICAgIGdpdGh1Yi1jbGlfdGFyZ2V0KFwiR2l0SHViIEFjdGlvbnMgLSBDTElcIik7XG4gICAganVuaXRfc3JjKFwiSlVuaXQueG1sXCIpO1xuICAgIGp1bml0X3RhcmdldChcIkpVbml0LnhtbFwiKTtcbiAgICBwaHBtZC1qc29uX3NyYyhcIlBIUG1kLmpzb25cIik7XG4gICAgcGhwbW5kX3NyYyhcIlBIUG1uZC54bWxcIik7XG4gICAgcG1kLWNwZF9zcmMoXCJQbWRDcGQueG1sXCIpO1xuICAgIHBzYWxtLWpzb25fc3JjKFwiUHNhbG0uanNvblwiKTtcbiAgICB0Yy1pbnNwZWN0aW9uc190YXJnZXQoXCJUZWFtQ2l0eSAtIEluc3BlY3Rpb25zXCIpO1xuICAgIHRjLXRlc3RzX3RhcmdldChcIlRlYW1DaXR5IC0gVGVzdHNcIik7XG5cbiAgICBjaGVja3N0eWxlX3NyYyA9PT4gY2ktcmVwb3J0LWNvbnZlcnRlcjtcbiAgICBjaS1yZXBvcnQtY29udmVydGVyID09PiBnaXRodWItY2xpX3RhcmdldDtcbiAgICBjaS1yZXBvcnQtY29udmVydGVyID09PiBqdW5pdF90YXJnZXQ7XG4gICAgY2ktcmVwb3J0LWNvbnZlcnRlciA9PT4gdGMtaW5zcGVjdGlvbnNfdGFyZ2V0O1xuICAgIGNpLXJlcG9ydC1jb252ZXJ0ZXIgPT0+IHRjLXRlc3RzX3RhcmdldDtcbiAgICBqdW5pdF9zcmMgPT0+IGNpLXJlcG9ydC1jb252ZXJ0ZXI7XG4gICAgcGhwbWQtanNvbl9zcmMgPT0+IGNpLXJlcG9ydC1jb252ZXJ0ZXI7XG4gICAgcGhwbW5kX3NyYyA9PT4gY2ktcmVwb3J0LWNvbnZlcnRlcjtcbiAgICBwbWQtY3BkX3NyYyA9PT4gY2ktcmVwb3J0LWNvbnZlcnRlcjtcbiAgICBwc2FsbS1qc29uX3NyYyA9PT4gY2ktcmVwb3J0LWNvbnZlcnRlcjtcblxubGlua1N0eWxlIGRlZmF1bHQgaW50ZXJwb2xhdGUgYmFzaXM7IiwibWVybWFpZCI6eyJ0aGVtZSI6ImZvcmVzdCJ9fQ==">
</p>

```sh
php ./vendor/bin/ci-report-converter convert:map
```

| Source/Target | CheckStyle.xml | GitHub Actions - CLI | JUnit.xml | PHPmd.json | PHPmnd.xml | Psalm.json | TeamCity - Inspections | TeamCity - Tests |
|:-----------------------|:--------------:|:--------------------:|:---------:|:----------:|:----------:|:----------:|:----------------------:|:----------------:|
| CheckStyle.xml | - | Yes | Yes | - | - | - | Yes | Yes |
| GitHub Actions - CLI | - | - | - | - | - | - | - | - |
| JUnit.xml | - | Yes | Yes | - | - | - | Yes | Yes |
| PHPmd.json | - | Yes | Yes | - | - | - | Yes | Yes |
| PHPmnd.xml | - | Yes | Yes | - | - | - | Yes | Yes |
| Psalm.json | - | Yes | Yes | - | - | - | Yes | Yes |
| TeamCity - Inspections | - | - | - | - | - | - | - | - |
| TeamCity - Tests | - | - | - | - | - | - | - | - |

| Source/Target | CheckStyle.xml | GitHub Actions - CLI | JUnit.xml | PHPmd.json | PHPmnd.xml | PmdCpd.xml | Psalm.json | TeamCity - Inspections | TeamCity - Tests |
|:-----------------------|:--------------:|:--------------------:|:---------:|:----------:|:----------:|:----------:|:----------:|:----------------------:|:----------------:|
| CheckStyle.xml | - | Yes | Yes | - | - | - | - | Yes | Yes |
| GitHub Actions - CLI | - | - | - | - | - | - | - | - | - |
| JUnit.xml | - | Yes | Yes | - | - | - | - | Yes | Yes |
| PHPmd.json | - | Yes | Yes | - | - | - | - | Yes | Yes |
| PHPmnd.xml | - | Yes | Yes | - | - | - | - | Yes | Yes |
| PmdCpd.xml | - | Yes | Yes | - | - | - | - | Yes | Yes |
| Psalm.json | - | Yes | Yes | - | - | - | - | Yes | Yes |
| TeamCity - Inspections | - | - | - | - | - | - | - | - | - |
| TeamCity - Tests | - | - | - | - | - | - | - | - | - |



Expand Down
1 change: 1 addition & 0 deletions src/Converters/Map.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Map
TeamCityInspectionsConverter::class => [self::INPUT => false, self::OUTPUT => true],
PhpMndConverter::class => [self::INPUT => true, self::OUTPUT => false],
GithubCliConverter::class => [self::INPUT => false, self::OUTPUT => true],
PmdCpdConverter::class => [self::INPUT => true, self::OUTPUT => false],
];

public const MAP_METRICS = [
Expand Down
190 changes: 190 additions & 0 deletions src/Converters/PmdCpdConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<?php

/**
* JBZoo Toolbox - CI-Report-Converter
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package CI-Report-Converter
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @link https://github.com/JBZoo/CI-Report-Converter
*/

declare(strict_types=1);

namespace JBZoo\CiReportConverter\Converters;

use JBZoo\CiReportConverter\Formats\Source\FileRef;
use JBZoo\CiReportConverter\Formats\Source\SourceCaseOutput;
use JBZoo\CiReportConverter\Formats\Source\SourceSuite;
use JBZoo\CiReportConverter\Formats\Xml;
use JBZoo\Data\Data;

use function JBZoo\Data\data;

/**
* Class PmdCpdConverter
* @package JBZoo\CiReportConverter\Converters
*/
class PmdCpdConverter extends AbstractConverter
{
public const TYPE = 'pmd-cpd';
public const NAME = 'PmdCpd.xml';

/**
* @inheritDoc
*/
public function toInternal(string $source): SourceSuite
{
$xmlAsArray = data(Xml::dom2Array(Xml::createDomDocument($source)));

$sourceSuite = new SourceSuite($this->rootSuiteName ?: 'PMD Copy/Paste Detector');

foreach ($xmlAsArray->find('_children.0._children') as $duplication) {
$duplication = data($duplication);
$lines = self::getLinesNumber($duplication);
$tokens = self::getTokens($duplication);

$mainFile = $this->getFileByIndex($duplication);
$errorTitle = "Duplicate code found (lines={$lines}, tokens={$tokens})";

$case = $sourceSuite->addTestCase(self::getTestCaseName($mainFile, $lines));
$case->file = $mainFile->fullpath;
$case->line = $mainFile->line;
$case->warning = new SourceCaseOutput('Warning', $errorTitle, $this->getDetails($duplication));
}

return $sourceSuite;
}

/**
* @param Data $duplication
* @param int $index
* @return FileRef
*/
private function getFileByIndex(Data $duplication, int $index = 0): FileRef
{
$fileRef = new FileRef();
$fileRef->fullpath = $duplication->findString("_children.{$index}._attrs.path");
$fileRef->line = $duplication->findInt("_children.{$index}._attrs.line");
$fileRef->name = $this->cleanFilepath($fileRef->fullpath ?: '');

return $fileRef;
}

/**
* @param Data $duplication
* @return FileRef[]
*/
private function getFileList(Data $duplication): array
{
$list = [];

foreach ($duplication->getArray('_children') as $index => $child) {
if (isset($child['_node']) && $child['_node'] === 'file') {
$list[] = $this->getFileByIndex($duplication, $index);
}
}

return $list;
}

/**
* @param Data $duplication
* @return string
*/
private static function getCodeFragment(Data $duplication): string
{
foreach ($duplication->getArray('_children') as $child) {
if (isset($child['_node']) && $child['_node'] === 'codefragment') {
return $child['_text'] ?? 'Undefined Code Fragment';
}
}

return 'Undefined Code Fragment';
}

/**
* @param Data $duplication
* @return int
*/
private static function getLinesNumber(Data $duplication): int
{
return $duplication->findInt('_attrs.lines');
}

/**
* @param Data $duplication
* @return int
*/
private static function getTokens(Data $duplication): int
{
return $duplication->findInt('_attrs.tokens');
}

/**
* @param Data $duplication
* @return string
*/
private function getDetails(Data $duplication): string
{
$fileList = $this->getFileList($duplication);

$lines = self::getLinesNumber($duplication);
$tokens = self::getTokens($duplication);
$fileNumber = count($fileList);

$filesAsString = '';
foreach ($fileList as $fileRef) {
$filePoint = self::getFileName($fileRef, $lines);
$filesAsString .= "- {$filePoint}\n";
}

return implode("\n", [
'',
"Found {$lines} cloned lines in {$fileNumber} files ({$tokens} tokens):",
$filesAsString,
'',
"Code Fragment:",
'',
'```',
self::getCodeFragment($duplication),
'```',
]);
}

/**
* @param FileRef $fileRef
* @param int $lines
* @return string
*/
private static function getTestCaseName(FileRef $fileRef, int $lines): string
{
$startLine = (int)$fileRef->line;
$endLine = $startLine + $lines;
$place = $startLine === $endLine ? (string)$startLine : "{$startLine}-{$endLine}";

if ($lines > 0) {
return "{$fileRef->name}:{$place} ({$lines} lines)";
}

return "{$fileRef->name}:{$place}";
}

/**
* @param FileRef $fileRef
* @param int $lines
* @return string
*/
private static function getFileName(FileRef $fileRef, int $lines = 0): string
{
$startLine = (int)$fileRef->line;
$endLine = $startLine + $lines;
$place = $startLine === $endLine ? (string)$startLine : "{$startLine}-{$endLine}";

return "{$fileRef->fullpath}:{$place}";
}
}
4 changes: 3 additions & 1 deletion src/Formats/JUnit/CaseOutput/AbstractOutput.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

namespace JBZoo\CiReportConverter\Formats\JUnit\CaseOutput;

use JBZoo\Utils\Xml;

/**
* Class AbstractOutput
* @package JBZoo\CiReportConverter\Formats\JUnit\CaseOutput
Expand Down Expand Up @@ -85,7 +87,7 @@ public function setDescription(string $description): self
public function toXML(\DOMDocument $document): \DOMNode
{
if (null !== $this->description) {
$node = $document->createElement($this->elementName, str_replace(' &0 ', ' &amp;0 ', $this->description));
$node = $document->createElement($this->elementName, Xml::escape($this->description));
} else {
$node = $document->createElement($this->elementName);
}
Expand Down
67 changes: 67 additions & 0 deletions src/Formats/Source/FileRef.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/**
* JBZoo Toolbox - CI-Report-Converter
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package CI-Report-Converter
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @link https://github.com/JBZoo/CI-Report-Converter
*/

declare(strict_types=1);

namespace JBZoo\CiReportConverter\Formats\Source;

use JBZoo\CiReportConverter\Formats\AbstractNode;

/**
* Class FileRef
* @package JBZoo\CiReportConverter\Formats\Source
*
* @property string $name
* @property string|null $fullpath
* @property int|null $line
* @property int|null $column
*/
class FileRef extends AbstractNode
{
/**
* @var array
*/
protected $meta = [
'name' => ['string'], // It's relative path to file
'fullpath' => ['string'],
'line' => ['int'],
];

/**
* @return string
*/
public function getFullName(): string
{
$result = (string)$this->fullpath;
if ($this->line > 0) {
$result .= ":{$this->line}";
}

return $result;
}

/**
* @return string
*/
public function getShortName(): string
{
$result = $this->name;
if ($this->line > 0) {
$result .= " on line {$this->line}";
}

return $result;
}
}
54 changes: 54 additions & 0 deletions tests/ConverterPmdCpdTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/**
* JBZoo Toolbox - CI-Report-Converter
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package CI-Report-Converter
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @link https://github.com/JBZoo/CI-Report-Converter
*/

declare(strict_types=1);

namespace JBZoo\PHPUnit;

use JBZoo\CiReportConverter\Converters\JUnitConverter;
use JBZoo\CiReportConverter\Converters\PmdCpdConverter;
use JBZoo\CiReportConverter\Converters\TeamCityTestsConverter;

/**
* Class ConverterPmdCpdTest
*
* @package JBZoo\PHPUnit
*/
class ConverterPmdCpdTest extends PHPUnit
{
public function testToJUnit()
{
$source = (new PmdCpdConverter())
->setRootPath('/Users/smetdenis/Work/projects/jbzoo-ci-report-converter')
->toInternal(file_get_contents(Fixtures::PHPCPD_XML));

$actual = (new JUnitConverter())->fromInternal($source);

Aliases::isValidXml($actual);
isSame(Fixtures::getExpectedFileContent(), $actual);
}

public function testToTeamCity()
{
$source = (new PmdCpdConverter())
->setRootPath('/Users/smetdenis/Work/projects/jbzoo-ci-report-converter')
->toInternal(file_get_contents(Fixtures::PHPCPD_XML));

$actual = (new TeamCityTestsConverter(['show-datetime' => false], 42))
->fromInternal($source);

isSame(Fixtures::getExpectedFileContent('txt'), $actual);
}
}

0 comments on commit ff1b57c

Please sign in to comment.