diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 6269b4d8..e615422e 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -68,11 +68,17 @@ services: tags: - { name: "support_tools.system_info.collector", identifier: "ibexa" } + EzSystems\EzSupportTools\VersionStability\ComposerVersionStabilityChecker: ~ + + EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker: + '@EzSystems\EzSupportTools\VersionStability\ComposerVersionStabilityChecker' + support_tools.system_info.collector.composer.lock_file: class: "%support_tools.system_info.collector.composer.lock_file.class%" arguments: - - "%kernel.project_dir%/composer.lock" - - "%kernel.project_dir%/composer.json" + $versionStabilityChecker: '@EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker' + $lockFile: "%kernel.project_dir%/composer.lock" + $jsonFile: "%kernel.project_dir%/composer.json" tags: - { name: "support_tools.system_info.collector", identifier: "composer" } diff --git a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php index 9e89c91d..7c4de5b9 100644 --- a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php +++ b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php @@ -7,6 +7,7 @@ namespace EzSystems\EzSupportToolsBundle\SystemInfo\Collector; use EzSystems\EzPlatformCoreBundle\EzPlatformCoreBundle; +use EzSystems\EzSupportTools\Value\Stability; use EzSystems\EzSupportToolsBundle\DependencyInjection\EzSystemsEzSupportToolsExtension; use EzSystems\EzSupportToolsBundle\SystemInfo\Exception\ComposerLockFileNotFoundException; use EzSystems\EzSupportToolsBundle\SystemInfo\Value\ComposerSystemInfo; @@ -226,7 +227,7 @@ private function getEOLDate(string $ibexaRelease): ?DateTime private static function getStability(ComposerSystemInfo $composerInfo): string { - $stabilityFlags = array_flip(JsonComposerLockSystemInfoCollector::STABILITIES); + $stabilityFlags = array_flip(Stability::STABILITIES); // Root package stability $stabilityFlag = $composerInfo->minimumStability !== null ? @@ -248,7 +249,7 @@ private static function getStability(ComposerSystemInfo $composerInfo): string } } - return JsonComposerLockSystemInfoCollector::STABILITIES[$stabilityFlag]; + return Stability::STABILITIES[$stabilityFlag]; } private static function hasAnyPackage( diff --git a/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php index 0c8efdc9..c66034fa 100644 --- a/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php +++ b/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php @@ -6,6 +6,9 @@ */ namespace EzSystems\EzSupportToolsBundle\SystemInfo\Collector; +use Composer\InstalledVersions; +use EzSystems\EzSupportTools\Value\Stability; +use EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker; use EzSystems\EzSupportToolsBundle\SystemInfo\Exception; use EzSystems\EzSupportToolsBundle\SystemInfo\Value\ComposerSystemInfo; use EzSystems\EzSupportToolsBundle\SystemInfo\Value\ComposerPackage; @@ -15,18 +18,10 @@ */ class JsonComposerLockSystemInfoCollector implements SystemInfoCollector { - /** - * @var array Hash of stability constant values to human readable stabilities, see Composer\Package\BasePackage. - * - * Needed as long as we don't want to depend on Composer. - */ - public const STABILITIES = [ - 0 => 'stable', - 5 => 'RC', - 10 => 'beta', - 15 => 'alpha', - 20 => 'dev', - ]; + public const IBEXA_OSS_PACKAGE = 'ibexa/oss'; + + /** @var \EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker */ + private $versionStabilityChecker; /** * @var string Composer lock file with full path. @@ -43,8 +38,12 @@ class JsonComposerLockSystemInfoCollector implements SystemInfoCollector */ private $value; - public function __construct($lockFile, $jsonFile) - { + public function __construct( + VersionStabilityChecker $versionStabilityChecker, + $lockFile, + $jsonFile + ) { + $this->versionStabilityChecker = $versionStabilityChecker; $this->lockFile = $lockFile; $this->jsonFile = $jsonFile; } @@ -52,9 +51,9 @@ public function __construct($lockFile, $jsonFile) /** * Collects information about installed composer packages. * - * @throws Exception\ComposerLockFileNotFoundException if the composer.lock file was not found. - * * @return \EzSystems\EzSupportToolsBundle\SystemInfo\Value\ComposerSystemInfo + * + * @throws Exception\ComposerLockFileNotFoundException if the composer.lock file was not found. */ public function collect(): ComposerSystemInfo { @@ -72,11 +71,16 @@ public function collect(): ComposerSystemInfo $lockData = json_decode(file_get_contents($this->lockFile), true); $jsonData = json_decode(file_get_contents($this->jsonFile), true); + $stability = InstalledVersions::isInstalled(self::IBEXA_OSS_PACKAGE) + ? $this->versionStabilityChecker->getStability( + InstalledVersions::getVersion(self::IBEXA_OSS_PACKAGE) + ) + : $this->getMinimumStability($lockData); return $this->value = new ComposerSystemInfo([ 'packages' => $this->extractPackages($lockData), 'repositoryUrls' => $this->extractRepositoryUrls($jsonData), - 'minimumStability' => isset($lockData['minimum-stability']) ? $lockData['minimum-stability'] : null, + 'minimumStability' => $stability, ]); } @@ -106,8 +110,8 @@ private function extractPackages(array $lockData): array if (isset($lockData['stability-flags'][$package->name])) { $stabilityFlag = (int)$lockData['stability-flags'][$package->name]; - if (isset(self::STABILITIES[$stabilityFlag])) { - $package->stability = self::STABILITIES[$stabilityFlag]; + if (isset(Stability::STABILITIES[$stabilityFlag])) { + $package->stability = Stability::STABILITIES[$stabilityFlag]; } } @@ -171,4 +175,9 @@ private static function setNormalizedVersion(ComposerPackage $package): void $package->version = $version; } + + private function getMinimumStability(array $lockData): ?string + { + return $lockData['minimum-stability'] ?? null; + } } diff --git a/src/bundle/SystemInfo/Value/IbexaSystemInfo.php b/src/bundle/SystemInfo/Value/IbexaSystemInfo.php index 7b007814..642afc6c 100644 --- a/src/bundle/SystemInfo/Value/IbexaSystemInfo.php +++ b/src/bundle/SystemInfo/Value/IbexaSystemInfo.php @@ -83,14 +83,14 @@ class IbexaSystemInfo extends ValueObject implements SystemInfo /** * Lowest stability found in the installation (packages / minimumStability). * - * @var string One of {@see \EzSystems\EzSupportToolsBundle\SystemInfo\Collector\JsonComposerLockSystemInfoCollector::STABILITIES}. + * @var string One of {@see \EzSystems\EzSupportTools\Value\Stability::STABILITIES}. */ public $lowestStability; /** * @deprecated Instead use $lowestStability. * - * @var string One of {@see \EzSystems\EzSupportToolsBundle\SystemInfo\Collector\JsonComposerLockSystemInfoCollector::STABILITIES}. + * @var string One of {@see \EzSystems\EzSupportTools\Value\Stability::STABILITIES}. */ public $stability; diff --git a/src/bundle/Tests/SystemInfo/Collector/IbexaSystemInfoCollectorTest.php b/src/bundle/Tests/SystemInfo/Collector/IbexaSystemInfoCollectorTest.php index cde6575d..db20a2eb 100644 --- a/src/bundle/Tests/SystemInfo/Collector/IbexaSystemInfoCollectorTest.php +++ b/src/bundle/Tests/SystemInfo/Collector/IbexaSystemInfoCollectorTest.php @@ -9,6 +9,7 @@ namespace EzSystems\EzSupportToolsBundle\Tests\SystemInfo\Collector; use EzSystems\EzPlatformCoreBundle\EzPlatformCoreBundle; +use EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker; use EzSystems\EzSupportToolsBundle\SystemInfo\Collector\IbexaSystemInfoCollector; use EzSystems\EzSupportToolsBundle\SystemInfo\Collector\JsonComposerLockSystemInfoCollector; use EzSystems\EzSupportToolsBundle\SystemInfo\Value\IbexaSystemInfo; @@ -16,10 +17,20 @@ class IbexaSystemInfoCollectorTest extends TestCase { + /** @var \EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker|\PHPUnit\Framework\MockObject\MockObject */ + private $versionStabilityChecker; + + public function setUp(): void + { + $this->versionStabilityChecker = $this->createMock(VersionStabilityChecker::class); + } + public function testCollect(): void { $composerCollector = new JsonComposerLockSystemInfoCollector( - __DIR__ . '/_fixtures/composer.lock', __DIR__ . '/_fixtures/composer.json' + $this->versionStabilityChecker, + __DIR__ . '/_fixtures/composer.lock', + __DIR__ . '/_fixtures/composer.json' ); $systemInfoCollector = new IbexaSystemInfoCollector( diff --git a/src/bundle/Tests/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php b/src/bundle/Tests/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php index baa3d048..424946a4 100644 --- a/src/bundle/Tests/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php +++ b/src/bundle/Tests/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php @@ -6,6 +6,7 @@ */ namespace EzSystems\EzSupportToolsBundle\Tests\SystemInfo\Collector; +use EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker; use EzSystems\EzSupportToolsBundle\SystemInfo\Collector\JsonComposerLockSystemInfoCollector; use EzSystems\EzSupportToolsBundle\SystemInfo\Exception\ComposerJsonFileNotFoundException; use EzSystems\EzSupportToolsBundle\SystemInfo\Exception\ComposerLockFileNotFoundException; @@ -15,10 +16,18 @@ class JsonComposerLockSystemInfoCollectorTest extends TestCase { + /** @var \EzSystems\EzSupportTools\VersionStability\VersionStabilityChecker|\PHPUnit\Framework\MockObject\MockObject */ + private $versionStabilityChecker; + + public function setUp(): void + { + $this->versionStabilityChecker = $this->createMock(VersionStabilityChecker::class); + } + /** * @covers \EzSystems\EzSupportToolsBundle\SystemInfo\Collector\JsonComposerLockSystemInfoCollector::collect() */ - public function testCollect() + public function testCollectWithMinimumStability() { $expected = new ComposerSystemInfo([ 'packages' => [ @@ -68,7 +77,11 @@ public function testCollect() 'repositoryUrls' => ['https://updates.ez.no/bul'], ]); - $composerCollector = new JsonComposerLockSystemInfoCollector(__DIR__ . '/_fixtures/composer.lock', __DIR__ . '/_fixtures/composer.json'); + $composerCollector = new JsonComposerLockSystemInfoCollector( + $this->versionStabilityChecker, + __DIR__ . '/_fixtures/composer.lock', + __DIR__ . '/_fixtures/composer.json' + ); $value = $composerCollector->collect(); self::assertInstanceOf('EzSystems\EzSupportToolsBundle\SystemInfo\Value\ComposerSystemInfo', $value); @@ -82,7 +95,11 @@ public function testCollectLockFileNotFound() { $this->expectException(ComposerLockFileNotFoundException::class); - $composerCollectorNotFound = new JsonComposerLockSystemInfoCollector(__DIR__ . '/_fixtures/snafu.lock', __DIR__ . '/_fixtures/composer.json'); + $composerCollectorNotFound = new JsonComposerLockSystemInfoCollector( + $this->versionStabilityChecker, + __DIR__ . '/_fixtures/snafu.lock', + __DIR__ . '/_fixtures/composer.json' + ); $composerCollectorNotFound->collect(); } @@ -93,7 +110,11 @@ public function testCollectJsonFileNotFound() { $this->expectException(ComposerJsonFileNotFoundException::class); - $composerCollectorNotFound = new JsonComposerLockSystemInfoCollector(__DIR__ . '/_fixtures/composer.lock', __DIR__ . '/_fixtures/snafu.json'); + $composerCollectorNotFound = new JsonComposerLockSystemInfoCollector( + $this->versionStabilityChecker, + __DIR__ . '/_fixtures/composer.lock', + __DIR__ . '/_fixtures/snafu.json' + ); $composerCollectorNotFound->collect(); } } diff --git a/src/lib/Tests/VersionStability/VersionStabilityCheckerTest.php b/src/lib/Tests/VersionStability/VersionStabilityCheckerTest.php new file mode 100644 index 00000000..1232ba78 --- /dev/null +++ b/src/lib/Tests/VersionStability/VersionStabilityCheckerTest.php @@ -0,0 +1,101 @@ +versionStabilityChecker = new ComposerVersionStabilityChecker(); + } + + /** + * @dataProvider provideStableVersions + */ + public function testIsStableVersion(string $stableVersion): void + { + self::assertTrue( + $this->versionStabilityChecker->isStableVersion($stableVersion) + ); + } + + public function provideStableVersions(): iterable + { + yield ['1.0.0.0']; + yield ['1.1.0.0']; + yield ['2.10.5.0']; + yield ['6.1.10.10']; + yield ['15.20.100.1500']; + } + + /** + * @dataProvider provideNotStableVersions + */ + public function testIsNotStableVersion(string $notStableVersion): void + { + self::assertFalse( + $this->versionStabilityChecker->isStableVersion($notStableVersion) + ); + } + + public function provideNotStableVersions(): iterable + { + yield ['1.0.20']; + yield ['1.0.2-beta']; + yield ['1.0.2-beta1']; + yield ['1.0.2-rc']; + yield ['1.0.2-dev']; + yield ['dev-1.0.2']; + yield ['dev-master']; + yield ['dev-main']; + yield ['1.0.2.1-alpha']; + yield ['1.0']; + yield ['v1.0-rc2']; + } + + /** + * @dataProvider provideVersions + */ + public function testGetStability( + string $version, + string $expectedStability + ): void { + self::assertEquals( + $expectedStability, + $this->versionStabilityChecker->getStability($version) + ); + } + + public function provideVersions(): iterable + { + yield ['0.1.10.50', Stability::STABILITIES[0]]; + yield ['10.10.10.50', Stability::STABILITIES[0]]; + yield ['1.0.0.1-RC20', Stability::STABILITIES[5]]; + yield ['1.0.1.5-RC2', Stability::STABILITIES[5]]; + yield ['1.0.1.5-beta1', Stability::STABILITIES[10]]; + yield ['1.0.1.5-beta12', Stability::STABILITIES[10]]; + yield ['1.0.1.5-beta100', Stability::STABILITIES[10]]; + yield ['1.1000.1.5-beta1000', Stability::STABILITIES[10]]; + yield ['1.100.10.0-alpha1', Stability::STABILITIES[15]]; + yield ['1.0.0-alpha5', Stability::STABILITIES[15]]; + yield ['1.0.0-alpha51', Stability::STABILITIES[15]]; + yield ['10.10.10.50-dev', Stability::STABILITIES[20]]; + yield ['dev-master', Stability::STABILITIES[20]]; + yield ['1.0.0.1-custom', Stability::STABILITIES[20]]; + yield ['dev-master', Stability::STABILITIES[20]]; + yield ['dev-test-v1', Stability::STABILITIES[20]]; + yield ['dev-test_custom', Stability::STABILITIES[20]]; + } +} diff --git a/src/lib/Value/Stability.php b/src/lib/Value/Stability.php new file mode 100644 index 00000000..4c808b88 --- /dev/null +++ b/src/lib/Value/Stability.php @@ -0,0 +1,25 @@ + 'stable', + 5 => 'RC', + 10 => 'beta', + 15 => 'alpha', + 20 => 'dev', + ]; +} diff --git a/src/lib/VersionStability/ComposerVersionStabilityChecker.php b/src/lib/VersionStability/ComposerVersionStabilityChecker.php new file mode 100644 index 00000000..0e277405 --- /dev/null +++ b/src/lib/VersionStability/ComposerVersionStabilityChecker.php @@ -0,0 +1,45 @@ +isStableVersion($version)) { + return Stability::STABILITIES[0]; + } + + $stability = $this->getStabilityFromVersionString($version); + + return in_array($stability, Stability::STABILITIES, true) + ? $stability + : Stability::STABILITIES[20]; + } + + public function isStableVersion(string $version): bool + { + $pattern = '/^(\d+\.\d+\.\d+\.\d+)$/'; + + return (bool) preg_match($pattern, $version); + } + + private function getStabilityFromVersionString(string $version): ?string + { + return preg_match('/^(dev)-/', $version, $matches) + || preg_match('/-(\w+)\d+$/U', $version, $matches) + ? $matches[1] + : null; + } +} diff --git a/src/lib/VersionStability/VersionStabilityChecker.php b/src/lib/VersionStability/VersionStabilityChecker.php new file mode 100644 index 00000000..9386c86c --- /dev/null +++ b/src/lib/VersionStability/VersionStabilityChecker.php @@ -0,0 +1,16 @@ +