Skip to content

Commit c7f66e7

Browse files
authored
ORGA-2151 generate trend result file in json to allow later formatting (#121)
1 parent 84f6432 commit c7f66e7

File tree

4 files changed

+209
-35
lines changed

4 files changed

+209
-35
lines changed

bin/phpstan-baseline-trend.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
22

33
use function Safe\ini_set;
4+
use function Safe\substr;
5+
use function Safe\sprintf;
46

57
// Finding composer
68

@@ -32,5 +34,27 @@
3234
exit(254);
3335
}
3436

35-
$exitCode = $app->start($argv[1], $argv[2]);
37+
$exitCode = $app->start($argv[1], $argv[2], extractOutputFormat($argv));
3638
exit($exitCode);
39+
40+
/**
41+
* @param list<string> $args
42+
* @return \staabm\PHPStanBaselineAnalysis\TrendApplication::OUTPUT_FORMAT_*
43+
*/
44+
function extractOutputFormat(array $args): string
45+
{
46+
foreach($args as $arg) {
47+
if (false === strpos($arg, '--format=')) {
48+
continue;
49+
}
50+
51+
$format = substr($arg, strlen('--format='));
52+
if (in_array($format, \staabm\PHPStanBaselineAnalysis\TrendApplication::getAllowedOutputFormats(), true)) {
53+
return $format;
54+
}
55+
56+
throw new \InvalidArgumentException(sprintf('Invalid output format "%s".', $format));
57+
}
58+
59+
return \staabm\PHPStanBaselineAnalysis\TrendApplication::OUTPUT_FORMAT_DEFAULT;
60+
}

lib/TrendApplication.php

Lines changed: 93 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
namespace staabm\PHPStanBaselineAnalysis;
44

5-
use \Iterator;
6-
use function Safe\file_get_contents;
7-
use function Safe\json_decode;
5+
use function Safe\json_encode;
86

