Skip to content

Commit

Permalink
ORGA-2151 generate trend result file in json to allow later formatting (
Browse files Browse the repository at this point in the history
  • Loading branch information
trailsnail authored Jun 26, 2023
1 parent 84f6432 commit c7f66e7
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 35 deletions.
26 changes: 25 additions & 1 deletion bin/phpstan-baseline-trend.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

use function Safe\ini_set;
use function Safe\substr;
use function Safe\sprintf;

// Finding composer

Expand Down Expand Up @@ -32,5 +34,27 @@
exit(254);
}

$exitCode = $app->start($argv[1], $argv[2]);
$exitCode = $app->start($argv[1], $argv[2], extractOutputFormat($argv));
exit($exitCode);

/**
* @param list<string> $args
* @return \staabm\PHPStanBaselineAnalysis\TrendApplication::OUTPUT_FORMAT_*
*/
function extractOutputFormat(array $args): string
{
foreach($args as $arg) {
if (false === strpos($arg, '--format=')) {
continue;
}

$format = substr($arg, strlen('--format='));
if (in_array($format, \staabm\PHPStanBaselineAnalysis\TrendApplication::getAllowedOutputFormats(), true)) {
return $format;
}

throw new \InvalidArgumentException(sprintf('Invalid output format "%s".', $format));
}

return \staabm\PHPStanBaselineAnalysis\TrendApplication::OUTPUT_FORMAT_DEFAULT;
}
124 changes: 93 additions & 31 deletions lib/TrendApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace staabm\PHPStanBaselineAnalysis;

use \Iterator;
use function Safe\file_get_contents;
use function Safe\json_decode;
use function Safe\json_encode;

final class TrendApplication
{
Expand All @@ -21,53 +19,119 @@ final class TrendApplication
*/
const EXIT_WORSE = 2;

public const OUTPUT_FORMAT_DEFAULT = 'text';

/**
* @api
*/
public const OUTPUT_FORMAT_JSON = 'json';

/**
* @return list<self::OUTPUT_FORMAT_*>
*/
public static function getAllowedOutputFormats(): array
{
return [
self::OUTPUT_FORMAT_DEFAULT,
self::OUTPUT_FORMAT_JSON,
];
}

/**
* @param self::OUTPUT_FORMAT_* $outputFormat
* @return self::EXIT_*
* @throws \Safe\Exceptions\JsonException
*
* @throws \Safe\Exceptions\FilesystemException
*/
public function start(string $referenceFilePath, string $comparingFilePath): int
public function start(string $referenceFilePath, string $comparingFilePath, string $outputFormat): int
{
$exitCode = self::EXIT_IMPROVED;

$reader = new AnalyzerResultReader();
$reference = $reader->readFile($referenceFilePath);
$comparing = $reader->readFile($comparingFilePath);

foreach ($reference as $baselinePath => $result) {
echo 'Analyzing Trend for ' . $baselinePath . "\n";
if ($outputFormat === self::OUTPUT_FORMAT_JSON) {
return $this->createOutputJson($reference, $comparing, $exitCode);
}

return $this->createOutputText($reference, $comparing, $exitCode);
}

if (isset($comparing[$baselinePath])) {
$exitCode = $this->compare(ResultPrinter::KEY_OVERALL_ERRORS, $result->overallErrors, $comparing[$baselinePath]->overallErrors, $exitCode);
echo "\n";
public function help(): void
{
printf('USAGE: phpstan-baseline-trend <reference-result.json> <comparing-result.json> [--format=json|text]');
}

$exitCode = $this->compare(ResultPrinter::KEY_CLASSES_COMPLEXITY, $result->classesComplexity, $comparing[$baselinePath]->classesComplexity, $exitCode);
echo "\n";

$exitCode = $this->compare(ResultPrinter::KEY_DEPRECATIONS, $result->deprecations, $comparing[$baselinePath]->deprecations, $exitCode);
echo "\n";
/**
* @param array<string, AnalyzerResult> $reference
* @param array<string, AnalyzerResult> $comparing
* @param self::EXIT_* $exitCode
*
* @return self::EXIT_*
*/
private function createOutputText(array $reference, array $comparing, int $exitCode): int
{
foreach ($reference as $baselinePath => $result) {
list($trendResult, $exitCode) = $this->createTrendResult($baselinePath, $comparing, $result, $exitCode);

echo $trendResult->headline . "\n";
foreach($trendResult->results as $key => $stats) {
echo ' '.$key.': '.$stats['reference']." -> ".$stats['comparing']." => ".$stats['trend']."\n";
}
}

$exitCode = $this->compare(ResultPrinter::KEY_INVALID_PHPDOCS, $result->invalidPhpdocs, $comparing[$baselinePath]->invalidPhpdocs, $exitCode);
echo "\n";
return $exitCode;
}

$exitCode = $this->compare(ResultPrinter::KEY_UNKNOWN_TYPES, $result->unknownTypes, $comparing[$baselinePath]->unknownTypes, $exitCode);
echo "\n";
/**
* @param array<string, AnalyzerResult> $reference
* @param array<string, AnalyzerResult> $comparing
* @param self::EXIT_* $exitCode
*
* @return self::EXIT_*
*/
private function createOutputJson(array $reference, array $comparing, int $exitCode): int
{
$trendResults = [];
foreach ($reference as $baselinePath => $result) {

$exitCode = $this->compare(ResultPrinter::KEY_ANONYMOUS_VARIABLES, $result->anonymousVariables, $comparing[$baselinePath]->anonymousVariables, $exitCode);
echo "\n";
list($trendResult, $exitCode) = $this->createTrendResult($baselinePath, $comparing, $result, $exitCode);

$exitCode = $this->compare(ResultPrinter::KEY_UNUSED_SYMBOLS, $result->unusedSymbols, $comparing[$baselinePath]->unusedSymbols, $exitCode);
echo "\n";
}
$trendResults[] = $trendResult;
}

echo json_encode($trendResults);


return $exitCode;
}

public function help(): void
/**
* @param array<string, AnalyzerResult> $comparing
* @param self::EXIT_* $exitCode
*
* @return array{TrendResult, self::EXIT_*}
*/
private function createTrendResult(string $baselinePath, array $comparing, AnalyzerResult $reference, int $exitCode): array
{
printf('USAGE: phpstan-baseline-trend <reference-result.json> <comparing-result.json>');
$trendResult = new TrendResult('Analyzing Trend for ' . $baselinePath);

if (!isset($comparing[$baselinePath])) {
return array($trendResult, $exitCode);
}

$exitCode = $this->compare($trendResult, ResultPrinter::KEY_OVERALL_ERRORS, $reference->overallErrors, $comparing[$baselinePath]->overallErrors, $exitCode);
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_CLASSES_COMPLEXITY, $reference->classesComplexity, $comparing[$baselinePath]->classesComplexity, $exitCode);
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_DEPRECATIONS, $reference->deprecations, $comparing[$baselinePath]->deprecations, $exitCode);
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_INVALID_PHPDOCS, $reference->invalidPhpdocs, $comparing[$baselinePath]->invalidPhpdocs, $exitCode);
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_UNKNOWN_TYPES, $reference->unknownTypes, $comparing[$baselinePath]->unknownTypes, $exitCode);
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_ANONYMOUS_VARIABLES, $reference->anonymousVariables, $comparing[$baselinePath]->anonymousVariables, $exitCode);
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_UNUSED_SYMBOLS, $reference->unusedSymbols, $comparing[$baselinePath]->unusedSymbols, $exitCode);

