diff --git a/CHANGELOG.md b/CHANGELOG.md index daa5eae..b4c8dbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixes - Validate PR - Skip PRs opened by bots of GitHub Apps owned by Sentry (the `getsentry` organization or the `sentry` enterprise), such as `sentry-junior[bot]`. App bot users are never repo collaborators, so the write-access check couldn't recognize them. ([#179](https://github.com/getsentry/github-workflows/pull/179)) +- Updater - Support prefixed release tags, such as `cli@1.2.3`, via a `version` named group in `pattern`. ([#184](https://github.com/getsentry/github-workflows/pull/184)) ## 3.4.1 diff --git a/updater/README.md b/updater/README.md index 7929dfb..3d09e18 100644 --- a/updater/README.md +++ b/updater/README.md @@ -153,6 +153,9 @@ Git lookup or fetch failures are also reported as errors. Annotated release tags * type: string * required: true * `pattern`: RegEx pattern that will be matched against available versions when picking the latest one. + An optional `version` named group marks the version part of the tag, which is used to compare versions and in the PR title and changelog entry. + For monorepos that tag releases with a product prefix (e.g. `cli@1.2.3`), use a pattern like `'^cli@(?[0-9.]+)$'`. + Without the group, only a leading `v` is removed from the tag. * type: string * required: false * default: '' diff --git a/updater/action.yml b/updater/action.yml index ead6fa1..5a53486 100644 --- a/updater/action.yml +++ b/updater/action.yml @@ -10,7 +10,7 @@ inputs: description: 'Name used in the PR title and the changelog entry.' required: true pattern: - description: 'RegEx pattern that will be matched against available versions when picking the latest one.' + description: 'RegEx pattern that will be matched against available versions when picking the latest one. An optional `version` named group marks the version part of the tag, e.g. `^cli@(?[0-9.]+)$`.' required: false default: '' gh-title-pattern: @@ -448,6 +448,8 @@ runs: TARGET_MAIN_BRANCH: ${{ steps.target.outputs.mainBranch }} ORIGINAL_TAG: ${{ steps.target.outputs.originalTag }} LATEST_TAG: ${{ steps.target.outputs.latestTag }} + ORIGINAL_VERSION: ${{ steps.target.outputs.originalVersion }} + LATEST_VERSION: ${{ steps.target.outputs.latestVersion }} run: | ${{ github.action_path }}/scripts/update-changelog.ps1 ` -Name $env:DEPENDENCY_NAME ` @@ -456,6 +458,8 @@ runs: -MainBranch $env:TARGET_MAIN_BRANCH ` -OldTag $env:ORIGINAL_TAG ` -NewTag $env:LATEST_TAG ` + -OldVersion $env:ORIGINAL_VERSION ` + -NewVersion $env:LATEST_VERSION ` -Section $env:CHANGELOG_SECTION - name: Show final git diff diff --git a/updater/scripts/common.ps1 b/updater/scripts/common.ps1 index d248721..ea64d9d 100644 --- a/updater/scripts/common.ps1 +++ b/updater/scripts/common.ps1 @@ -1,4 +1,39 @@ +$FallbackVersionPattern = '^v?(?.+)$' + +function GetVersionFromTag([string] $tag, [string] $pattern = '') +{ + if ($pattern -ne '' -and $tag -match $pattern -and $Matches.ContainsKey('version')) + { + return $Matches['version'] + } + if ($tag -match $FallbackVersionPattern) + { + return $Matches['version'] + } + return $tag +} + +# E.g. `cli@` for both `cli@1.2.3` and `cli@v1.2.3` +function GetTagPrefix([string] $tag, [string] $pattern) +{ + $match = [regex]::Match($tag, $pattern, 'IgnoreCase') + if (-not $match.Success -or -not $match.Groups['version'].Success) + { + return '' + } + return $tag.Substring(0, $match.Groups['version'].Index) -replace 'v$', '' +} + +function GetVersionAfterPrefix([string] $tag, [string] $prefix) +{ + if ($tag -match ('^' + [regex]::Escape($prefix) + 'v?(?.+)$')) + { + return $Matches['version'] + } + return $null +} + function GetComparableVersion([string] $value) { $value = $value -replace '^v', '' diff --git a/updater/scripts/get-changelog.ps1 b/updater/scripts/get-changelog.ps1 index c892160..39ff8ce 100644 --- a/updater/scripts/get-changelog.ps1 +++ b/updater/scripts/get-changelog.ps1 @@ -201,8 +201,8 @@ function Format-ChangelogContent { } # Apply standard formatting - # Remove at-mentions - $changelog = $changelog -replace '@', '' + # Remove at-mentions, but keep prefixed tags (`cli@1.2.3`) and email addresses + $changelog = $changelog -replace '(?[0-9.]+)$' } Write-Host "Filtering tags with pattern '$Pattern'" @@ -215,10 +215,19 @@ if ("$Tag" -eq '') { throw "Found no tags matching pattern '$Pattern'" } - $tags = & "$PSScriptRoot/sort-versions.ps1" $tags + $tags = @(& "$PSScriptRoot/sort-versions.ps1" $tags -Pattern $Pattern) + + if ($tags.Count -eq 0) { + throw "Found no tags with a semantic version matching pattern '$Pattern'. If the tags have a prefix, mark the version with a ``version`` named group, e.g. '^cli@(?[0-9.]+)$'." + } Write-Host "Sorted tags: $tags" $latestTag = $tags[-1] + $latestVersion = GetVersionFromTag $latestTag $Pattern + + # Read the original tag with the latest tag's prefix, so that a tag of another product is never read as a version + $tagPrefix = GetTagPrefix $latestTag $Pattern + $originalVersion = GetVersionAfterPrefix $originalTag $tagPrefix if (("$originalTag" -ne '') -and ("$latestTag" -ne '') -and ("$latestTag" -ne "$originalTag")) { do { @@ -245,7 +254,7 @@ if ("$Tag" -eq '') { # 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 (-not $isUnreleasedPin -and (GetComparableVersion $originalTag) -ge (GetComparableVersion $latestTag)) { + if (-not $isUnreleasedPin -and $null -ne $originalVersion -and (GetComparableVersion $originalVersion) -ge (GetComparableVersion $latestVersion)) { Write-Host "SemVer represented by the original tag '$originalTag' is newer than the latest tag '$latestTag'. Skipping update." $latestTag = $originalTag break @@ -265,10 +274,15 @@ if ("$Tag" -eq '') { } while ($false) } - $latestTagNice = ($latestTag -match '^[0-9]') ? "v$latestTag" : $latestTag + if ("$originalTag" -eq "$latestTag") { + $latestVersion = $originalVersion + } + $latestTagNice = ($latestVersion -match '^[0-9]') ? "v$latestVersion" : $latestTag SetOutput 'originalTag' $originalTag + SetOutput 'originalVersion' $originalVersion SetOutput 'latestTag' $latestTag + SetOutput 'latestVersion' $latestVersion SetOutput 'latestTagNice' $latestTagNice SetOutput 'url' $url SetOutput 'mainBranch' $mainBranch diff --git a/updater/tests/get-changelog.Tests.ps1 b/updater/tests/get-changelog.Tests.ps1 index aaa48c1..86b619e 100644 --- a/updater/tests/get-changelog.Tests.ps1 +++ b/updater/tests/get-changelog.Tests.ps1 @@ -322,6 +322,26 @@ Features, fixes and improvements in this release have been contributed by: $actual | Should -Be $expected } + It 'git commit fallback keeps prefixed tags' { + $actual = & "$PSScriptRoot/../scripts/get-changelog.ps1" ` + -RepoUrl 'https://github.com/getsentry/javascript-debug-ids' -OldTag '@debugids/browser@0.1.2' -NewTag '@debugids/browser@0.1.3' + + $expected = @' +## Changelog + +### Commits between debugids/browser@0.1.2 and debugids/browser@0.1.3 + +- meta(changelog): Update package versions ([#50](https://github-redirect.dependabot.com/getsentry/javascript-debug-ids/issues/50)) +- chore: Update dev deps to latest versions ([#49](https://github-redirect.dependabot.com/getsentry/javascript-debug-ids/issues/49)) +- chore: Add changeset for native vite support +- feat: Document native Vite support ([#48](https://github-redirect.dependabot.com/getsentry/javascript-debug-ids/issues/48)) +- feat: Update LICENSE date range for 2025 ([#47](https://github-redirect.dependabot.com/getsentry/javascript-debug-ids/issues/47)) +- chore: Format package.json +'@ + + $actual | Should -Be $expected + } + It 'git commit fallback returns empty when no commits found' { # Test with same tags (no commits between them) $actual = & "$PSScriptRoot/../scripts/get-changelog.ps1" ` diff --git a/updater/tests/sort-versions.Tests.ps1 b/updater/tests/sort-versions.Tests.ps1 index aec246e..1cde4bd 100644 --- a/updater/tests/sort-versions.Tests.ps1 +++ b/updater/tests/sort-versions.Tests.ps1 @@ -1,8 +1,8 @@ BeforeAll { - function SortVersions([Parameter(Mandatory = $true)][string[]] $List) + function SortVersions([Parameter(Mandatory = $true)][string[]] $List, [string] $Pattern = '') { - $result = & "$PSScriptRoot/../scripts/sort-versions.ps1" $List + $result = & "$PSScriptRoot/../scripts/sort-versions.ps1" $List -Pattern $Pattern if (-not $?) { throw $result @@ -27,4 +27,19 @@ Describe 'sort-versions' { $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') $sorted | Should -Be @('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') } + + It 'prefixed versions with a version group' { + $sorted = SortVersions @('cli@0.47.0', 'cli@0.9.0', 'cli@0.46.0', 'cli@0.47.0-beta.1') '^cli@(?.+)$' + $sorted | Should -Be @('cli@0.9.0', 'cli@0.46.0', 'cli@0.47.0-beta.1', 'cli@0.47.0') + } + + It 'skips prefixed versions without a version group' { + $sorted = SortVersions @('cli@0.47.0', '0.42.0') '^(cli@)?[0-9.]+$' 3>$null + $sorted | Should -Be @('0.42.0') + } + + It 'skips tags of another product' { + $sorted = SortVersions @('cli@0.47.0', 'logger@9.0.0') '^cli@(?.+)$' 3>$null + $sorted | Should -Be @('cli@0.47.0') + } } diff --git a/updater/tests/update-changelog.Tests.ps1 b/updater/tests/update-changelog.Tests.ps1 index 2665c42..214220c 100644 --- a/updater/tests/update-changelog.Tests.ps1 +++ b/updater/tests/update-changelog.Tests.ps1 @@ -48,4 +48,70 @@ Describe 'update-changelog' { Get-Content "$testCasePath/CHANGELOG.md" | Should -Be (Get-Content "$testCasePath/CHANGELOG.md.expected") } + + Context 'prefixed tags' { + BeforeEach { + $testCasePath = "$TestDrive/prefixed-tags" + New-Item $testCasePath -ItemType Directory -Force | Out-Null + } + + It 'should use the versions in displayed versions and the changelog anchor' { + @('# Changelog', '', '## Unreleased', '', '### Dependencies', '', '- Existing entry', '') | Out-File "$testCasePath/CHANGELOG.md" + + pwsh -WorkingDirectory $testCasePath -File "$PSScriptRoot/../scripts/update-changelog.ps1" ` + -Name 'Dependency' ` + -PR 'https://github.com/getsentry/dependant/pulls/123' ` + -RepoUrl 'https://github.com/getsentry/dependency' ` + -MainBranch 'main' ` + -OldTag 'cli@0.46.0' ` + -NewTag 'cli@0.47.0' ` + -OldVersion '0.46.0' ` + -NewVersion '0.47.0' ` + -Section 'Dependencies' + + $content = Get-Content "$testCasePath/CHANGELOG.md" + $content | Should -Contain '- Bump Dependency from v0.46.0 to v0.47.0 ([#123](https://github.com/getsentry/dependant/pulls/123))' + $content | Should -Contain ' - [changelog](https://github.com/getsentry/dependency/blob/main/CHANGELOG.md#0470)' + $content | Should -Contain ' - [diff](https://github.com/getsentry/dependency/compare/cli@0.46.0...cli@0.47.0)' + } + + It 'should update an existing entry' { + @('# Changelog', '', '## Unreleased', '', '### Dependencies', '', + '- Bump Dependency from v0.45.0 to v0.46.0 ([#100](https://github.com/getsentry/dependant/pulls/100))', + ' - [changelog](https://github.com/getsentry/dependency/blob/main/CHANGELOG.md#0460)', + ' - [diff](https://github.com/getsentry/dependency/compare/cli@0.45.0...cli@0.46.0)', '') | Out-File "$testCasePath/CHANGELOG.md" + + pwsh -WorkingDirectory $testCasePath -File "$PSScriptRoot/../scripts/update-changelog.ps1" ` + -Name 'Dependency' ` + -PR 'https://github.com/getsentry/dependant/pulls/123' ` + -RepoUrl 'https://github.com/getsentry/dependency' ` + -MainBranch 'main' ` + -OldTag 'cli@0.46.0' ` + -NewTag 'cli@0.47.0' ` + -OldVersion '0.46.0' ` + -NewVersion '0.47.0' ` + -Section 'Dependencies' + + $content = Get-Content "$testCasePath/CHANGELOG.md" + $content | Should -Contain '- Bump Dependency from v0.45.0 to v0.47.0 ([#100](https://github.com/getsentry/dependant/pulls/100), [#123](https://github.com/getsentry/dependant/pulls/123))' + $content | Should -Contain ' - [changelog](https://github.com/getsentry/dependency/blob/main/CHANGELOG.md#0470)' + $content | Should -Contain ' - [diff](https://github.com/getsentry/dependency/compare/cli@0.45.0...cli@0.47.0)' + } + + It 'should show the tag when the old version is unknown' { + @('# Changelog', '', '## Unreleased', '', '### Dependencies', '', '- Existing entry', '') | Out-File "$testCasePath/CHANGELOG.md" + + pwsh -WorkingDirectory $testCasePath -File "$PSScriptRoot/../scripts/update-changelog.ps1" ` + -Name 'Dependency' ` + -PR 'https://github.com/getsentry/dependant/pulls/123' ` + -RepoUrl 'https://github.com/getsentry/dependency' ` + -MainBranch 'main' ` + -OldTag 'logger@0.46.0' ` + -NewTag 'cli@0.47.0' ` + -NewVersion '0.47.0' ` + -Section 'Dependencies' + + Get-Content "$testCasePath/CHANGELOG.md" | Should -Contain '- Bump Dependency from logger@0.46.0 to v0.47.0 ([#123](https://github.com/getsentry/dependant/pulls/123))' + } + } } diff --git a/updater/tests/update-dependency.Tests.ps1 b/updater/tests/update-dependency.Tests.ps1 index 4690804..d8b50f7 100644 --- a/updater/tests/update-dependency.Tests.ps1 +++ b/updater/tests/update-dependency.Tests.ps1 @@ -56,6 +56,50 @@ Describe ('update-dependency') { Get-Content $testFile | Should -Be @("repo=$repo", 'version=3.2.1') } + It 'version pattern match with prefixed tags' { + $testFile = "$testDir/test.properties" + $repo = 'https://github.com/getsentry/toolkit' + @("repo=$repo", 'version=cli@0.45.0') | Out-File $testFile + $stdout = UpdateDependency $testFile '^cli@(?0\.46\.[0-9]+)$' + Get-Content $testFile | Should -Be @("repo=$repo", 'version=cli@0.46.0') + $stdout | Should -Contain 'originalVersion=0.45.0' + $stdout | Should -Contain 'latestTag=cli@0.46.0' + $stdout | Should -Contain 'latestVersion=0.46.0' + $stdout | Should -Contain 'latestTagNice=v0.46.0' + } + + It 'will not update from a later prefixed release to an earlier release' { + $testFile = "$testDir/test.properties" + $repo = 'https://github.com/getsentry/toolkit' + @("repo=$repo", 'version=cli@99.0.0') | Out-File $testFile + UpdateDependency $testFile '^cli@(?0\.46\.[0-9]+)$' + Get-Content $testFile | Should -Be @("repo=$repo", 'version=cli@99.0.0') + } + + It 'reads the prefix of the original tag regardless of case' { + $testFile = "$testDir/test.properties" + $repo = 'https://github.com/getsentry/toolkit' + @("repo=$repo", 'version=cli@99.0.0') | Out-File $testFile + UpdateDependency $testFile '^CLI@(?0\.46\.[0-9]+)$' + Get-Content $testFile | Should -Be @("repo=$repo", 'version=cli@99.0.0') + } + + It 'fails when no matching tag has a semantic version' { + $testFile = "$testDir/test.properties" + $repo = 'https://github.com/getsentry/toolkit' + @("repo=$repo", 'version=cli@0.45.0') | Out-File $testFile + { UpdateDependency $testFile '^cli@0\.46\.[0-9]+$' 3>$null } | Should -Throw '*Found no tags with a semantic version*' + } + + It 'does not read a tag without the prefix as a version' { + $testFile = "$testDir/test.properties" + $repo = 'https://github.com/getsentry/toolkit' + @("repo=$repo", 'version=99.0.0') | Out-File $testFile + $stdout = UpdateDependency $testFile '^cli@(?0\.46\.[0-9]+)$' + Get-Content $testFile | Should -Be @("repo=$repo", 'version=cli@0.46.0') + $stdout | Should -Contain 'originalVersion=' + } + It 'will not update from a later release to an earlier release' { $testFile = "$testDir/test.properties" $repo = 'https://github.com/getsentry/sentry-java'