Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions src/TodoByPackageVersionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

namespace staabm\PHPStanTodoBy;

use Composer\InstalledVersions;
use Composer\Semver\Comparator;
use OutOfBoundsException;
use Composer\Semver\VersionParser;
use PhpParser\Comment;
use PhpParser\Node;
Expand Down Expand Up @@ -61,6 +60,11 @@ final class TodoByPackageVersionRule implements Rule
*/
private array $virtualPackages;

/**
* @var array{versions: array<string, array{version: string, pretty_version?: string}>}
*/
private array $installedVersions;

/**
* @param array<string, string> $virtualPackages
*/
Expand All @@ -74,9 +78,9 @@ public function __construct(
$this->errorBuilder = $errorBuilder;

// require the top level installed versions, so we don't mix it up with the one in phpstan.phar
$installedVersions = $this->workingDirectory . '/vendor/composer/InstalledVersions.php';
if (!class_exists(InstalledVersions::class, false) && is_readable($installedVersions)) {
require_once $installedVersions;
$installedVersions = $this->workingDirectory . '/vendor/composer/installed.php';
if (is_readable($installedVersions)) {
$this->installedVersions = require $installedVersions;
}
}

Expand Down Expand Up @@ -261,7 +265,7 @@ private function satisfiesInstalledPackage(string $package, string $version, Com
$versionParser = new VersionParser();

// see https://getcomposer.org/doc/07-runtime.md#installed-versions
if (!InstalledVersions::isInstalled($package)) {
if (!isset($this->installedVersions['versions'][$package])) {
return $this->errorBuilder->buildError(
$comment->getText(),
$comment->getStartLine(),
Expand All @@ -273,7 +277,10 @@ private function satisfiesInstalledPackage(string $package, string $version, Com
}

try {
return InstalledVersions::satisfies($versionParser, $package, $version);
$constraint = $versionParser->parseConstraints($version);
$provided = $versionParser->parseConstraints($this->getVersionRanges($package));

return $provided->matches($constraint);
} catch (UnexpectedValueException $e) {
return $this->errorBuilder->buildError(
$comment->getText(),
Expand All @@ -298,4 +305,27 @@ private function getVersionComparator(string $version): ?string

return $comparator;
}

public function getVersionRanges(string $packageName) : string
{
if (!isset($this->installedVersions['versions'][$packageName])) {
throw new OutOfBoundsException('Package "' . $packageName . '" is not installed');
}

$ranges = array();
if (isset($this->installedVersions['versions'][$packageName]['pretty_version'])) {
$ranges[] = $this->installedVersions['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $this->installedVersions['versions'][$packageName])) {
$ranges = array_merge($ranges, $this->installedVersions['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $this->installedVersions['versions'][$packageName])) {
$ranges = array_merge($ranges, $this->installedVersions['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $this->installedVersions['versions'][$packageName])) {
$ranges = array_merge($ranges, $this->installedVersions['versions'][$packageName]['provided']);
}

return implode(' || ', $ranges);
}
}
18 changes: 7 additions & 11 deletions tests/TodoByPackageVersionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,33 @@ public static function provideErrors(): iterable
'Unknown package "not-installed/package". It is neither installed via composer.json nor declared as virtual package via PHPStan config.',
11,
],
[
'"phpunit/phpunit" version requirement "<10" satisfied.',
14,
],
[
'"phpunit/phpunit" version requirement "<11" satisfied.',
15,
14,
],
[
'Invalid version constraint "<inValid.12" for package "phpunit/phpunit".',
17,
16,
],
[
'"php" version requirement ">7.3" satisfied: drop this code after min-version raise.',
19,
18,
],
[
'"php" version requirement ">=7" satisfied: drop this code after min-version raise.',
20,
19,
],
[
'"php" version requirement ">=7" satisfied.',
22,
21,
],
[
'"php" version requirement ">=7" satisfied.',
23,
22,
],
[
'"php" version requirement ">=7" satisfied.',
24,
23,
],
],
];
Expand Down
1 change: 0 additions & 1 deletion tests/data/packageVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// TODO: not-installed/package:<5 this should error because package is not in composer.json

// TODO: phpunit/phpunit:<9
// TODO: phpunit/phpunit:<10
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just realized after merge: next time don't delete such line but make it empty. that way you don't need unrelated changes in test expectations

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's clever

// TODO: phpunit/phpunit:<11

// TODO: phpunit/phpunit:<inValid.12
Expand Down
Loading