diff --git a/CHANGELOG.md b/CHANGELOG.md index bcd7e86..7104b20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Don't update from a manually-updated prerelease to a latest stable release that is earlier than the prerelease ([#78](https://github.com/getsentry/github-workflows/pull/78)) + ## 2.11.0 ### Features diff --git a/updater/scripts/common.ps1 b/updater/scripts/common.ps1 new file mode 100644 index 0000000..d248721 --- /dev/null +++ b/updater/scripts/common.ps1 @@ -0,0 +1,11 @@ + +function GetComparableVersion([string] $value) +{ + $value = $value -replace '^v', '' + try { + [System.Management.Automation.SemanticVersion]::Parse($value) + } catch { + Write-Warning "Failed to parse string '$value' as semantic version: $_" + $null + } +} diff --git a/updater/scripts/sort-versions.ps1 b/updater/scripts/sort-versions.ps1 index 1b2248c..0c23c00 100644 --- a/updater/scripts/sort-versions.ps1 +++ b/updater/scripts/sort-versions.ps1 @@ -3,38 +3,8 @@ param( ) Set-StrictMode -Version latest +. "$PSScriptRoot/common.ps1" -function GetComparablePart([Parameter(Mandatory = $true)][string] $value) -{ - $value.PadLeft(10, '0') -} - -function GetComparableVersion([Parameter(Mandatory = $true)][string] $value) -{ - $value = $value -replace '^v', '' - $output = '' - $buffer = '' - for ($i = 0; $i -lt $value.Length; $i++) - { - $char = $value[$i] - if ("$char" -match '[^a-zA-Z0-9]') - { - # Found a separtor, update the current buffer - $output += GetComparablePart $buffer - $output += $char - $buffer = '' - } - else - { - $buffer += $char - } - } - if ($buffer.Length -gt 0) - { - $output += GetComparablePart $buffer - } - - $output -} - -$List | Sort-Object -Property @{Expression = { GetComparableVersion $_ } } +$List ` + | Where-Object { $null -ne (GetComparableVersion $_) } ` + | Sort-Object -Property @{Expression = { GetComparableVersion $_ } } diff --git a/updater/scripts/update-dependency.ps1 b/updater/scripts/update-dependency.ps1 index bfa0ba4..c9af07b 100644 --- a/updater/scripts/update-dependency.ps1 +++ b/updater/scripts/update-dependency.ps1 @@ -14,6 +14,7 @@ param( ) Set-StrictMode -Version latest +. "$PSScriptRoot/common.ps1" if (-not (Test-Path $Path )) { @@ -45,8 +46,9 @@ if (-not $isSubmodule) if (Get-Command 'chmod' -ErrorAction SilentlyContinue) { chmod +x $Path - if ($LastExitCode -ne 0) { - throw "chmod failed"; + if ($LastExitCode -ne 0) + { + throw 'chmod failed'; } } try @@ -69,18 +71,18 @@ if (-not $isSubmodule) { switch ($action) { - "get-version" + 'get-version' { return (Get-Content $Path -Raw | ConvertFrom-StringData).version } - "get-repo" + 'get-repo' { return (Get-Content $Path -Raw | ConvertFrom-StringData).repo } - "set-version" + 'set-version' { $content = Get-Content $Path - $content = $content -replace "^(?version *= *).*$", "`${prop}$value" + $content = $content -replace '^(?version *= *).*$', "`${prop}$value" $content | Out-File $Path $readVersion = (Get-Content $Path -Raw | ConvertFrom-StringData).version @@ -99,7 +101,7 @@ if (-not $isSubmodule) } } -if ("$Tag" -eq "") +if ("$Tag" -eq '') { if ($isSubmodule) { @@ -111,7 +113,7 @@ if ("$Tag" -eq "") git fetch --tags [string[]]$tags = $(git tag --list) $url = $(git remote get-url origin) - $mainBranch = $(git remote show origin | Select-String "HEAD branch: (.*)").Matches[0].Groups[1].Value + $mainBranch = $(git remote show origin | Select-String 'HEAD branch: (.*)').Matches[0].Groups[1].Value } finally { @@ -125,9 +127,9 @@ if ("$Tag" -eq "") # Get tags for a repo without cloning. [string[]]$tags = $(git ls-remote --refs --tags $url) - $tags = $tags | ForEach-Object { ($_ -split "\s+")[1] -replace '^refs/tags/', '' } + $tags = $tags | ForEach-Object { ($_ -split '\s+')[1] -replace '^refs/tags/', '' } - $headRef = ($(git ls-remote $url HEAD) -split "\s+")[0] + $headRef = ($(git ls-remote $url HEAD) -split '\s+')[0] if ("$headRef" -eq '') { throw "Couldn't determine repository head (no ref returned by ls-remote HEAD" @@ -155,18 +157,46 @@ if ("$Tag" -eq "") Write-Host "Sorted tags: $tags" $latestTag = $tags[-1] - $latestTagNice = ($latestTag -match "^[0-9]") ? "v$latestTag" : $latestTag - SetOutput "originalTag" $originalTag - SetOutput "latestTag" $latestTag - SetOutput "latestTagNice" $latestTagNice - SetOutput "url" $url - SetOutput "mainBranch" $mainBranch + if (("$originalTag" -ne '') -and ("$latestTag" -ne '') -and ("$latestTag" -ne "$originalTag")) + { + do + { + # It's possible that the dependency was updated to a pre-release version manually in which case we don't want to + # roll back, even though it's not the latest version matching the configured pattern. + if ((GetComparableVersion $originalTag) -ge (GetComparableVersion $latestTag)) + { + Write-Host "SemVer represented by the original tag '$originalTag' is newer than the latest tag '$latestTag'. Skipping update." + $latestTag = $originalTag + break + } + + # Verify that the latest tag actually points to a different commit. Otherwise, we don't need to update. + $refs = $(git ls-remote --tags $url) + $refOriginal = (($refs -match "refs/tags/$originalTag" ) -split '[ \t]') | Select-Object -First 1 + $refLatest = (($refs -match "refs/tags/$latestTag" ) -split '[ \t]') | Select-Object -First 1 + if ($refOriginal -eq $refLatest) + { + Write-Host "Latest tag '$latestTag' points to the same commit as the original tag '$originalTag'. Skipping update." + $latestTag = $originalTag + break + } + } while ($false) + } + + $latestTagNice = ($latestTag -match '^[0-9]') ? "v$latestTag" : $latestTag + + SetOutput 'originalTag' $originalTag + SetOutput 'latestTag' $latestTag + SetOutput 'latestTagNice' $latestTagNice + SetOutput 'url' $url + SetOutput 'mainBranch' $mainBranch if ("$originalTag" -eq "$latestTag") { return } + $Tag = $latestTag } diff --git a/updater/tests/sort-versions.ps1 b/updater/tests/sort-versions.ps1 index f4cc31e..b7cf5e6 100644 --- a/updater/tests/sort-versions.ps1 +++ b/updater/tests/sort-versions.ps1 @@ -20,8 +20,8 @@ RunTest "sort standard versions v2" { AssertEqual @('v1.2.3', '3.0.0', '5.4.1', '5.4.11', '5.5', 'v6.0') $sorted } -# TODO, currently doesn't respect (order) stuff like RC, Beta, etc. -# RunTest "sort with pre-releases" { -# $sorted = SortVersions @('3.0.0', '5.4.11', 'v1.2.3', '5.4.1', '5.4.11-rc.0') -# AssertEqual @('v1.2.3', '3.0.0', '5.4.1', '5.4.11-rc.0', '5.4.11') $sorted -# } +# https://semver.org/#spec-item-11 +RunTest "sort with pre-releases" { + $sorted = SortVersions @('1.0.0-rc.1', '1.0.0', '1.0.0-beta.11', '1.0.0-alpha.1', '1.0.0-beta', '1.0.0-alpha.beta', '1.0.0-alpha', '1.0.0-beta.2') + AssertEqual @('1.0.0-alpha', '1.0.0-alpha.1', '1.0.0-alpha.beta', '1.0.0-beta', '1.0.0-beta.2', '1.0.0-beta.11', '1.0.0-rc.1', '1.0.0') $sorted +} diff --git a/updater/tests/update-dependency.ps1 b/updater/tests/update-dependency.ps1 index 9a6eb1f..4fed6af 100644 --- a/updater/tests/update-dependency.ps1 +++ b/updater/tests/update-dependency.ps1 @@ -23,19 +23,19 @@ $repoUrl = 'https://github.com/getsentry/github-workflows' $currentVersion = (git -c 'versionsort.suffix=-' ls-remote --tags --sort='v:refname' $repoUrl ` | Select-Object -Last 1 | Select-String -Pattern 'refs/tags/(.*)$').Matches.Groups[1].Value -RunTest "properties-file" { +RunTest 'properties-file' { $testFile = "$testDir/test.properties" - @("repo=$repoUrl", "version = none") | Out-File $testFile + @("repo=$repoUrl", 'version = none') | Out-File $testFile UpdateDependency $testFile AssertEqual @("repo=$repoUrl", "version = $currentVersion") (Get-Content $testFile) } -RunTest "version pattern match" { +RunTest 'version pattern match' { $testFile = "$testDir/test.properties" $repo = 'https://github.com/getsentry/sentry-cli' - @("repo=$repo", "version=0") | Out-File $testFile + @("repo=$repo", 'version=0') | Out-File $testFile UpdateDependency $testFile '^0\.' - AssertEqual @("repo=$repo", "version=0.28.0") (Get-Content $testFile) + AssertEqual @("repo=$repo", 'version=0.28.0') (Get-Content $testFile) } function _testOutput([string[]] $output) @@ -48,27 +48,27 @@ function _testOutput([string[]] $output) AssertContains $output 'mainBranch=master' } -RunTest "writes output" { +RunTest 'writes output' { $testFile = "$testDir/test.properties" $repo = 'https://github.com/getsentry/sentry-cli' - @("repo=$repo", "version=0") | Out-File $testFile + @("repo=$repo", 'version=0') | Out-File $testFile $stdout = UpdateDependency $testFile '^0\.' _testOutput $stdout } -RunTest "writes to env:GITHUB_OUTPUT" { +RunTest 'writes to env:GITHUB_OUTPUT' { $testFile = "$testDir/test.properties" $repo = 'https://github.com/getsentry/sentry-cli' - @("repo=$repo", "version=0") | Out-File $testFile + @("repo=$repo", 'version=0') | Out-File $testFile $outFile = "$testDir/outfile" New-Item $outFile -ItemType File | Out-Null try { $env:GITHUB_OUTPUT = $outFile $stdout = UpdateDependency $testFile '^0\.' - Write-Host "Testing standard output" + Write-Host 'Testing standard output' _testOutput $stdout - Write-Host "Testing env:GITHUB_OUTPUT" + Write-Host 'Testing env:GITHUB_OUTPUT' _testOutput (Get-Content $outFile) } finally @@ -80,15 +80,23 @@ RunTest "writes to env:GITHUB_OUTPUT" { } # Note: without custom sorting, this would have yielded 'v1.7.31_gradle_plugin' -RunTest "version sorting must work properly" { +RunTest 'version sorting must work properly' { $testFile = "$testDir/test.properties" $repo = 'https://github.com/getsentry/sentry-java' - @("repo=$repo", "version=0") | Out-File $testFile + @("repo=$repo", 'version=0') | Out-File $testFile UpdateDependency $testFile '^v?[123].*$' - AssertEqual @("repo=$repo", "version=3.2.1") (Get-Content $testFile) + AssertEqual @("repo=$repo", 'version=3.2.1') (Get-Content $testFile) } -RunTest "powershell-script" { +RunTest 'will not update from a later release to an earlier release' { + $testFile = "$testDir/test.properties" + $repo = 'https://github.com/getsentry/sentry-java' + @("repo=$repo", 'version=999.0.0-beta.1') | Out-File $testFile + UpdateDependency $testFile + AssertEqual @("repo=$repo", 'version=999.0.0-beta.1') (Get-Content $testFile) +} + +RunTest 'powershell-script' { $testFile = "$testDir/test.version" '' | Out-File $testFile $testScript = "$testDir/test.ps1" @@ -109,7 +117,7 @@ switch ($action) AssertEqual $currentVersion (Get-Content $testFile) } -RunTest "bash-script" { +RunTest 'bash-script' { $testFile = "$testDir/test.version" '' | Out-File $testFile $testScript = "$testDir/test.sh" @@ -136,18 +144,18 @@ esac '@ | Out-File $testScript UpdateDependency $testScript AssertEqual $currentVersion (Get-Content $testFile) -} -skipReason ($IsWindows ? "on Windows" : '') +} -skipReason ($IsWindows ? 'on Windows' : '') -RunTest "powershell-script fails in get-version" { +RunTest 'powershell-script fails in get-version' { $testScript = "$testDir/test.ps1" @' throw "Failure" '@ | Out-File $testScript - AssertFailsWith "get-version | output: Failure" { UpdateDependency $testScript } + AssertFailsWith 'get-version | output: Failure' { UpdateDependency $testScript } } -RunTest "bash-script fails in get-version" { +RunTest 'bash-script fails in get-version' { $testScript = "$testDir/test.sh" @' #!/usr/bin/env bash @@ -155,10 +163,10 @@ echo "Failure" exit 1 '@ | Out-File $testScript - AssertFailsWith "get-version | output: Failure" { UpdateDependency $testScript } -} -skipReason ($IsWindows ? "on Windows" : '') + AssertFailsWith 'get-version | output: Failure' { UpdateDependency $testScript } +} -skipReason ($IsWindows ? 'on Windows' : '') -RunTest "powershell-script fails in get-repo" { +RunTest 'powershell-script fails in get-repo' { $testScript = "$testDir/test.ps1" @' param([string] $action, [string] $value) @@ -168,10 +176,10 @@ if ($action -eq "get-repo") } '@ | Out-File $testScript - AssertFailsWith "get-repo | output: Failure" { UpdateDependency $testScript } + AssertFailsWith 'get-repo | output: Failure' { UpdateDependency $testScript } } -RunTest "bash-script fails in get-repo" { +RunTest 'bash-script fails in get-repo' { $testScript = "$testDir/test.sh" @' #!/usr/bin/env bash @@ -186,10 +194,10 @@ get-repo) esac '@ | Out-File $testScript - AssertFailsWith "get-repo | output: Failure" { UpdateDependency $testScript } -} -skipReason ($IsWindows ? "on Windows" : '') + AssertFailsWith 'get-repo | output: Failure' { UpdateDependency $testScript } +} -skipReason ($IsWindows ? 'on Windows' : '') -RunTest "powershell-script fails in set-version" { +RunTest 'powershell-script fails in set-version' { $testScript = "$testDir/test.ps1" @' param([string] $action, [string] $value) @@ -206,7 +214,7 @@ switch ($action) AssertFailsWith "set-version $currentVersion | output: Failure" { UpdateDependency $testScript } } -RunTest "bash-script fails in set-version" { +RunTest 'bash-script fails in set-version' { $testScript = "$testDir/test.sh" @' #!/usr/bin/env bash @@ -228,4 +236,4 @@ esac '@ | Out-File $testScript AssertFailsWith "set-version $currentVersion | output: Failure" { UpdateDependency $testScript } -} -skipReason ($IsWindows ? "on Windows" : '') +} -skipReason ($IsWindows ? 'on Windows' : '')