return array($trendResult, $exitCode);
}

/**
Expand All @@ -78,21 +142,19 @@ public function help(): void
*
* @return self::EXIT_*
*/
private function compare($key, $referenceValue, $comparingValue, $exitCode): int
private function compare(TrendResult $trendResult, string $key, $referenceValue, $comparingValue, int $exitCode): int
{
if ($comparingValue > $referenceValue) {
printf(' %s: %d -> %d => worse', $key, $referenceValue, $comparingValue);

$trendResult->setKey($key, $referenceValue, $comparingValue, 'worse');
$exitCode = max($exitCode, self::EXIT_WORSE);
} elseif ($comparingValue < $referenceValue) {
printf(' %s: %d -> %d => improved', $key, $referenceValue, $comparingValue);

$trendResult->setKey($key, $referenceValue, $comparingValue, 'improved');
$exitCode = max($exitCode, self::EXIT_IMPROVED);
} else {
printf(' %s: %d -> %d => good', $key, $referenceValue, $comparingValue);

$trendResult->setKey($key, $referenceValue, $comparingValue, 'good');
$exitCode = max($exitCode, self::EXIT_STEADY);
}

return $exitCode;
}
}
34 changes: 34 additions & 0 deletions lib/TrendResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace staabm\PHPStanBaselineAnalysis;

final class TrendResult
{
public string $headline;

/**
* @var array<ResultPrinter::KEY_*, array{reference: int, comparing: int, trend: string}>
*/
public array $results;

public function __construct(string $headline)
{
$this->headline = $headline;
$this->results = [];
}

/**
* @param ResultPrinter::KEY_* $key
* @param int $referenceValue
* @param int $comparingValue
* @return void
*/
public function setKey(string $key, $referenceValue, $comparingValue, string $trend): void
{
$this->results[$key] = [
'reference' => $referenceValue,
'comparing' => $comparingValue,
'trend' => $trend,
];
}
}
60 changes: 57 additions & 3 deletions tests/TrendApplicationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function testSameTrend():void
$app = new TrendApplication();

