diff --git a/bin/checkver.ps1 b/bin/checkver.ps1 index 660971ab8f..ea4a92cac6 100644 --- a/bin/checkver.ps1 +++ b/bin/checkver.ps1 @@ -292,7 +292,7 @@ while ($in_progress -gt 0) { Write-Host $ver -ForegroundColor DarkRed -NoNewline Write-Host " (scoop version is $expected_ver)" -NoNewline - $update_available = (compare_versions $expected_ver $ver) -eq -1 + $update_available = (Compare-Version -ReferenceVersion $ver -DifferenceVersion $expected_ver) -ne 0 if ($json.autoupdate -and $update_available) { Write-Host ' autoupdate available' -ForegroundColor Cyan diff --git a/bin/uninstall.ps1 b/bin/uninstall.ps1 index 59bd9718b1..c97762724d 100644 --- a/bin/uninstall.ps1 +++ b/bin/uninstall.ps1 @@ -34,7 +34,7 @@ $errors = $false # Uninstall given app function do_uninstall($app, $global) { - $version = current_version $app $global + $version = Select-CurrentVersion -AppName $app -Global:$global $dir = versiondir $app $version $global $manifest = installed_manifest $app $version $global $install = install_info $app $version $global diff --git a/lib/core.ps1 b/lib/core.ps1 index 182144a2d5..c67970258f 100644 --- a/lib/core.ps1 +++ b/lib/core.ps1 @@ -290,7 +290,7 @@ function Test-Aria2Enabled { function app_status($app, $global) { $status = @{} $status.installed = (installed $app $global) - $status.version = current_version $app $global + $status.version = Select-CurrentVersion -AppName $app -Global:$global $status.latest_version = $status.version $install_info = install_info $app $status.version $global @@ -300,13 +300,17 @@ function app_status($app, $global) { $manifest = manifest $app $install_info.bucket $install_info.url $status.removed = (!$manifest) - if($manifest.version) { + if ($manifest.version) { $status.latest_version = $manifest.version } $status.outdated = $false - if($status.version -and $status.latest_version) { - $status.outdated = ((compare_versions $status.latest_version $status.version) -gt 0) + if ($status.version -and $status.latest_version) { + if (get_config 'force-update' $false) { + $status.outdated = ((Compare-Version -ReferenceVersion $status.version -DifferenceVersion $status.latest_version) -ne 0) + } else { + $status.outdated = ((Compare-Version -ReferenceVersion $status.version -DifferenceVersion $status.latest_version) -gt 0) + } } $status.missing_deps = @() @@ -314,8 +318,8 @@ function app_status($app, $global) { $app, $bucket, $null = parse_app $_ return !(installed $app) } - if($deps) { - $status.missing_deps += ,$deps + if ($deps) { + $status.missing_deps += , $deps } return $status diff --git a/lib/versions.ps1 b/lib/versions.ps1 index 4f55e653e7..a3a1309ca1 100644 --- a/lib/versions.ps1 +++ b/lib/versions.ps1 @@ -1,53 +1,274 @@ # versions -function latest_version($app, $bucket, $url) { - (manifest $app $bucket $url).version -} -function current_version($app, $global) { - @(versions $app $global)[-1] +function Get-LatestVersion { + <# + .SYNOPSIS + Get latest version of app from manifest + .PARAMETER AppName + App's name + .PARAMETER Bucket + Bucket which the app belongs to + .PARAMETER Uri + Remote app manifest's URI + #> + [OutputType([String])] + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] + [Alias('App')] + [String] + $AppName, + [Parameter(Position = 1)] + [String] + $Bucket, + [Parameter(Position = 2)] + [String] + $Uri + ) + process { + return (manifest $AppName $Bucket $Uri).version + } } -function versions($app, $global) { - $appdir = appdir $app $global - if(!(test-path $appdir)) { return @() } - sort_versions (Get-ChildItem $appdir -dir -attr !reparsePoint | Where-Object { $null -ne $(Get-ChildItem $_.fullname) } | ForEach-Object { $_.name }) +function Select-CurrentVersion { + <# + .SYNOPSIS + Select current version of installed app, from 'current\manifest.json' or modified time of version directory + .PARAMETER AppName + App's name + .PARAMETER Global + Globally installed application + #> + [OutputType([String])] + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] + [Alias('App')] + [String] + $AppName, + [Parameter(Position = 1)] + [Switch] + $Global + ) + process { + $appPath = appdir $AppName $Global + if (Test-Path "$appPath\current" -PathType Container) { + $currentVersion = (installed_manifest $AppName 'current' $Global).version + if ($currentVersion -eq 'nightly') { + $currentVersion = (Get-Item "$appPath\current").Target | Split-Path -Leaf + } + } else { + $installedVersion = Get-InstalledVersion -AppName $AppName -Global:$Global + if ($installedVersion) { + $currentVersion = $installedVersion[-1] + } else { + $currentVersion = $null + } + } + return $currentVersion + } } -function version($ver) { - $ver -split '[\.-]' | ForEach-Object { - $num = $_ -as [int] - if($num) { $num } else { $_ } +function Get-InstalledVersion { + <# + .SYNOPSIS + Get all installed version of app, by checking version directories' 'install.json' + .PARAMETER AppName + App's name + .PARAMETER Global + Globally installed application + .NOTES + Versions are sorted from oldest to newest, i.e., latest installed version is the last one in the output array. + If no installed version found, empty array will be returned. + #> + [OutputType([Object[]])] + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] + [Alias('App')] + [String] + $AppName, + [Parameter(Position = 1)] + [Switch] + $Global + ) + process { + $appPath = appdir $AppName $Global + if (Test-Path $appPath) { + $versions = @((Get-ChildItem "$appPath\*\install.json" | Sort-Object -Property LastWriteTimeUtc).Directory.Name) + return $versions | Where-Object { ($_ -ne 'current') -and ($_ -notlike '_*.old*') } + } else { + return @() + } } + # Deprecated + # sort_versions (Get-ChildItem $appPath -dir -attr !reparsePoint | Where-Object { $null -ne $(Get-ChildItem $_.FullName) } | ForEach-Object { $_.Name }) } -function compare_versions($a, $b) { - $ver_a = @(version $a) - $ver_b = @(version $b) - for($i=0;$i -lt $ver_a.length;$i++) { - if($i -gt $ver_b.length) { return 1; } +function Compare-Version { + <# + .SYNOPSIS + Compare versions, mainly according to SemVer's rules + .PARAMETER ReferenceVersion + Specifies a version used as a reference for comparison + .PARAMETER DifferenceVersion + Specifies the version that are compared to the reference version + .PARAMETER Delimiter + Specifies the delimiter of versions + .OUTPUTS + System.Int32 + '0' if DifferenceVersion is equal to ReferenceVersion, + '1' if DifferenceVersion is greater then ReferenceVersion, + '-1' if DifferenceVersion is less then ReferenceVersion + #> + [OutputType([Int32])] + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true, Position = 0)] + [AllowEmptyString()] + [String] + $ReferenceVersion, + [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true)] + [AllowEmptyString()] + [String] + $DifferenceVersion, + [String] + $Delimiter = '-' + ) + process { + # Use '+' sign as post-release, see https://github.com/lukesampson/scoop/pull/3721#issuecomment-553718093 + $ReferenceVersion, $DifferenceVersion = @($ReferenceVersion, $DifferenceVersion) -replace '\+', '-' - # don't try to compare int to string - if($ver_b[$i] -is [string] -and $ver_a[$i] -isnot [string]) { - $ver_a[$i] = "$($ver_a[$i])" + # Return 0 if versions are equal + if ($DifferenceVersion -eq $ReferenceVersion) { + return 0 } - if($ver_a[$i] -gt $ver_b[$i]) { return 1; } - if($ver_a[$i] -lt $ver_b[$i]) { return -1; } + # Preprocess versions (split, convert and separate) + $splitReferenceVersion = @(SplitVersion -Version $ReferenceVersion -Delimiter $Delimiter) + $splitDifferenceVersion = @(SplitVersion -Version $DifferenceVersion -Delimiter $Delimiter) + + # Nightly versions are always equal + if ($splitReferenceVersion[0] -eq 'nightly' -and $splitDifferenceVersion[0] -eq 'nightly') { + return 0 + } + + for ($i = 0; $i -lt [Math]::Max($splitReferenceVersion.Length, $splitDifferenceVersion.Length); $i++) { + # '1.1-alpha' is less then '1.1' + if ($i -ge $splitReferenceVersion.Length) { + if ($splitDifferenceVersion[$i] -match 'alpha|beta|rc|pre') { + return -1 + } else { + return 1 + } + } + # '1.1' is greater then '1.1-beta' + if ($i -ge $splitDifferenceVersion.Length) { + if ($splitReferenceVersion[$i] -match 'alpha|beta|rc|pre') { + return 1 + } else { + return -1 + } + } + + # If some parts of versions have '.', compare them with delimiter '.' + if (($splitReferenceVersion[$i] -match '\.') -or ($splitDifferenceVersion[$i] -match '\.')) { + $Result = Compare-Version -ReferenceVersion $splitReferenceVersion[$i] -DifferenceVersion $splitDifferenceVersion[$i] -Delimiter '.' + # If the parts are equal, continue to next part, otherwise return + if ($Result -ne 0) { + return $Result + } else { + continue + } + } + + # Don't try to compare [Long] to [String] + if ($null -ne $splitReferenceVersion[$i] -and $null -ne $splitDifferenceVersion[$i]) { + if ($splitReferenceVersion[$i] -is [String] -and $splitDifferenceVersion[$i] -isnot [String]) { + $splitDifferenceVersion[$i] = "$($splitDifferenceVersion[$i])" + } + if ($splitDifferenceVersion[$i] -is [String] -and $splitReferenceVersion[$i] -isnot [String]) { + $splitReferenceVersion[$i] = "$($splitReferenceVersion[$i])" + } + } + + # Compare [String] or [Long] + if ($splitDifferenceVersion[$i] -gt $splitReferenceVersion[$i]) { + return 1 + } + if ($splitDifferenceVersion[$i] -lt $splitReferenceVersion[$i]) { + return -1 + } + } } - if($ver_b.length -gt $ver_a.length) { return -1 } - return 0 } +# Helper function +function SplitVersion { + <# + .SYNOPSIS + Split version by Delimiter, convert number string to number, and separate letters from numbers + .PARAMETER Version + Specifies a version + .PARAMETER Delimiter + Specifies the delimiter of version (Literal) + #> + [OutputType([Object[]])] + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] + [AllowEmptyString()] + [String] + $Version, + [String] + $Delimiter = '-' + ) + process { + $Version = $Version -replace '[a-zA-Z]+', "$Delimiter$&$Delimiter" + return ($Version -split [Regex]::Escape($Delimiter) -ne '' | ForEach-Object { if ($_ -match '^\d+$') { [Long]$_ } else { $_ } }) + } +} + +# Deprecated +# Not used anymore in scoop core function qsort($ary, $fn) { - if($null -eq $ary) { return @() } - if(!($ary -is [array])) { return @($ary) } + warn '"qsort" is deprecated. Please avoid using it anymore.' + if ($null -eq $ary) { return @() } + if (!($ary -is [array])) { return @($ary) } $pivot = $ary[0] - $rem = $ary[1..($ary.length-1)] + $rem = $ary[1..($ary.length - 1)] - $lesser = qsort ($rem | Where-Object { (& $fn $_ $pivot) -lt 0 }) $fn + $lesser = qsort ($rem | Where-Object { (& $fn $pivot $_) -lt 0 }) $fn - $greater = qsort ($rem | Where-Object { (& $fn $_ $pivot) -ge 0 }) $fn + $greater = qsort ($rem | Where-Object { (& $fn $pivot $_) -ge 0 }) $fn return @() + $lesser + @($pivot) + $greater } -function sort_versions($versions) { qsort $versions compare_versions } + +# Deprecated +# Not used anymore in scoop core +function sort_versions($versions) { + warn '"sort_versions" is deprecated. Please avoid using it anymore.' + qsort $versions Compare-Version +} + +function compare_versions($a, $b) { + Show-DeprecatedWarning $MyInvocation 'Compare-Version' + # Please note the parameters' sequence + return Compare-Version -ReferenceVersion $b -DifferenceVersion $a +} + +function latest_version($app, $bucket, $url) { + Show-DeprecatedWarning $MyInvocation 'Get-LatestVersion' + return Get-LatestVersion -AppName $app -Bucket $bucket -Uri $url +} + +function current_version($app, $global) { + Show-DeprecatedWarning $MyInvocation 'Select-CurrentVersion' + return Select-CurrentVersion -AppName $app -Global:$global +} + +function versions($app, $global) { + Show-DeprecatedWarning $MyInvocation 'Get-InstalledVersion' + return Get-InstalledVersion -AppName $app -Global:$global +} diff --git a/libexec/scoop-cleanup.ps1 b/libexec/scoop-cleanup.ps1 index 482fbc1ac0..4b9c735b7d 100644 --- a/libexec/scoop-cleanup.ps1 +++ b/libexec/scoop-cleanup.ps1 @@ -31,11 +31,11 @@ if ($global -and !(is_admin)) { } function cleanup($app, $global, $verbose, $cache) { - $current_version = current_version $app $global + $current_version = Select-CurrentVersion -AppName $app -Global:$global if ($cache) { Remove-Item "$cachedir\$app#*" -Exclude "$app#$current_version#*" } - $versions = versions $app $global | Where-Object { $_ -ne $current_version -and $_ -ne 'current' } + $versions = Get-InstalledVersion -AppName $app -Global:$global | Where-Object { $_ -ne $current_version -and $_ -ne 'current' } if (!$versions) { if ($verbose) { success "$app is already clean" } return diff --git a/libexec/scoop-export.ps1 b/libexec/scoop-export.ps1 index e2cce6d7b7..e4a9d81f5c 100644 --- a/libexec/scoop-export.ps1 +++ b/libexec/scoop-export.ps1 @@ -23,7 +23,7 @@ if($apps) { $apps | Sort-Object { $_.name } | Where-Object { !$query -or ($_.name -match $query) } | ForEach-Object { $app = $_.name $global = $_.global - $ver = current_version $app $global + $ver = Select-CurrentVersion -AppName $app -Global:$global $global_display = $null; if($global) { $global_display = ' *global*'} $install_info = install_info $app $ver $global diff --git a/libexec/scoop-info.ps1 b/libexec/scoop-info.ps1 index e13119a945..b54720a4cc 100644 --- a/libexec/scoop-info.ps1 +++ b/libexec/scoop-info.ps1 @@ -85,7 +85,7 @@ Write-Output "Manifest:`n $manifest_file" if($status.installed) { # Show installed versions Write-Output "Installed:" - $versions = versions $app $global + $versions = Get-InstalledVersion -AppName $app -Global:$global $versions | ForEach-Object { $dir = versiondir $app $_ $global if($global) { $dir += " *global*" } diff --git a/libexec/scoop-install.ps1 b/libexec/scoop-install.ps1 index 379784d5b5..8a759463ea 100644 --- a/libexec/scoop-install.ps1 +++ b/libexec/scoop-install.ps1 @@ -37,7 +37,7 @@ function is_installed($app, $global) { if (installed $app $global) { function gf($g) { if ($g) { ' --global' } } - $version = @(versions $app $global)[-1] + $version = Select-CurrentVersion -AppName $app -Global:$global if (!(install_info $app $version $global)) { warn "Purging previous failed installation of $app." & "$PSScriptRoot\scoop-uninstall.ps1" $app$(gf $global) @@ -117,7 +117,7 @@ $apps, $skip = prune_installed $apps $global $skip | Where-Object { $explicit_apps -contains $_ } | ForEach-Object { $app, $null, $null = parse_app $_ - $version = @(versions $app $global)[-1] + $version = Select-CurrentVersion -AppName $app -Global:$global warn "'$app' ($version) is already installed. Skipping." } diff --git a/libexec/scoop-list.ps1 b/libexec/scoop-list.ps1 index 44c45a7415..438d56ab9b 100644 --- a/libexec/scoop-list.ps1 +++ b/libexec/scoop-list.ps1 @@ -21,7 +21,7 @@ if($apps) { $apps | Sort-Object { $_.name } | Where-Object { !$query -or ($_.name -match $query) } | ForEach-Object { $app = $_.name $global = $_.global - $ver = current_version $app $global + $ver = Select-CurrentVersion -AppName $app -Global:$global $install_info = install_info $app $ver $global write-host " $app " -NoNewline diff --git a/libexec/scoop-reset.ps1 b/libexec/scoop-reset.ps1 index 1c89fb1c2f..b2ce410734 100644 --- a/libexec/scoop-reset.ps1 +++ b/libexec/scoop-reset.ps1 @@ -45,7 +45,7 @@ $apps | ForEach-Object { } if ($null -eq $version) { - $version = current_version $app $global + $version = Select-CurrentVersion -AppName $app -Global:$global } $manifest = installed_manifest $app $version $global diff --git a/libexec/scoop-search.ps1 b/libexec/scoop-search.ps1 index 7758fa53c8..e60cddeea9 100644 --- a/libexec/scoop-search.ps1 +++ b/libexec/scoop-search.ps1 @@ -44,7 +44,7 @@ function search_bucket($bucket, $query) { } } } - $apps | ForEach-Object { $_.version = (latest_version $_.name $bucket); $_ } + $apps | ForEach-Object { $_.version = (Get-LatestVersion -AppName $_.name -Bucket $bucket); $_ } } function download_json($url) { diff --git a/libexec/scoop-uninstall.ps1 b/libexec/scoop-uninstall.ps1 index e9797e6cbf..500d6c4bc5 100644 --- a/libexec/scoop-uninstall.ps1 +++ b/libexec/scoop-uninstall.ps1 @@ -50,7 +50,7 @@ if (!$apps) { exit 0 } :app_loop foreach ($_ in $apps) { ($app, $global) = $_ - $version = current_version $app $global + $version = Select-CurrentVersion -AppName $app -Global:$global Write-Host "Uninstalling '$app' ($version)." $dir = versiondir $app $version $global @@ -101,7 +101,7 @@ if (!$apps) { exit 0 } } # remove older versions - $old = @(versions $app $global) + $old = Get-InstalledVersion -AppName $app -Global:$global foreach ($oldver in $old) { Write-Host "Removing older version ($oldver)." $dir = versiondir $app $oldver $global @@ -115,7 +115,7 @@ if (!$apps) { exit 0 } } } - if (@(versions $app $global).length -eq 0) { + if ((Get-InstalledVersion -AppName $app -Global:$global).length -eq 0) { $appdir = appdir $app $global try { # if last install failed, the directory seems to be locked and this diff --git a/libexec/scoop-update.ps1 b/libexec/scoop-update.ps1 index de071d1a56..100e3c0a91 100644 --- a/libexec/scoop-update.ps1 +++ b/libexec/scoop-update.ps1 @@ -154,7 +154,7 @@ function update_scoop() { } function update($app, $global, $quiet = $false, $independent, $suggested, $use_cache = $true, $check_hash = $true) { - $old_version = current_version $app $global + $old_version = Select-CurrentVersion -AppName $app -Global:$global $old_manifest = installed_manifest $app $old_version $global $install = install_info $app $old_version $global @@ -173,7 +173,7 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c $deps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash } } - $version = latest_version $app $bucket $url + $version = Get-LatestVersion -AppName $app -Bucket $bucket -Uri $url $is_nightly = $version -eq 'nightly' if ($is_nightly) { $version = nightly_version $(get-date) $quiet diff --git a/test/Scoop-Versions.Tests.ps1 b/test/Scoop-Versions.Tests.ps1 index a02e968213..8fee628604 100644 --- a/test/Scoop-Versions.Tests.ps1 +++ b/test/Scoop-Versions.Tests.ps1 @@ -1,37 +1,96 @@ . "$psscriptroot\Scoop-TestLib.ps1" . "$psscriptroot\..\lib\versions.ps1" -describe "versions" -Tag 'Scoop' { - it 'compares versions with integer-string mismatch' { - $a = '1.8.9' - $b = '1.8.5-1' - $res = compare_versions $a $b +Describe 'versions comparison' -Tag 'Scoop' { + Context 'semver compliant versions' { + It 'handles major.minor.patch progressing' { + Compare-Version '0.1.0' '0.1.1' | Should -Be 1 + Compare-Version '0.1.1' '0.2.0' | Should -Be 1 + Compare-Version '0.2.0' '1.0.0' | Should -Be 1 + } - $res | should -be 1 - } - - it 'handles plain string version comparison to int version' { - $a = 'latest' - $b = '20150405' - $res = compare_versions $a $b + It 'handles pre-release versioning progression' { + Compare-Version '0.4.0' '0.5.0-alpha.1' | Should -Be 1 + Compare-Version '0.5.0-alpha.1' '0.5.0-alpha.2' | Should -Be 1 + Compare-Version '0.5.0-alpha.2' '0.5.0-alpha.10' | Should -Be 1 + Compare-Version '0.5.0-alpha.10' '0.5.0-beta' | Should -Be 1 + Compare-Version '0.5.0-beta' '0.5.0-alpha.10' | Should -Be -1 + Compare-Version '0.5.0-beta' '0.5.0-beta.0' | Should -Be 1 + } - $res | should -be 1 + It 'handles the pre-release tags in an alphabetic order' { + Compare-Version '0.5.0-rc.1' '0.5.0-z' | Should -Be 1 + Compare-Version '0.5.0-rc.1' '0.5.0-howdy' | Should -Be -1 + Compare-Version '0.5.0-howdy' '0.5.0-rc.1' | Should -Be 1 + } } - it 'handles dashed version components' { - $a = '7.0.4-9' - $b = '7.0.4-10' + Context 'semver semi-compliant versions' { + It 'handles Windows-styled major.minor.patch.build progression' { + Compare-Version '0.0.0.0' '0.0.0.1' | Should -Be 1 + Compare-Version '0.0.0.1' '0.0.0.2' | Should -Be 1 + Compare-Version '0.0.0.2' '0.0.1.0' | Should -Be 1 + Compare-Version '0.0.1.0' '0.0.1.1' | Should -Be 1 + Compare-Version '0.0.1.1' '0.0.1.2' | Should -Be 1 + Compare-Version '0.0.1.2' '0.0.2.0' | Should -Be 1 + Compare-Version '0.0.2.0' '0.1.0.0' | Should -Be 1 + Compare-Version '0.1.0.0' '0.1.0.1' | Should -Be 1 + Compare-Version '0.1.0.1' '0.1.0.2' | Should -Be 1 + Compare-Version '0.1.0.2' '0.1.1.0' | Should -Be 1 + Compare-Version '0.1.1.0' '0.1.1.1' | Should -Be 1 + Compare-Version '0.1.1.1' '0.1.1.2' | Should -Be 1 + Compare-Version '0.1.1.2' '0.2.0.0' | Should -Be 1 + Compare-Version '0.2.0.0' '1.0.0.0' | Should -Be 1 + } - $res = compare_versions $a $b + It 'handles partial semver version differences' { + Compare-Version '1' '1.1' | Should -Be 1 + Compare-Version '1' '1.0' | Should -Be 1 + Compare-Version '1.1.0.0' '1.1' | Should -Be -1 + Compare-Version '1.4' '1.3.0' | Should -Be -1 + Compare-Version '1.4' '1.3.255.255' | Should -Be -1 + Compare-Version '1.4' '1.4.4' | Should -Be 1 + Compare-Version '1.1.1_8' '1.1.1' | Should -Be -1 + Compare-Version '1.1.1b' '1.1.1a' | Should -Be -1 + Compare-Version '1.1.1a' '1.1.1b' | Should -Be 1 + Compare-Version '1.1a2' '1.1a3' | Should -Be 1 + Compare-Version '1.1.1a10' '1.1.1b1' | Should -Be 1 + } - $res | should -be -1 + It 'handles dash-style versions' { + Compare-Version '1.8.9' '1.8.5-1' | Should -Be -1 + Compare-Version '7.0.4-9' '7.0.4-10' | Should -Be 1 + Compare-Version '7.0.4-9' '7.0.4-8' | Should -Be -1 + Compare-Version '2019-01-01' '2019-01-02' | Should -Be 1 + Compare-Version '2019-01-02' '2019-01-01' | Should -Be -1 + Compare-Version '2018-01-01' '2019-01-01' | Should -Be 1 + Compare-Version '2019-01-01' '2018-01-01' | Should -Be -1 + } + It 'handles post-release tagging ("+")' { + Compare-Version '1' '1+hotfix.0' | Should -Be 1 + Compare-Version '1.0.0' '1.0.0+hotfix.0' | Should -Be 1 + Compare-Version '1.0.0+hotfix.0' '1.0.0+hotfix.1' | Should -Be 1 + Compare-Version '1.0.0+hotfix.1' '1.0.1' | Should -Be 1 + Compare-Version '1.0.0+1.1' '1.0.0+1' | Should -Be -1 + } } - it 'handles comparsion against en empty string' { - compare_versions '7.0.4-9' '' | should -be 1 - } + Context 'other misc versions' { + It 'handles plain text string' { + Compare-Version 'latest' '20150405' | Should -Be -1 + Compare-Version '0.5alpha' '0.5' | Should -Be 1 + Compare-Version '0.5' '0.5Beta' | Should -Be -1 + Compare-Version '0.4' '0.5Beta' | Should -Be 1 + } + + It 'handles empty string' { + Compare-Version '7.0.4-9' '' | Should -Be -1 + } - it 'handles equal versions' { - compare_versions '12.0' '12.0' | should -be 0 + It 'handles equal versions' { + Compare-Version '12.0' '12.0' | Should -Be 0 + Compare-Version '7.0.4-9' '7.0.4-9' | Should -Be 0 + Compare-Version 'nightly-20190801' 'nightly' | Should -Be 0 + } } }