Skip to content

Commit

Permalink
Change PHPStan configuration
Browse files Browse the repository at this point in the history
* Remove "Just-in-Time" configuration
* Add dynamic configuration
  • Loading branch information
rdss-sknott committed Jun 20, 2024
1 parent 2fbe969 commit c91a0c2
Show file tree
Hide file tree
Showing 24 changed files with 422 additions and 356 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,4 @@ jobs:
- name: Check infections
if: ${{ matrix.composer_parameters == '--prefer-stable' }}
run: |
composer infection
composer ci
18 changes: 14 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,23 @@
"scripts": {
"post-update-cmd": "npm update",
"post-install-cmd": "npm install",
"ci": [
"@test-prepare",
"@test",
"@infection-command"
],
"test-mkdirs": "mkdir -p tmp/phpunit",
"test-paratest-command": "paratest -p$(getconf _NPROCESSORS_ONLN)",
"test-prepare": "mkdir -p tmp/phpunit",
"test": [
"mkdir -p tmp/phpunit",
"paratest -p$(getconf _NPROCESSORS_ONLN)"
"@test-prepare",
"@test-paratest-command"
],
"infection-command": "infection -n --threads=$(getconf _NPROCESSORS_ONLN) --skip-initial-tests --coverage=tmp/phpunit --no-progress",
"infection": [
"@test",
"infection -n --threads=$(getconf _NPROCESSORS_ONLN) --skip-initial-tests --coverage=tmp/phpunit --no-progress"
"@test-prepare",
"@test --testsuite=InfectionRelevant",
"@infection-command"
]
},
"config": {
Expand Down
25 changes: 25 additions & 0 deletions config/phpstan/phpstan.config.drop.in.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

use Zooroyal\CodingStandard\CommandLine\ApplicationLifeCycle\ContainerFactory;
use Zooroyal\CodingStandard\CommandLine\StaticCodeAnalysis\PHPStan\PHPStanConfigGenerator;

$autoloadFiles = [
__DIR__ . '/../../../../autoload.php',
__DIR__ . '/../../vendor/autoload.php',
];

foreach ($autoloadFiles as $autoloadFile) {
if (file_exists($autoloadFile)) {
require_once $autoloadFile;
break;
}
}
$config = ContainerFactory::getContainerInstance()
->get(PHPStanConfigGenerator::class)
->addDynamicConfigValues([]);

echo 'Coding-Standard config loaded!' . PHP_EOL;

return $config;
13 changes: 0 additions & 13 deletions config/phpstan/phpstan.neon.dist

This file was deleted.

14 changes: 12 additions & 2 deletions infection.json.dist
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"timeout": 20,
"minMsi": 86,
"minMsi": 88,
"minCoveredMsi": 94,
"source": {
"directories": [
Expand All @@ -16,6 +16,16 @@
"github": true
},
"mutators": {
"@default": true
"@default": true,
"DecrementInteger": {
"ignoreSourceCodeByRegex": [
".*json_decode\\([^,\\\\)]+, (true|false), 512[^\\\\)]*\\).*"
]
},
"IncrementInteger": {
"ignoreSourceCodeByRegex": [
".*json_decode\\([^,\\\\)]+, (true|false), 512[^\\\\)]*\\).*"
]
}
}
}
6 changes: 5 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@
<testsuites>
<testsuite name="AllUnitTests">
<directory>./tests/Unit/</directory>
<exclude>./tests/Functional/Plugin/Fixtures/ComposerTest/vendor*</exclude>
</testsuite>
<testsuite name="AllFunctionalTests">
<directory>./tests/Functional/</directory>
<exclude>./tests/Functional/Plugin/Fixtures/ComposerTest/vendor*</exclude>
</testsuite>
<testsuite name="InfectionRelevant">
<directory>./tests/Unit/</directory>
<directory>./tests/Functional/</directory>
<exclude>./tests/Functional/Plugin/Fixtures/ComposerTest/vendor*</exclude>
</testsuite>
<testsuite name="AllSystemTests">
<directory>./tests/System/</directory>
</testsuite>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,37 @@

namespace Zooroyal\CodingStandard\CommandLine\StaticCodeAnalysis\Generic\TerminalCommand\PhpVersion;

use JsonException;
use Safe\Exceptions\FilesystemException;
use Zooroyal\CodingStandard\CommandLine\EnhancedFileInfo\EnhancedFileInfoFactory;
use Zooroyal\CodingStandard\CommandLine\EnhancedFileInfo\EnhancedFileInfo;
use Zooroyal\CodingStandard\CommandLine\Environment\Environment;
use Zooroyal\CodingStandard\CommandLine\FileSearch\FileSearchInterface;

use function Safe\file_get_contents;

class ComposerInterpreter
{
private const SEARCH_DEPTH_MIN = 1;
private const SEARCH_DEPTH_MAX = 4;

private ?string $cachedMinimalViablePhpVersion = null;
private string $cachedMinimalRootPackagePhpVersion;

public function __construct(
private readonly Environment $environment,
private readonly EnhancedFileInfoFactory $enhancedFileInfoFactory,
private readonly ConstraintToVersionConverter $constraintToVersionConverter,
private readonly FileSearchInterface $fileSearch,
) {
}

/**
* Get local php-version-constraints from root composer.json.
*
* @throws FilesystemException
* @throws JsonException
* Reads the php version constraint from the root composer.json. Does not look at PHP version constraints in
* dependencies.
*/
public function getLocalPhpVersionConstraint(): string
private function readConstraintFromRootComposerFile(): string
{
$rootDirectory = $this->environment->getRootDirectory();
$path = $rootDirectory->getRealPath();
$composerFile = $this->enhancedFileInfoFactory->buildFromPath($path . '/composer.json');
$composerConfig = json_decode(
file_get_contents($composerFile->getRealPath()),
file_get_contents($path . '/composer.json'),
associative: true,
flags: JSON_THROW_ON_ERROR,
);
Expand All @@ -41,9 +43,77 @@ public function getLocalPhpVersionConstraint(): string
?? $composerConfig['require']['php']
?? '*';

$phpVersionConstraintExtracted = $this->constraintToVersionConverter
return $phpVersionConstraint;
}

/**
* Get local php-version-constraints from root composer.json.
*/
public function getMinimalRootPackagePhpVersion(): string
{
if (isset($this->cachedMinimalRootPackagePhpVersion)) {
return $this->cachedMinimalRootPackagePhpVersion;
}

$phpVersionConstraint = $this->readConstraintFromRootComposerFile();
$this->cachedMinimalRootPackagePhpVersion = $this->constraintToVersionConverter
->extractActualPhpVersion($phpVersionConstraint);

return $phpVersionConstraintExtracted;
return $this->cachedMinimalRootPackagePhpVersion;
}

/**
* Get the minimal viable PHP version from all composer files in the project. This is the lowest common PHP version
* and our best guess for the minimal PHP version required to run the project.
*/
public function getMinimalViablePhpVersion(): string
{
if ($this->cachedMinimalViablePhpVersion === null) {
$composerFiles = $this->gatherComposerFiles();
$this->cachedMinimalViablePhpVersion = $this->searchMinimalViablePhpVersion($composerFiles);
}

return $this->cachedMinimalViablePhpVersion;
}

/**
* Finds all composer files in the project.
*
* @return array<EnhancedFileInfo>
*/
private function gatherComposerFiles(): array
{
$rootDirectory = $this->environment->getRootDirectory();

$foundComposerFiles = $this->fileSearch->listFolderFiles(
fileName: 'composer.json',
path: $rootDirectory,
minDepth: self::SEARCH_DEPTH_MIN,
maxDepth: self::SEARCH_DEPTH_MAX,
);

return $foundComposerFiles;
}

/**
* Combines Constraints of given composer files and returns the lowest possible php version.
*
* @param array<EnhancedFileInfo> $composerFiles
*/
private function searchMinimalViablePhpVersion(array $composerFiles): string
{
$minimalViablePhpVersion = $this->getMinimalRootPackagePhpVersion();

foreach ($composerFiles as $composerFile) {
$contents = file_get_contents($composerFile->getRealPath());
$composerConfig = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);

$phpVersionConstraint = $composerConfig['require']['php'] ?? '*';
$minPhpVersionPackage = $this->constraintToVersionConverter->extractActualPhpVersion($phpVersionConstraint);
$minimalViablePhpVersion = version_compare($minimalViablePhpVersion, $minPhpVersionPackage, '<')
? $minPhpVersionPackage
: $minimalViablePhpVersion;
}
return $minimalViablePhpVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function __construct()
'7.4.' => '33',
'8.0.' => '30',
'8.1.' => '28',
'8.2.' => (explode('.', phpversion()))[2],
'8.2.' => '19',
];

foreach ($phpVersionRanges as $phpVersionString => $phpMaxPatchVersion) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@

class MinimalVersionDecorator extends TerminalCommandDecorator
{
private ?string $cachedMinPhpVersion = null;

public function __construct(
private readonly ConstraintToVersionConverter $constraintToVersionConverter,
private readonly ComposerInterpreter $composerInterpreter,
) {
public function __construct(private readonly ComposerInterpreter $composerInterpreter)
{
}

public function decorate(DecorateEvent $event): void
Expand All @@ -26,17 +22,11 @@ public function decorate(DecorateEvent $event): void
return;
}

if ($this->cachedMinPhpVersion === null) {
$phpVersionConstraint = $this->composerInterpreter->getLocalPhpVersionConstraint();

$this->cachedMinPhpVersion = $this->constraintToVersionConverter
->extractActualPhpVersion($phpVersionConstraint);
}

$terminalCommand->setMinimalPhpVersion($this->cachedMinPhpVersion);
$minimalPhpVersion = $this->composerInterpreter->getMinimalRootPackagePhpVersion();
$terminalCommand->setMinimalPhpVersion($minimalPhpVersion);

$event->getOutput()->writeln(
'<info>Targeted minimal PHP version is ' . $this->cachedMinPhpVersion . '</info>' . PHP_EOL,
'<info>Targeted minimal PHP version is ' . $minimalPhpVersion . '</info>' . PHP_EOL,
OutputInterface::VERBOSITY_VERBOSE,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,12 @@
namespace Zooroyal\CodingStandard\CommandLine\StaticCodeAnalysis\Generic\TerminalCommand\PhpVersion;

use Symfony\Component\Console\Output\OutputInterface;
use Zooroyal\CodingStandard\CommandLine\EnhancedFileInfo\EnhancedFileInfo;
use Zooroyal\CodingStandard\CommandLine\Environment\Environment;
use Zooroyal\CodingStandard\CommandLine\FileSearch\FileSearchInterface;
use Zooroyal\CodingStandard\CommandLine\StaticCodeAnalysis\Generic\TerminalCommand\DecorateEvent;
use Zooroyal\CodingStandard\CommandLine\StaticCodeAnalysis\Generic\TerminalCommand\TerminalCommandDecorator;

use function Safe\file_get_contents;

class VersionDecorator extends TerminalCommandDecorator
{
private ?string $cachedMinPhpVersion = null;

public function __construct(
private readonly Environment $environment,
private readonly FileSearchInterface $fileSearchInterface,
private readonly ConstraintToVersionConverter $constraintToVersionConverter,
private readonly ComposerInterpreter $composerInterpreter,
) {
}
Expand All @@ -33,58 +23,12 @@ public function decorate(DecorateEvent $event): void
return;
}

if ($this->cachedMinPhpVersion === null) {
$composerFiles = $this->gatherComposerFiles();
$this->cachedMinPhpVersion = $this->searchMinimalViablePhpVersion($composerFiles);
}

$terminalCommand->setPhpVersion($this->cachedMinPhpVersion);
$phpVersion = $this->composerInterpreter->getMinimalViablePhpVersion();
$terminalCommand->setPhpVersion($phpVersion);

$event->getOutput()->writeln(
'<info>Targeted PHP version is ' . $this->cachedMinPhpVersion . '</info>' . PHP_EOL,
'<info>Targeted PHP version is ' . $phpVersion . '</info>' . PHP_EOL,
OutputInterface::VERBOSITY_VERBOSE,
);
}

/**
* Finds all composer files in the project.
*
* @return array<EnhancedFileInfo>
*/
private function gatherComposerFiles(): array
{
$rootDirectory = $this->environment->getRootDirectory();

$foundComposerFiles = $this->fileSearchInterface->listFolderFiles(
fileName: 'composer.json',
path: $rootDirectory,
minDepth: 1,
maxDepth: 4,
);

return $foundComposerFiles;
}

/**
* Combines Constraints of given composer files and returns the lowest possible php version.
*
* @param array<EnhancedFileInfo> $composerFiles
*/
private function searchMinimalViablePhpVersion(array $composerFiles): string
{
$minPhpVersion = $this->composerInterpreter->getLocalPhpVersionConstraint();

foreach ($composerFiles as $composerFile) {
$contents = file_get_contents($composerFile->getRealPath());
$composerConfig = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);

$phpVersionConstraint = $composerConfig['require']['php'] ?? '*';

$minPhpVersionPackage = $this->constraintToVersionConverter->extractActualPhpVersion($phpVersionConstraint);
$minPhpVersion = version_compare($minPhpVersion, $minPhpVersionPackage, '<')
? $minPhpVersionPackage
: $minPhpVersion;
}
return $minPhpVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function decorate(DecorateEvent $event): void
$output = $event->getOutput();

if ($input->getOption('verbose') === true) {
$terminalCommand->addVerbosityLevel(OutputInterface::VERBOSITY_VERBOSE);
$terminalCommand->addVerbosityLevel($output->getVerbosity());
$output->writeln(
'<info>Command will be executed verbosely</info>' . PHP_EOL,
OutputInterface::VERBOSITY_VERBOSE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@

class PHPStanCommand extends TargetableToolsCommand
{
public const EXCLUSION_LIST_TOKEN = '.dontStanPHP';

/** @var string string */
protected string $exclusionListToken = '.dontStanPHP';
protected string $exclusionListToken = self::EXCLUSION_LIST_TOKEN;
/** @var array<string> */
protected array $allowedFileEndings = ['.php'];

Expand Down
Loading

0 comments on commit c91a0c2

Please sign in to comment.