diff --git a/composer.json b/composer.json index 40cc9965ebf..d8a80df72df 100644 --- a/composer.json +++ b/composer.json @@ -117,7 +117,7 @@ ], "verify-callmap": "@php phpunit tests/Internal/Codebase/InternalCallMapHandlerTest.php", "psalm": "@php ./psalm", - "psalm-set-baseline": "@php ./psalm --set-baseline=psalm-baseline.xml", + "psalm-set-baseline": "@php ./psalm --set-baseline", "tests": [ "@lint", "@cs", diff --git a/docs/running_psalm/dealing_with_code_issues.md b/docs/running_psalm/dealing_with_code_issues.md index 552dede75bc..84ac39765ee 100644 --- a/docs/running_psalm/dealing_with_code_issues.md +++ b/docs/running_psalm/dealing_with_code_issues.md @@ -95,11 +95,17 @@ If you wish to suppress all issues, you can use `@psalm-suppress all` instead of If you have a bunch of errors and you don't want to fix them all at once, Psalm can grandfather-in errors in existing code, while ensuring that new code doesn't have those same sorts of errors. +``` +vendor/bin/psalm --set-baseline +``` + +will generate a file psalm-baseline.xml containing the current errors. Alternateivly you can specify the name of your baseline file. + ``` vendor/bin/psalm --set-baseline=your-baseline.xml ``` -will generate a file containing the current errors. You should commit that generated file so that Psalm can use it when running in other places (e.g. CI). It won't complain about those errors either. +You should commit that generated file so that Psalm can use it when running in other places (e.g. CI). It won't complain about those errors either. You have two options to use the generated baseline when running psalm: diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index a4d4fe35e24..0cc094b5049 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -130,10 +130,11 @@ class Config { private const DEFAULT_FILE_NAME = 'psalm.xml'; - public const CONFIG_NAMESPACE = 'https://getpsalm.org/schema/config'; - public const REPORT_INFO = 'info'; - public const REPORT_ERROR = 'error'; - public const REPORT_SUPPRESS = 'suppress'; + final public const DEFAULT_BASELINE_NAME = 'psalm-baseline.xml'; + final public const CONFIG_NAMESPACE = 'https://getpsalm.org/schema/config'; + final public const REPORT_INFO = 'info'; + final public const REPORT_ERROR = 'error'; + final public const REPORT_SUPPRESS = 'suppress'; /** * @var array diff --git a/src/Psalm/Internal/Cli/Psalm.php b/src/Psalm/Internal/Cli/Psalm.php index 5aacced0f61..80ab5ffc8ad 100644 --- a/src/Psalm/Internal/Cli/Psalm.php +++ b/src/Psalm/Internal/Cli/Psalm.php @@ -131,7 +131,7 @@ final class Psalm 'report:', 'report-show-info:', 'root:', - 'set-baseline:', + 'set-baseline::', 'show-info:', 'show-snippet:', 'stats', @@ -271,7 +271,6 @@ public static function run(array $argv): void $config->debug_emitted_issues = true; } - setlocale(LC_CTYPE, 'C'); if (isset($options['set-baseline'])) { @@ -639,7 +638,7 @@ private static function initProviders(array $options, Config $config, string $cu } /** - * @param array{"set-baseline": string, ...} $options + * @param array{"set-baseline": mixed, ...} $options * @return array}>> */ private static function generateBaseline( @@ -650,10 +649,13 @@ private static function generateBaseline( ): array { fwrite(STDERR, 'Writing error baseline to file...' . PHP_EOL); + $errorBaseline = ((string) $options['set-baseline']) + ?: $config->error_baseline ?: Config::DEFAULT_BASELINE_NAME; + try { $issue_baseline = ErrorBaseline::read( new FileProvider, - $options['set-baseline'], + $errorBaseline, ); } catch (ConfigException $e) { $issue_baseline = []; @@ -661,18 +663,20 @@ private static function generateBaseline( ErrorBaseline::create( new FileProvider, - $options['set-baseline'], + $errorBaseline, IssueBuffer::getIssuesData(), $config->include_php_versions_in_error_baseline || isset($options['include-php-versions']), ); - fwrite(STDERR, "Baseline saved to {$options['set-baseline']}."); + fwrite(STDERR, "Baseline saved to $errorBaseline."); - CliUtils::updateConfigFile( - $config, - $path_to_config ?? $current_dir, - $options['set-baseline'], - ); + if ($errorBaseline !== $config->error_baseline) { + CliUtils::updateConfigFile( + $config, + $path_to_config ?? $current_dir, + $errorBaseline, + ); + } fwrite(STDERR, PHP_EOL); @@ -1033,7 +1037,7 @@ private static function initBaseline( ): array { $issue_baseline = []; - if (isset($options['set-baseline']) && is_string($options['set-baseline'])) { + if (isset($options['set-baseline'])) { if ($paths_to_check !== null) { fwrite(STDERR, PHP_EOL . 'Cannot generate baseline when checking specific files' . PHP_EOL); exit(1); @@ -1307,11 +1311,13 @@ private static function getHelpText(): string Output the taint graph using the DOT language – requires --taint-analysis Issue baselines: - --set-baseline=PATH + --set-baseline[=PATH] Save all current error level issues to a file, to mark them as info in subsequent runs Add --include-php-versions to also include a list of PHP extension versions + Default value is `psalm-baseline.xml` + --use-baseline=PATH Allows you to use a baseline other than the default baseline provided in your config diff --git a/tests/EndToEnd/PsalmEndToEndTest.php b/tests/EndToEnd/PsalmEndToEndTest.php index bdbb2cb1a0e..724f21396e6 100644 --- a/tests/EndToEnd/PsalmEndToEndTest.php +++ b/tests/EndToEnd/PsalmEndToEndTest.php @@ -190,6 +190,22 @@ public function testTainting(): void $this->assertSame(2, $result['CODE']); } + public function testPsalmSetBaseline(): void + { + $this->runPsalmInit(1); + $this->runPsalm(['--set-baseline'], self::$tmpDir, true); + + $this->assertSame(0, $this->runPsalm([], self::$tmpDir)['CODE']); + } + + public function testPsalmSetBaselineWithArgument(): void + { + $this->runPsalmInit(1); + $this->runPsalm(['--set-baseline=psalm-custom-baseline.xml'], self::$tmpDir, true); + + $this->assertSame(0, $this->runPsalm([], self::$tmpDir)['CODE']); + } + public function testTaintingWithoutInit(): void { $result = $this->runPsalm(['--taint-analysis'], self::$tmpDir, true, false); @@ -206,7 +222,7 @@ public function testTaintGraphDumping(): void $result = $this->runPsalm( [ '--taint-analysis', - '--dump-taint-graph='.self::$tmpDir.'/taints.dot', + '--dump-taint-graph=' . self::$tmpDir . '/taints.dot', ], self::$tmpDir, true, @@ -215,7 +231,7 @@ public function testTaintGraphDumping(): void $this->assertSame(2, $result['CODE']); $this->assertFileEquals( __DIR__ . '/../fixtures/expected_taint_graph.dot', - self::$tmpDir.'/taints.dot', + self::$tmpDir . '/taints.dot', ); } @@ -257,7 +273,7 @@ private function runPsalmInit(?int $level = null, ?string $php_version = null): if ($level) { $args[] = 'src'; - $args[] = (string) $level; + $args[] = (string)$level; } $ret = $this->runPsalm($args, self::$tmpDir, false, false);