97
final class TrendApplication
108
{
@@ -21,53 +19,119 @@ final class TrendApplication
2119
*/
2220
const EXIT_WORSE = 2;
2321

22+
public const OUTPUT_FORMAT_DEFAULT = 'text';
23+
2424
/**
25+
* @api
26+
*/
27+
public const OUTPUT_FORMAT_JSON = 'json';
28+
29+
/**
30+
* @return list<self::OUTPUT_FORMAT_*>
31+
*/
32+
public static function getAllowedOutputFormats(): array
33+
{
34+
return [
35+
self::OUTPUT_FORMAT_DEFAULT,
36+
self::OUTPUT_FORMAT_JSON,
37+
];
38+
}
39+
40+
/**
41+
* @param self::OUTPUT_FORMAT_* $outputFormat
2542
* @return self::EXIT_*
2643
* @throws \Safe\Exceptions\JsonException
2744
*
2845
* @throws \Safe\Exceptions\FilesystemException
2946
*/
30-
public function start(string $referenceFilePath, string $comparingFilePath): int
47+
public function start(string $referenceFilePath, string $comparingFilePath, string $outputFormat): int
3148
{
3249
$exitCode = self::EXIT_IMPROVED;
3350

3451
$reader = new AnalyzerResultReader();
3552
$reference = $reader->readFile($referenceFilePath);
3653
$comparing = $reader->readFile($comparingFilePath);
3754

38-
foreach ($reference as $baselinePath => $result) {
39-
echo 'Analyzing Trend for ' . $baselinePath . "\n";
55+
if ($outputFormat === self::OUTPUT_FORMAT_JSON) {
56+
return $this->createOutputJson($reference, $comparing, $exitCode);
57+
}
58+
59+
return $this->createOutputText($reference, $comparing, $exitCode);
60+
}
4061

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

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

48-
$exitCode = $this->compare(ResultPrinter::KEY_DEPRECATIONS, $result->deprecations, $comparing[$baselinePath]->deprecations, $exitCode);
49-
echo "\n";
68+
/**
69+
* @param array<string, AnalyzerResult> $reference
70+
* @param array<string, AnalyzerResult> $comparing
71+
* @param self::EXIT_* $exitCode
72+
*
73+
* @return self::EXIT_*
74+
*/
75+
private function createOutputText(array $reference, array $comparing, int $exitCode): int
76+
{
77+
foreach ($reference as $baselinePath => $result) {
78+
list($trendResult, $exitCode) = $this->createTrendResult($baselinePath, $comparing, $result, $exitCode);
79+
80+
echo $trendResult->headline . "\n";
81+
foreach($trendResult->results as $key => $stats) {
82+
echo ' '.$key.': '.$stats['reference']." -> ".$stats['comparing']." => ".$stats['trend']."\n";
83+
}
84+
}
5085

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

54-
$exitCode = $this->compare(ResultPrinter::KEY_UNKNOWN_TYPES, $result->unknownTypes, $comparing[$baselinePath]->unknownTypes, $exitCode);
55-
echo "\n";
89+
/**
90+
* @param array<string, AnalyzerResult> $reference
91+
* @param array<string, AnalyzerResult> $comparing
92+
* @param self::EXIT_* $exitCode
93+
*
94+
* @return self::EXIT_*
95+
*/
96+
private function createOutputJson(array $reference, array $comparing, int $exitCode): int
97+
{
98+
$trendResults = [];
99+
foreach ($reference as $baselinePath => $result) {
56100

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

60-
$exitCode = $this->compare(ResultPrinter::KEY_UNUSED_SYMBOLS, $result->unusedSymbols, $comparing[$baselinePath]->unusedSymbols, $exitCode);
61-
echo "\n";
62-
}
103+
$trendResults[] = $trendResult;
63104
}
64105

106+
echo json_encode($trendResults);
107+
108+
65109
return $exitCode;
66110
}
67111

68-
public function help(): void
112+
/**
113+
* @param array<string, AnalyzerResult> $comparing
114+
* @param self::EXIT_* $exitCode
115+
*
116+
* @return array{TrendResult, self::EXIT_*}
117+
*/
118+
private function createTrendResult(string $baselinePath, array $comparing, AnalyzerResult $reference, int $exitCode): array
69119
{
70-
printf('USAGE: phpstan-baseline-trend <reference-result.json> <comparing-result.json>');
120+
$trendResult = new TrendResult('Analyzing Trend for ' . $baselinePath);
121+
122+
if (!isset($comparing[$baselinePath])) {
123+
return array($trendResult, $exitCode);
124+
}
125+
126+
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_OVERALL_ERRORS, $reference->overallErrors, $comparing[$baselinePath]->overallErrors, $exitCode);
127+
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_CLASSES_COMPLEXITY, $reference->classesComplexity, $comparing[$baselinePath]->classesComplexity, $exitCode);
128+
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_DEPRECATIONS, $reference->deprecations, $comparing[$baselinePath]->deprecations, $exitCode);
129+
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_INVALID_PHPDOCS, $reference->invalidPhpdocs, $comparing[$baselinePath]->invalidPhpdocs, $exitCode);
130+
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_UNKNOWN_TYPES, $reference->unknownTypes, $comparing[$baselinePath]->unknownTypes, $exitCode);
131+
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_ANONYMOUS_VARIABLES, $reference->anonymousVariables, $comparing[$baselinePath]->anonymousVariables, $exitCode);
132+
$exitCode = $this->compare($trendResult, ResultPrinter::KEY_UNUSED_SYMBOLS, $reference->unusedSymbols, $comparing[$baselinePath]->unusedSymbols, $exitCode);
133+
134+
return array($trendResult, $exitCode);
71135
}
72136