ob_start();
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-same-result.json');
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-same-result.json', TrendApplication::OUTPUT_FORMAT_DEFAULT);
$rendered = ob_get_clean();

$rendered = str_replace(__DIR__, '', $rendered);
Expand All @@ -37,7 +37,7 @@ function testHigherTrend():void
$app = new TrendApplication();

ob_start();
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-higher-result.json');
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-higher-result.json', TrendApplication::OUTPUT_FORMAT_DEFAULT);
$rendered = ob_get_clean();

$rendered = str_replace(__DIR__, '', $rendered);
Expand All @@ -63,7 +63,7 @@ function testLowerTrend():void
$app = new TrendApplication();

ob_start();
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-lower-result.json');
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-lower-result.json', TrendApplication::OUTPUT_FORMAT_DEFAULT);
$rendered = ob_get_clean();

$rendered = str_replace(__DIR__, '', $rendered);
Expand All @@ -78,6 +78,60 @@ function testLowerTrend():void
Anonymous-Variables: 2 -> 1 => improved
Unused-Symbols: 1 -> 0 => improved
PHP;

$this->assertSame($expected, $rendered);
$this->assertSame(TrendApplication::EXIT_IMPROVED, $exitCode);
}

function testSameTrendFormatJson():void
{
$app = new TrendApplication();

ob_start();
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-same-result.json', TrendApplication::OUTPUT_FORMAT_JSON);
$rendered = ob_get_clean();

$rendered = str_replace(__DIR__, '', $rendered);

$expected = <<<PHP
[{"headline":"Analyzing Trend for \/fixtures\/all-in.neon","results":{"Overall-Errors":{"reference":18,"comparing":18,"trend":"good"},"Classes-Cognitive-Complexity":{"reference":70,"comparing":70,"trend":"good"},"Deprecations":{"reference":1,"comparing":1,"trend":"good"},"Invalid-Phpdocs":{"reference":3,"comparing":3,"trend":"good"},"Unknown-Types":{"reference":5,"comparing":5,"trend":"good"},"Anonymous-Variables":{"reference":2,"comparing":2,"trend":"good"},"Unused-Symbols":{"reference":1,"comparing":1,"trend":"good"}}}]
PHP;

$this->assertSame($expected, $rendered);
$this->assertSame(TrendApplication::EXIT_STEADY, $exitCode);
}

function testHigherTrendFormatJson():void
{
$app = new TrendApplication();

ob_start();
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-higher-result.json', TrendApplication::OUTPUT_FORMAT_JSON);
$rendered = ob_get_clean();

$rendered = str_replace(__DIR__, '', $rendered);

$expected = <<<PHP
[{"headline":"Analyzing Trend for \/fixtures\/all-in.neon","results":{"Overall-Errors":{"reference":18,"comparing":24,"trend":"worse"},"Classes-Cognitive-Complexity":{"reference":70,"comparing":90,"trend":"worse"},"Deprecations":{"reference":1,"comparing":10,"trend":"worse"},"Invalid-Phpdocs":{"reference":3,"comparing":30,"trend":"worse"},"Unknown-Types":{"reference":5,"comparing":15,"trend":"worse"},"Anonymous-Variables":{"reference":2,"comparing":5,"trend":"worse"},"Unused-Symbols":{"reference":1,"comparing":10,"trend":"worse"}}}]
PHP;

$this->assertSame($expected, $rendered);
$this->assertSame(TrendApplication::EXIT_WORSE, $exitCode);
}

function testLowerTrendFormatJson():void
{
$app = new TrendApplication();

ob_start();
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-lower-result.json', TrendApplication::OUTPUT_FORMAT_JSON);
$rendered = ob_get_clean();

$rendered = str_replace(__DIR__, '', $rendered);

$expected = <<<PHP
[{"headline":"Analyzing Trend for \/fixtures\/all-in.neon","results":{"Overall-Errors":{"reference":18,"comparing":10,"trend":"improved"},"Classes-Cognitive-Complexity":{"reference":70,"comparing":50,"trend":"improved"},"Deprecations":{"reference":1,"comparing":0,"trend":"improved"},"Invalid-Phpdocs":{"reference":3,"comparing":1,"trend":"improved"},"Unknown-Types":{"reference":5,"comparing":3,"trend":"improved"},"Anonymous-Variables":{"reference":2,"comparing":1,"trend":"improved"},"Unused-Symbols":{"reference":1,"comparing":0,"trend":"improved"}}}]
PHP;

$this->assertSame($expected, $rendered);
Expand Down

0 comments on commit c7f66e7

Please sign in to comment.