diff --git a/src/Composer/VersionComparator.php b/src/Composer/VersionComparator.php index a780054..8acac16 100644 --- a/src/Composer/VersionComparator.php +++ b/src/Composer/VersionComparator.php @@ -14,4 +14,23 @@ public static function areAndMinorVersionsEqual(string $firstVersion, string $se // if major and minor are equal, we can skip the update return $firstMajor === $secondMajor && $firstMinor === $secondMinor; } + + public static function areVersionsEqual(string $firstVersion, string $secondVersion): bool + { + return self::normalizeVersion($firstVersion) === self::normalizeVersion($secondVersion); + } + + /** + * Make versions comparable, e.g. "v2.3" and "2.3.0" are the same version + */ + private static function normalizeVersion(string $version): string + { + $version = ltrim($version, 'v'); + + while (preg_match('#^\d+(\.\d+)?$#', $version) === 1) { + $version .= '.0'; + } + + return $version; + } } diff --git a/src/OutdatedComposerFactory.php b/src/OutdatedComposerFactory.php index 02d0e54..bd31ab4 100644 --- a/src/OutdatedComposerFactory.php +++ b/src/OutdatedComposerFactory.php @@ -4,6 +4,7 @@ namespace Rector\Jack; +use Rector\Jack\Composer\VersionComparator; use Rector\Jack\Mapper\OutdatedPackageMapper; use Rector\Jack\ValueObject\OutdatedComposer; use Rector\Jack\ValueObject\OutdatedPackage; @@ -26,9 +27,14 @@ public function createOutdatedComposer(array $installedPackages, string $compose $outdatedPackages = $this->outdatedPackageMapper->mapToObjects($installedPackages, $composerJsonFilePath); // filter out dev packages, those are silently added, when "minimum-stability" is set to "dev" + // filter out false positives, where the latest version is the same as the current one $nonDevOutdatedPackages = array_filter( $outdatedPackages, fn (OutdatedPackage $outdatedPackage): bool => ! $outdatedPackage->lastestIsDevBranch() + && ! VersionComparator::areVersionsEqual( + $outdatedPackage->getCurrentVersion(), + $outdatedPackage->getLatestVersion() + ) ); return new OutdatedComposer($nonDevOutdatedPackages); diff --git a/tests/OutdatedComposerFactory/Fixture/some-composer.json b/tests/OutdatedComposerFactory/Fixture/some-composer.json index 96aa4e1..cedf39b 100644 --- a/tests/OutdatedComposerFactory/Fixture/some-composer.json +++ b/tests/OutdatedComposerFactory/Fixture/some-composer.json @@ -1,6 +1,7 @@ { "name": "some/project", "require": { - "symfony/console": "^3.5" + "symfony/console": "^3.5", + "phpecs/phpecs": "^2.3" } } diff --git a/tests/OutdatedComposerFactory/OutdatedComposerFactoryTest.php b/tests/OutdatedComposerFactory/OutdatedComposerFactoryTest.php index 52f933f..a49a625 100644 --- a/tests/OutdatedComposerFactory/OutdatedComposerFactoryTest.php +++ b/tests/OutdatedComposerFactory/OutdatedComposerFactoryTest.php @@ -36,4 +36,28 @@ public function test(): void $this->assertCount(0, $outdatedComposer->getDevPackages()); } + + public function testSkipsPackageWithSameCurrentAndLatestVersion(): void + { + $outdatedComposerFactory = $this->make(OutdatedComposerFactory::class); + + $outdatedComposer = $outdatedComposerFactory->createOutdatedComposer([ + [ + 'name' => 'phpecs/phpecs', + 'direct-dependency' => true, + 'homepage' => 'https://github.com/easy-coding-standard/easy-coding-standard', + 'source' => 'https://github.com/easy-coding-standard/easy-coding-standard/tree/2.3.0', + 'version' => '2.3.0', + 'release-age' => '5 months old', + 'release-date' => '2026-01-12T10:00:00+00:00', + 'latest' => '2.3', + 'latest-status' => 'update-possible', + 'latest-release-date' => '2026-01-12T10:00:00+00:00', + 'description' => 'Use coding standard fixers and sniffs with 0-knowledge', + 'abandoned' => false, + ], + ], __DIR__ . '/Fixture/some-composer.json'); + + $this->assertCount(0, $outdatedComposer->getPackages()); + } }