73137
/**
@@ -78,21 +142,19 @@ public function help(): void
78142
*
79143
* @return self::EXIT_*
80144
*/
81-
private function compare($key, $referenceValue, $comparingValue, $exitCode): int
145+
private function compare(TrendResult $trendResult, string $key, $referenceValue, $comparingValue, int $exitCode): int
82146
{
83147
if ($comparingValue > $referenceValue) {
84-
printf(' %s: %d -> %d => worse', $key, $referenceValue, $comparingValue);
85-
148+
$trendResult->setKey($key, $referenceValue, $comparingValue, 'worse');
86149
$exitCode = max($exitCode, self::EXIT_WORSE);
87150
} elseif ($comparingValue < $referenceValue) {
88-
printf(' %s: %d -> %d => improved', $key, $referenceValue, $comparingValue);
89-
151+
$trendResult->setKey($key, $referenceValue, $comparingValue, 'improved');
90152
$exitCode = max($exitCode, self::EXIT_IMPROVED);
91153
} else {
92-
printf(' %s: %d -> %d => good', $key, $referenceValue, $comparingValue);
93-
154+
$trendResult->setKey($key, $referenceValue, $comparingValue, 'good');
94155
$exitCode = max($exitCode, self::EXIT_STEADY);
95156
}
157+
96158
return $exitCode;
97159
}
98160
}

lib/TrendResult.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace staabm\PHPStanBaselineAnalysis;
4+
5+
final class TrendResult
6+
{
7+
public string $headline;
8+
9+
/**
10+
* @var array<ResultPrinter::KEY_*, array{reference: int, comparing: int, trend: string}>
11+
*/
12+
public array $results;
13+
14+
public function __construct(string $headline)
15+
{
16+
$this->headline = $headline;
17+
$this->results = [];
18+
}
19+
20+
/**
21+
* @param ResultPrinter::KEY_* $key
22+
* @param int $referenceValue
23+
* @param int $comparingValue
24+
* @return void
25+
*/
26+
public function setKey(string $key, $referenceValue, $comparingValue, string $trend): void
27+
{
28+
$this->results[$key] = [
29+
'reference' => $referenceValue,
30+
'comparing' => $comparingValue,
31+
'trend' => $trend,
32+
];
33+
}
34+
}

tests/TrendApplicationTest.php

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function testSameTrend():void
1111
$app = new TrendApplication();
1212

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

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

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

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

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

6969
$rendered = str_replace(__DIR__, '', $rendered);
@@ -78,6 +78,60 @@ function testLowerTrend():void
7878
Anonymous-Variables: 2 -> 1 => improved
7979
Unused-Symbols: 1 -> 0 => improved
8080
81+
PHP;
82+
83+
$this->assertSame($expected, $rendered);
84+
$this->assertSame(TrendApplication::EXIT_IMPROVED, $exitCode);
85+
}
86+
87+
function testSameTrendFormatJson():void
88+
{
89+
$app = new TrendApplication();
90+
91+
ob_start();
92+
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-same-result.json', TrendApplication::OUTPUT_FORMAT_JSON);
93+
$rendered = ob_get_clean();
94+
95+
$rendered = str_replace(__DIR__, '', $rendered);
96+
97+
$expected = <<<PHP
98+
[{"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"}}}]
99+
PHP;
100+
101+
$this->assertSame($expected, $rendered);
102+
$this->assertSame(TrendApplication::EXIT_STEADY, $exitCode);
103+
}
104+
105+
function testHigherTrendFormatJson():void
106+
{
107+
$app = new TrendApplication();
108+
109+
ob_start();
110+
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-higher-result.json', TrendApplication::OUTPUT_FORMAT_JSON);
111+
$rendered = ob_get_clean();
112+
113+
$rendered = str_replace(__DIR__, '', $rendered);
114+
115+
$expected = <<<PHP
116+
[{"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"}}}]
117+
PHP;
118+
119+
$this->assertSame($expected, $rendered);
120+
$this->assertSame(TrendApplication::EXIT_WORSE, $exitCode);
121+
}
122+
123+
function testLowerTrendFormatJson():void
124+
{
125+
$app = new TrendApplication();
126+
127+
ob_start();
128+
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-lower-result.json', TrendApplication::OUTPUT_FORMAT_JSON);
129+
$rendered = ob_get_clean();
130+
131+
$rendered = str_replace(__DIR__, '', $rendered);
132+
133+
$expected = <<<PHP
134+
[{"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"}}}]
81135
PHP;
82136

83137
$this->assertSame($expected, $rendered);

0 commit comments

Comments
 (0)