Skip to content

Commit

Permalink
Allow generating baseline in .php format
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Feb 23, 2023
1 parent 34881e6 commit 8260032
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 8 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,29 @@ jobs:
cp phpstan-baseline.neon phpstan-baseline-orig.neon && \
make phpstan-generate-baseline && \
diff phpstan-baseline.neon phpstan-baseline-orig.neon
generate-baseline-php:
name: "Generate PHP baseline"

runs-on: "ubuntu-latest"
timeout-minutes: 60

steps:
- name: "Checkout"
uses: actions/checkout@v3

- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "8.1"
ini-file: development

- name: "Install dependencies"
run: "composer install --no-interaction --no-progress"

- name: "Generate baseline"
run: |
> phpstan-baseline.neon && \
make phpstan-generate-baseline-php && \
make phpstan-result-cache
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ phpstan-result-cache:
phpstan-generate-baseline:
php -d memory_limit=448M bin/phpstan --generate-baseline

phpstan-generate-baseline-php:
php -d memory_limit=448M bin/phpstan analyse --generate-baseline phpstan-baseline.php

phpstan-pro:
php -d memory_limit=448M bin/phpstan --pro

Expand Down
1 change: 1 addition & 0 deletions build/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ includes:
- ../vendor/phpstan/phpstan-strict-rules/rules.neon
- ../conf/bleedingEdge.neon
- ../phpstan-baseline.neon
- ../phpstan-baseline.php
- ignore-by-php-version.neon.php
- ignore-by-architecture.neon.php
parameters:
Expand Down
3 changes: 3 additions & 0 deletions phpstan-baseline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php declare(strict_types = 1);

return [];
23 changes: 15 additions & 8 deletions src/Command/AnalyseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use OndraM\CiDetector\CiDetector;
use PHPStan\Command\ErrorFormatter\BaselineNeonErrorFormatter;
use PHPStan\Command\ErrorFormatter\BaselinePhpErrorFormatter;
use PHPStan\Command\ErrorFormatter\ErrorFormatter;
use PHPStan\Command\ErrorFormatter\TableErrorFormatter;
use PHPStan\Command\Symfony\SymfonyOutput;
Expand All @@ -28,6 +29,7 @@
use function fopen;
use function get_class;
use function implode;
use function in_array;
use function is_array;
use function is_bool;
use function is_dir;
Expand Down Expand Up @@ -202,8 +204,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return $inceptionResult->handleReturn(1, null);
}

if ($baselineExtension !== 'neon') {
$inceptionResult->getStdOutput()->getStyle()->error(sprintf('Baseline filename extension must be .neon, .%s was used instead.', $baselineExtension));
if (!in_array($baselineExtension, ['neon', 'php'], true)) {
$inceptionResult->getStdOutput()->getStyle()->error(sprintf('Baseline filename extension must be .neon or .php, .%s was used instead.', $baselineExtension));

return $inceptionResult->handleReturn(1, null);
}
Expand Down Expand Up @@ -292,15 +294,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes());
}

$baselineFileDirectory = dirname($generateBaselineFile);
$baselineErrorFormatter = new BaselineNeonErrorFormatter(new ParentDirectoryRelativePathHelper($baselineFileDirectory));

$existingBaselineContent = is_file($generateBaselineFile) ? FileReader::read($generateBaselineFile) : '';

$streamOutput = $this->createStreamOutput();
$errorConsoleStyle = new ErrorsConsoleStyle(new StringInput(''), $streamOutput);
$baselineOutput = new SymfonyOutput($streamOutput, new SymfonyStyle($errorConsoleStyle));
$baselineErrorFormatter->formatErrors($analysisResult, $baselineOutput, $existingBaselineContent);
$baselineFileDirectory = dirname($generateBaselineFile);
$baselinePathHelper = new ParentDirectoryRelativePathHelper($baselineFileDirectory);

if ($baselineExtension === 'php') {
$baselineErrorFormatter = new BaselinePhpErrorFormatter($baselinePathHelper);
$baselineErrorFormatter->formatErrors($analysisResult, $baselineOutput);
} else {
$baselineErrorFormatter = new BaselineNeonErrorFormatter($baselinePathHelper);
$existingBaselineContent = is_file($generateBaselineFile) ? FileReader::read($generateBaselineFile) : '';
$baselineErrorFormatter->formatErrors($analysisResult, $baselineOutput, $existingBaselineContent);
}

$stream = $streamOutput->getStream();
rewind($stream);
Expand Down
87 changes: 87 additions & 0 deletions src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php declare(strict_types = 1);

namespace PHPStan\Command\ErrorFormatter;

use Nette\DI\Helpers;
use PHPStan\Command\AnalysisResult;
use PHPStan\Command\Output;
use PHPStan\File\RelativePathHelper;
use function ksort;
use function preg_quote;
use function sprintf;
use function var_export;
use const SORT_STRING;

class BaselinePhpErrorFormatter
{

public function __construct(private RelativePathHelper $relativePathHelper)
{
}

public function formatErrors(
AnalysisResult $analysisResult,
Output $output,
): int
{
if (!$analysisResult->hasErrors()) {
$php = '<?php declare(strict_types = 1);';
$php .= "\n\n";
$php .= 'return [];';
$php .= "\n";
$output->writeRaw($php);
return 0;
}

$fileErrors = [];
foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) {
if (!$fileSpecificError->canBeIgnored()) {
continue;
}
$fileErrors['/' . $this->relativePathHelper->getRelativePath($fileSpecificError->getFilePath())][] = $fileSpecificError->getMessage();
}
ksort($fileErrors, SORT_STRING);

$php = '<?php declare(strict_types = 1);';
$php .= "\n\n";
$php .= '$ignoreErrors = [];';
$php .= "\n";
foreach ($fileErrors as $file => $errorMessages) {
$fileErrorsCounts = [];
foreach ($errorMessages as $errorMessage) {
if (!isset($fileErrorsCounts[$errorMessage])) {
$fileErrorsCounts[$errorMessage] = 1;
continue;
}

$fileErrorsCounts[$errorMessage]++;
}
ksort($fileErrorsCounts, SORT_STRING);

foreach ($fileErrorsCounts as $message => $count) {
$template = <<<'PHP'
$ignoreErrors[] = [
'message' => %s,
'count' => %d,
'path' => __DIR__ . %s,
];
PHP;
$php .= sprintf(
$template,
var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true),
var_export($count, true),
var_export(Helpers::escape($file), true),
);
$php .= "\n";
}
}

$php .= "\n";
$php .= 'return [\'parameters\' => [\'ignoreErrors\' => $ignoreErrors]];';

$output->writeRaw($php);

return 1;
}

}

0 comments on commit 8260032

Please sign in to comment.