diff --git a/src/Composer/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilter.php b/src/Composer/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilter.php index 491ad01b9..8167fdd3e 100644 --- a/src/Composer/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilter.php +++ b/src/Composer/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilter.php @@ -20,4 +20,9 @@ final class IgnoreAllPlatformRequirementFilter implements PlatformRequirementFil { return PlatformRepository::isPlatformPackage($req); } + + public function isUpperBoundIgnored(string $req): bool + { + return $this->isIgnored($req); + } } diff --git a/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php b/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php index 43cc33469..73d536376 100644 --- a/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php +++ b/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php @@ -60,6 +60,15 @@ final class IgnoreListPlatformRequirementFilter implements PlatformRequirementFi return Preg::isMatch($this->ignoreRegex, $req); } + public function isUpperBoundIgnored(string $req): bool + { + if (!PlatformRepository::isPlatformPackage($req)) { + return false; + } + + return $this->isIgnored($req) || Preg::isMatch($this->ignoreUpperBoundRegex, $req); + } + /** * @param bool $allowUpperBoundOverride For conflicts we do not want the upper bound to be skipped */ diff --git a/src/Composer/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilter.php b/src/Composer/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilter.php index 265701824..ab225d6c9 100644 --- a/src/Composer/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilter.php +++ b/src/Composer/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilter.php @@ -21,4 +21,12 @@ final class IgnoreNothingPlatformRequirementFilter implements PlatformRequiremen { return false; } + + /** + * @return false + */ + public function isUpperBoundIgnored(string $req): bool + { + return false; + } } diff --git a/src/Composer/Filter/PlatformRequirementFilter/PlatformRequirementFilterInterface.php b/src/Composer/Filter/PlatformRequirementFilter/PlatformRequirementFilterInterface.php index af1f651c8..59e824591 100644 --- a/src/Composer/Filter/PlatformRequirementFilter/PlatformRequirementFilterInterface.php +++ b/src/Composer/Filter/PlatformRequirementFilter/PlatformRequirementFilterInterface.php @@ -15,4 +15,6 @@ namespace Composer\Filter\PlatformRequirementFilter; interface PlatformRequirementFilterInterface { public function isIgnored(string $req): bool; + + public function isUpperBoundIgnored(string $req): bool; } diff --git a/src/Composer/Package/Version/VersionSelector.php b/src/Composer/Package/Version/VersionSelector.php index 138b8fabf..0b6656816 100644 --- a/src/Composer/Package/Version/VersionSelector.php +++ b/src/Composer/Package/Version/VersionSelector.php @@ -13,6 +13,7 @@ namespace Composer\Package\Version; use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter; +use Composer\Filter\PlatformRequirementFilter\IgnoreListPlatformRequirementFilter; use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory; use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface; use Composer\IO\IOInterface; @@ -130,6 +131,13 @@ class VersionSelector // constraint satisfied, go to next require continue 2; } + if ($platformRequirementFilter instanceof IgnoreListPlatformRequirementFilter && $platformRequirementFilter->isUpperBoundIgnored($name)) { + $filteredConstraint = $platformRequirementFilter->filterConstraint($name, $link->getConstraint()); + if ($filteredConstraint->matches($providedConstraint)) { + // constraint satisfied with the upper bound ignored, go to next require + continue 2; + } + } } // constraint not satisfied diff --git a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilterTest.php b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilterTest.php index 8df56d81d..8d148ec7c 100644 --- a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilterTest.php +++ b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilterTest.php @@ -25,6 +25,7 @@ final class IgnoreAllPlatformRequirementFilterTest extends TestCase $platformRequirementFilter = new IgnoreAllPlatformRequirementFilter(); $this->assertSame($expectIgnored, $platformRequirementFilter->isIgnored($req)); + $this->assertSame($expectIgnored, $platformRequirementFilter->isUpperBoundIgnored($req)); } /** diff --git a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php index a3a588cef..5f3cc1f51 100644 --- a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php +++ b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php @@ -48,4 +48,37 @@ final class IgnoreListPlatformRequirementFilterTest extends TestCase 'list entries are not completing each other' => [['ext-', 'foo'], 'ext-foo', false], ]; } + + /** + * @dataProvider dataIsUpperBoundIgnored + * + * @param string[] $reqList + */ + public function testIsUpperBoundIgnored(array $reqList, string $req, bool $expectIgnored): void + { + $platformRequirementFilter = new IgnoreListPlatformRequirementFilter($reqList); + + $this->assertSame($expectIgnored, $platformRequirementFilter->isUpperBoundIgnored($req)); + } + + /** + * @return array + */ + public static function dataIsUpperBoundIgnored(): array + { + return [ + 'ext-json is ignored if listed and fully ignored' => [['ext-json', 'monolog/monolog'], 'ext-json', true], + 'ext-json is ignored if listed and upper bound ignored' => [['ext-json+', 'monolog/monolog'], 'ext-json', true], + 'php is not ignored if not listed' => [['ext-json+', 'monolog/monolog'], 'php', false], + 'monolog/monolog is not ignored even if listed' => [['monolog/monolog'], 'monolog/monolog', false], + 'ext-json is ignored if ext-* is listed' => [['ext-*+'], 'ext-json', true], + 'php is ignored if php* is listed' => [['ext-*+', 'php*+'], 'php', true], + 'ext-json is ignored if * is listed' => [['foo', '*+'], 'ext-json', true], + 'php is ignored if * is listed' => [['*+', 'foo'], 'php', true], + 'monolog/monolog is not ignored even if * or monolog/* are listed' => [['*+', 'monolog/*+'], 'monolog/monolog', false], + 'empty list entry does not ignore' => [[''], 'ext-foo', false], + 'empty array does not ignore' => [[], 'ext-foo', false], + 'list entries are not completing each other' => [['ext-', 'foo'], 'ext-foo', false], + ]; + } } diff --git a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php index a1baac58b..70c3fabd2 100644 --- a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php +++ b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php @@ -25,6 +25,7 @@ final class IgnoreNothingPlatformRequirementFilterTest extends TestCase $platformRequirementFilter = new IgnoreNothingPlatformRequirementFilter(); $this->assertFalse($platformRequirementFilter->isIgnored($req)); // @phpstan-ignore-line + $this->assertFalse($platformRequirementFilter->isUpperBoundIgnored($req)); // @phpstan-ignore-line } /**