diff --git a/src/actions/install.ps1 b/src/actions/install.ps1 index 6471833..04bd156 100644 --- a/src/actions/install.ps1 +++ b/src/actions/install.ps1 @@ -1,4 +1,59 @@ +function Get-Latest-PHP-Version { + param ($arch = $null, $buildType = $null) + + try { + $urls = Get-Source-Urls + $allVersions = @() + + foreach ($key in $urls.Keys) { + $url = $urls[$key] + try { + $html = Invoke-WebRequest -Uri $url + $links = $html.Links + + $filteredLinks = $links | Where-Object { + $_.href -match "php-\d+(\.\d+)*-(?:nts-)?win.*\.zip$" -and + $_.href -notmatch "php-debug" -and + $_.href -notmatch "php-devel" + } + + $filteredLinks | ForEach-Object { + $version = $_.href -replace '/downloads/releases/archives/|/downloads/releases/|php-|-nts|-Win.*|.zip', '' + $fileName = $_.href -split "/" + $fileName = $fileName[$fileName.Count - 1] + $allVersions += @{ + href = $_.href + version = $version + fileName = $fileName + BuildType = if ($fileName -match 'nts') { 'NTS' } else { 'TS' } + arch = ($fileName -replace '.*\b(x64|x86)\b.*', '$1') + } + } + } catch { + continue + } + } + + if ($arch) { + $allVersions = $allVersions | Where-Object { $_.arch -eq $arch } + } + if ($buildType) { + $allVersions = $allVersions | Where-Object { $_.BuildType -eq $buildType } + } + + # Sort by version number (descending) and return the first one + $latest = $allVersions | Sort-Object { [version]$_.version } -Descending | Select-Object -First 1 + + return $latest + } catch { + $logged = Log-Data -data @{ + header = "$($MyInvocation.MyCommand.Name) - Failed to get latest PHP version" + exception = $_ + } + return $null + } +} function Get-PHP-Versions-From-Url { param ($url, $version) diff --git a/src/core/router.ps1 b/src/core/router.ps1 index 877a45e..5fb5ec4 100644 --- a/src/core/router.ps1 +++ b/src/core/router.ps1 @@ -63,6 +63,8 @@ function Invoke-PVMInstall { param($arguments) $version = $arguments[0] + $arch = Resolve-Arch -arguments $arguments + $buildType = Resolve-BuildType -arguments $arguments if ($version -eq 'auto') { $result = Auto-Select-PHP-Version @@ -74,6 +76,15 @@ function Invoke-PVMInstall { } $version = $result.version + } elseif ($version -eq 'latest') { + $latestVersion = Get-Latest-PHP-Version -arch $arch -buildType $buildType + if (-not $latestVersion) { + Write-Host "`nFailed to find the latest PHP version" + return -1 + } + + $version = $latestVersion.version + Write-Host "`nLatest available PHP version is $version" } if (-not $version) { @@ -81,9 +92,6 @@ function Invoke-PVMInstall { return -1 } - $arch = Resolve-Arch -arguments $arguments - $buildType = Resolve-BuildType -arguments $arguments - $result = Install-PHP -version $version -arch $arch -buildType $buildType Display-Msg-By-ExitCode -result $result return 0 diff --git a/tests/install.tests.ps1 b/tests/install.tests.ps1 index 6efbb72..9f0163c 100644 --- a/tests/install.tests.ps1 +++ b/tests/install.tests.ps1 @@ -276,6 +276,67 @@ Describe "Get-Source-Urls Tests" { } } +Describe "Get-Latest-PHP-Version Tests" -tag i { + BeforeEach { + Reset-MockState + Mock Write-Host {} + } + + It "Should return the latest available version" { + $mockLinks = @( + @{ href = "/downloads/releases/php-8.0.10-Win32-vs16-x64.zip" }, + @{ href = "/downloads/releases/php-8.1.12-Win32-vs16-x64.zip" }, + @{ href = "/downloads/releases/php-8.2.1-Win32-vs16-x64.zip" }, + @{ href = "/downloads/releases/php-8.1.15-nts-Win32-vs16-x64.zip" } + ) + + Set-MockWebResponse -url $PHP_WIN_ARCHIVES_URL -links $mockLinks + Set-MockWebResponse -url $PHP_WIN_RELEASES_URL -links $mockLinks + + $result = Get-Latest-PHP-Version + + $result | Should -Not -BeNullOrEmpty + $result.version | Should -Be "8.2.1" + $result.arch | Should -Be "x64" + $result.BuildType | Should -Be "TS" + } + + It "Should filter by architecture and build type" { + $mockLinks = @( + @{ href = "/downloads/releases/php-8.3.0-Win32-vs16-x64.zip" }, + @{ href = "/downloads/releases/php-8.3.1-nts-Win32-vs16-x64.zip" }, + @{ href = "/downloads/releases/php-8.3.2-Win32-vs16-x86.zip" }, + @{ href = "/downloads/releases/php-8.3.3-nts-Win32-vs16-x86.zip" } + ) + + Set-MockWebResponse -url $PHP_WIN_ARCHIVES_URL -links $mockLinks + Set-MockWebResponse -url $PHP_WIN_RELEASES_URL -links $mockLinks + + $result = Get-Latest-PHP-Version -arch "x86" -buildType "NTS" + + $result | Should -Not -BeNullOrEmpty + $result.version | Should -Be "8.3.3" + $result.arch | Should -Be "x86" + $result.BuildType | Should -Be "NTS" + } + + It "Should return null when no versions are available" { + Set-MockWebResponse -url $PHP_WIN_ARCHIVES_URL -links @() + Set-MockWebResponse -url $PHP_WIN_RELEASES_URL -links @() + + $result = Get-Latest-PHP-Version + + $result | Should -BeNullOrEmpty + } + + It "Should handle exception gracefully" { + Mock Get-Source-Urls { throw 'Error' } + + $result = Get-Latest-PHP-Version + + $result | Should -BeNullOrEmpty + } +} Describe "Get-PHP-Versions-From-Url Tests" { BeforeEach { diff --git a/tests/router.tests.ps1 b/tests/router.tests.ps1 index acf2244..3419c1d 100644 --- a/tests/router.tests.ps1 +++ b/tests/router.tests.ps1 @@ -176,6 +176,27 @@ Describe "Invoke-PVMInstall Tests" { } } + It "Should install latest PHP version when 'latest' argument is provided" { + $arguments = @("latest") + Mock Get-Latest-PHP-Version { return @{version = "8.6.0"} } + + $result = Invoke-PVMInstall -arguments $arguments + $result | Should -Be 0 + + Assert-MockCalled Install-PHP -Times 1 -ParameterFilter { + $version -eq "8.6.0" + } + } + + It "Should return -1 when no latest PHP version was found" { + $arguments = @("latest") + Mock Get-Latest-PHP-Version { return $null } + + $result = Invoke-PVMInstall -arguments $arguments + + $result | Should -Be -1 + } + It "Should return -1 when detected PHP version is already installed" { $arguments = @("auto") Mock Auto-Select-PHP-Version { return @{ code = 0; version = "8.2" } }