diff --git a/classes/Models/AutoupgradeRelease.php b/classes/Models/AutoupgradeRelease.php index 25ec2cf99..9ebbee9aa 100644 --- a/classes/Models/AutoupgradeRelease.php +++ b/classes/Models/AutoupgradeRelease.php @@ -33,6 +33,8 @@ class AutoupgradeRelease private $recommendedVersionLink; /** @var string */ private $recommendedVersionMd5; + /** @var bool */ + private $recommended; /** @var string|null */ private $recommendedVersionChangelog; @@ -42,6 +44,7 @@ public function __construct( string $recommendedVersion, string $recommendedVersionLink, string $recommendedVersionMd5, + bool $recommended, ?string $recommendedVersionChangelog ) { $this->prestashopMinVersion = $prestashopMinVersion; @@ -50,6 +53,7 @@ public function __construct( $this->recommendedVersionLink = $recommendedVersionLink; $this->recommendedVersionMd5 = $recommendedVersionMd5; $this->recommendedVersionChangelog = $recommendedVersionChangelog; + $this->recommended = $recommended; } public function getPrestashopMinVersion(): string @@ -81,4 +85,9 @@ public function getRecommendedVersionChangelog(): ?string { return $this->recommendedVersionChangelog; } + + public function isRecommended(): bool + { + return $this->recommended; + } } diff --git a/classes/Services/DistributionApiService.php b/classes/Services/DistributionApiService.php index 6b118911f..9ae2b172f 100644 --- a/classes/Services/DistributionApiService.php +++ b/classes/Services/DistributionApiService.php @@ -206,6 +206,7 @@ private function createAutoupgradeReleaseCollection(array $data): array $versionInfo['autoupgrade_recommended']['last_version'], $versionInfo['autoupgrade_recommended']['download']['link'], $versionInfo['autoupgrade_recommended']['download']['md5'], + $versionInfo['recommended'] ?? true, $versionInfo['autoupgrade_recommended']['changelog'] ?? null ); } diff --git a/classes/Services/PhpVersionResolverService.php b/classes/Services/PhpVersionResolverService.php index 6e1918b9a..82952bff9 100644 --- a/classes/Services/PhpVersionResolverService.php +++ b/classes/Services/PhpVersionResolverService.php @@ -32,7 +32,6 @@ class PhpVersionResolverService const COMPATIBILITY_VALID = 1; const COMPATIBILITY_UNKNOWN = 2; - const TEMPORARY_EXCLUDED_MAX_RECOMMENDED_VERSION = '9'; const AVAILABLE_RELEASE_MAX = 'max'; const AVAILABLE_RELEASE_RECOMMENDED = 'recommended'; @@ -150,24 +149,49 @@ public function getPrestashopDestinationReleases(int $currentPhpVersionId): arra } } - // TODO: Will be improved later to return several options (minor or patch, major) instead of the current max / recommended. - // Currently limited to PS v8 with a temporary hardcoded value. - /** @var array $release */ - $release = array_reduce($validReleases, function ($carry, $item) { - $isABetterMaxVersion = empty($carry[self::AVAILABLE_RELEASE_MAX]) || version_compare($item->getVersion(), $carry[self::AVAILABLE_RELEASE_MAX]->getVersion()) > 0; - $isABetterRecommendedVersion = empty($carry[self::AVAILABLE_RELEASE_RECOMMENDED]) || version_compare($item->getVersion(), $carry[self::AVAILABLE_RELEASE_RECOMMENDED]->getVersion()) > 0; - $isEligibleToRecommendation = version_compare($item->getVersion(), self::TEMPORARY_EXCLUDED_MAX_RECOMMENDED_VERSION, '<'); + $releaseResult = []; - if ($isABetterMaxVersion) { - $carry[self::AVAILABLE_RELEASE_MAX] = $item; + $maxRelease = null; + $recommendedRelease = null; + $fallbackRecommendedRelease = null; + + foreach ($validReleases as $releaseItem) { + // Determine max release (latest version) + if ($maxRelease === null || version_compare($releaseItem->getVersion(), $maxRelease->getVersion(), '>')) { + $maxRelease = $releaseItem; } - if ($isEligibleToRecommendation && $isABetterRecommendedVersion) { - $carry[self::AVAILABLE_RELEASE_RECOMMENDED] = $item; + + // Determine recommended release based on autoupgrade compatibilities + foreach ($autoupgradeCompatibilities as $compatibility) { + $isRecommendedRelease = $compatibility->isRecommended() + && version_compare($compatibility->getPrestashopMaxVersion(), $releaseItem->getVersion(), '>=') + && version_compare($compatibility->getPrestashopMinVersion(), $releaseItem->getVersion(), '<=') + && ($recommendedRelease === null || version_compare($releaseItem->getVersion(), $recommendedRelease->getVersion(), '>')); + + if ($isRecommendedRelease) { + $recommendedRelease = $releaseItem; + } } - return $carry; - }, []); + $updateType = VersionUtils::getUpdateType($this->currentPsVersion, $releaseItem->getVersion()); + $isMinorOrPatchUpdate = $updateType === 'minor' || $updateType === 'patch'; + + if ($isMinorOrPatchUpdate) { + $fallbackRecommendedRelease = $releaseItem; + } + } + + // Build result array only if releases are found + if ($maxRelease !== null) { + $releaseResult[self::AVAILABLE_RELEASE_MAX] = $maxRelease; + } + + if ($recommendedRelease !== null) { + $releaseResult[self::AVAILABLE_RELEASE_RECOMMENDED] = $recommendedRelease; + } elseif ($fallbackRecommendedRelease !== null) { + $releaseResult[self::AVAILABLE_RELEASE_RECOMMENDED] = $fallbackRecommendedRelease; + } - return $release; + return $releaseResult; } } diff --git a/tests/fixtures/api-distribution/autoupgrade.json b/tests/fixtures/api-distribution/autoupgrade.json index 724163d25..522ff5b89 100644 --- a/tests/fixtures/api-distribution/autoupgrade.json +++ b/tests/fixtures/api-distribution/autoupgrade.json @@ -3,6 +3,7 @@ { "prestashop_min": "1.7.0.0", "prestashop_max": "8.2.1", + "recommended": true, "autoupgrade_recommended": { "last_version": "7.0.0", "download": { @@ -12,9 +13,34 @@ "changelog": "https://build.prestashop-project.org/news/2025/autoupgrade-v7.0-release/" } }, + { + "prestashop_min": "10.0.0", + "prestashop_max": "10.0.0", + "recommended": false, + "autoupgrade_recommended": { + "last_version": "8.0.0", + "download": { + "link": "https://github.com/PrestaShop/autoupgrade/releases/download/v8.0.0/autoupgrade-v8.0.0.zip", + "md5": "48ced9086bac4f2e2266c3d20505e58c" + } + } + }, + { + "prestashop_min": "9.1.0", + "prestashop_max": "9.2.1", + "recommended": true, + "autoupgrade_recommended": { + "last_version": "7.3.0", + "download": { + "link": "https://github.com/PrestaShop/autoupgrade/releases/download/v7.3.0/autoupgrade-v7.5.0.zip", + "md5": "48ced9086bac4f2e2266c3d20505e58c" + } + } + }, { "prestashop_min": "9.0.0", - "prestashop_max": "9.0.0", + "prestashop_max": "9.0.1", + "recommended": false, "autoupgrade_recommended": { "last_version": "7.3.0", "download": { diff --git a/tests/fixtures/api-distribution/prestashop.json b/tests/fixtures/api-distribution/prestashop.json index 45971db6d..88856666d 100644 --- a/tests/fixtures/api-distribution/prestashop.json +++ b/tests/fixtures/api-distribution/prestashop.json @@ -1,4 +1,64 @@ [ + { + "version": "10.0.0", + "distribution": "classic", + "distribution_version": "1.0", + "php_max_version": "8.5", + "php_min_version": "8.3", + "zip_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/10.0.0-1.0\/prestashop.zip", + "zip_md5": "d16ad2da1f7aa07958bc678a4036632f", + "xml_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/10.0.0-1.0\/prestashop.xml", + "stability": "stable", + "release_notes_url": "https:\/\/build.prestashop-project.org\/news\/2025\/prestashop-10-0-0-available\/" + }, + { + "version": "9.2.1", + "distribution": "classic", + "distribution_version": "1.0", + "php_max_version": "8.4", + "php_min_version": "8.2", + "zip_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.2.1-1.0\/prestashop.zip", + "zip_md5": "d16ad2da1f7aa07958bc678a4036632f", + "xml_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.2.1-1.0\/prestashop.xml", + "stability": "stable", + "release_notes_url": "https:\/\/build.prestashop-project.org\/news\/2025\/prestashop-9-2-1-available\/" + }, + { + "version": "9.2.0", + "distribution": "classic", + "distribution_version": "1.0", + "php_max_version": "8.4", + "php_min_version": "8.2", + "zip_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.2.0-1.0\/prestashop.zip", + "zip_md5": "d16ad2da1f7aa07958bc678a4036632f", + "xml_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.2.0-1.0\/prestashop.xml", + "stability": "stable", + "release_notes_url": "https:\/\/build.prestashop-project.org\/news\/2025\/prestashop-9-2-0-available\/" + }, + { + "version": "9.1.0", + "distribution": "classic", + "distribution_version": "1.0", + "php_max_version": "8.4", + "php_min_version": "8.2", + "zip_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.1.0-1.0\/prestashop.zip", + "zip_md5": "d16ad2da1f7aa07958bc678a4036632f", + "xml_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.1.0-1.0\/prestashop.xml", + "stability": "stable", + "release_notes_url": "https:\/\/build.prestashop-project.org\/news\/2025\/prestashop-9-1-0-available\/" + }, + { + "version": "9.0.1", + "distribution": "classic", + "distribution_version": "1.0", + "php_max_version": "8.4", + "php_min_version": "8.1", + "zip_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.0.1-1.0\/prestashop.zip", + "zip_md5": "d16ad2da1f7aa07958bc678a4036632f", + "xml_download_url": "https:\/\/api.prestashop-project.org\/assets\/prestashop-classic\/9.0.1-1.0\/prestashop.xml", + "stability": "stable", + "release_notes_url": "https:\/\/build.prestashop-project.org\/news\/2025\/prestashop-9-0-1-available\/" + }, { "version": "9.0.0", "distribution": "classic", diff --git a/tests/unit/Services/PhpVersionResolverServiceTest.php b/tests/unit/Services/PhpVersionResolverServiceTest.php index fc37dc266..f9eee4461 100644 --- a/tests/unit/Services/PhpVersionResolverServiceTest.php +++ b/tests/unit/Services/PhpVersionResolverServiceTest.php @@ -172,29 +172,53 @@ public function prestashopDestinationReleaseProvider(): array { return [ [999999, []], + [80500, [ + 'max' => new PrestashopRelease('10.0.0', + 'stable', + 'classic', + '8.5', + '8.3', + 'https://api.prestashop-project.org/assets/prestashop-classic/10.0.0-1.0/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop-classic/10.0.0-1.0/prestashop.xml', + 'd16ad2da1f7aa07958bc678a4036632f', + 'https://build.prestashop-project.org/news/2025/prestashop-10-0-0-available/', + '1.0' + ), + ]], [80300, [ - 'max' => new PrestashopRelease('9.0.0', + 'max' => new PrestashopRelease('10.0.0', + 'stable', + 'classic', + '8.5', + '8.3', + 'https://api.prestashop-project.org/assets/prestashop-classic/10.0.0-1.0/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop-classic/10.0.0-1.0/prestashop.xml', + 'd16ad2da1f7aa07958bc678a4036632f', + 'https://build.prestashop-project.org/news/2025/prestashop-10-0-0-available/', + '1.0' + ), + 'recommended' => new PrestashopRelease('9.2.1', 'stable', 'classic', '8.4', - '8.1', - 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.0-1.0/prestashop.zip', - 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.0-1.0/prestashop.xml', + '8.2', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.2.1-1.0/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.2.1-1.0/prestashop.xml', 'd16ad2da1f7aa07958bc678a4036632f', - 'https://build.prestashop-project.org/news/2025/prestashop-9-0-available/', + 'https://build.prestashop-project.org/news/2025/prestashop-9-2-1-available/', '1.0' ), ]], [80100, [ - 'max' => new PrestashopRelease('9.0.0', + 'max' => new PrestashopRelease('9.0.1', 'stable', 'classic', '8.4', '8.1', - 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.0-1.0/prestashop.zip', - 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.0-1.0/prestashop.xml', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.xml', 'd16ad2da1f7aa07958bc678a4036632f', - 'https://build.prestashop-project.org/news/2025/prestashop-9-0-available/', + 'https://build.prestashop-project.org/news/2025/prestashop-9-0-1-available/', '1.0' ), 'recommended' => new PrestashopRelease('8.2.1', @@ -277,4 +301,104 @@ public function testValidGetPrestashopDestinationRelease($input, $expected) $this->assertEquals($expected, $this->phpVersionResolverService->getPrestashopDestinationReleases($input)); } + + /** + * @throws UpgradeException + * @throws DistributionApiException + * @throws LogicException + */ + public function testValidGetPrestashopDestinationReleaseForv9() + { + $this->phpVersionResolverService = new PhpVersionResolverService($this->distributionApiService, '9.0.0'); + + $this->distributionApiService->method('getApiEndpoint') + ->will($this->returnValueMap([ + [DistributionApiService::PRESTASHOP_ENDPOINT, json_decode(@file_get_contents(__DIR__ . '/../../fixtures/api-distribution/prestashop.json'), true)], + [DistributionApiService::AUTOUPGRADE_ENDPOINT, json_decode(@file_get_contents(__DIR__ . '/../../fixtures/api-distribution/autoupgrade.json'), true)], + ])); + + $this->assertEquals([ + 'max' => new PrestashopRelease('9.0.1', + 'stable', + 'classic', + '8.4', + '8.1', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.xml', + 'd16ad2da1f7aa07958bc678a4036632f', + 'https://build.prestashop-project.org/news/2025/prestashop-9-0-1-available/', + '1.0' + ), + 'recommended' => new PrestashopRelease('9.0.1', + 'stable', + 'classic', + '8.4', + '8.1', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.xml', + 'd16ad2da1f7aa07958bc678a4036632f', + 'https://build.prestashop-project.org/news/2025/prestashop-9-0-1-available/', + '1.0' + ), + ], $this->phpVersionResolverService->getPrestashopDestinationReleases(80100)); + } + + /** + * @throws UpgradeException + * @throws DistributionApiException + * @throws LogicException + */ + public function testValidGetPrestashopDestinationReleaseForv901() + { + $this->phpVersionResolverService = new PhpVersionResolverService($this->distributionApiService, '9.0.1'); + + $this->distributionApiService->method('getApiEndpoint') + ->will($this->returnValueMap([ + [DistributionApiService::PRESTASHOP_ENDPOINT, json_decode(@file_get_contents(__DIR__ . '/../../fixtures/api-distribution/prestashop.json'), true)], + [DistributionApiService::AUTOUPGRADE_ENDPOINT, json_decode(@file_get_contents(__DIR__ . '/../../fixtures/api-distribution/autoupgrade.json'), true)], + ])); + + $this->assertEquals([], $this->phpVersionResolverService->getPrestashopDestinationReleases(80100)); + } + + /** + * @throws UpgradeException + * @throws DistributionApiException + * @throws LogicException + */ + public function testValidGetPrestashopDestinationReleaseForv8() + { + $this->phpVersionResolverService = new PhpVersionResolverService($this->distributionApiService, '8.0.0'); + + $this->distributionApiService->method('getApiEndpoint') + ->will($this->returnValueMap([ + [DistributionApiService::PRESTASHOP_ENDPOINT, json_decode(@file_get_contents(__DIR__ . '/../../fixtures/api-distribution/prestashop.json'), true)], + [DistributionApiService::AUTOUPGRADE_ENDPOINT, json_decode(@file_get_contents(__DIR__ . '/../../fixtures/api-distribution/autoupgrade.json'), true)], + ])); + + $this->assertEquals([ + 'max' => new PrestashopRelease('9.0.1', + 'stable', + 'classic', + '8.4', + '8.1', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop-classic/9.0.1-1.0/prestashop.xml', + 'd16ad2da1f7aa07958bc678a4036632f', + 'https://build.prestashop-project.org/news/2025/prestashop-9-0-1-available/', + '1.0' + ), + 'recommended' => new PrestashopRelease('8.2.1', + 'stable', + 'open_source', + '8.1', + '7.2.5', + 'https://api.prestashop-project.org/assets/prestashop/8.2.1/prestashop.zip', + 'https://api.prestashop-project.org/assets/prestashop/8.2.1/prestashop.xml', + '513bd62a9f9ad35a723f362d88c99790', + 'https://build.prestashop-project.org/news/2025/prestashop-8-2-1-maintenance-release/', + null + ), + ], $this->phpVersionResolverService->getPrestashopDestinationReleases(80100)); + } }