Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/script-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ jobs:
- run: Invoke-Pester
working-directory: updater
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}

danger:
name: Danger JS Tests
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ To update your existing Danger workflows:

### Features

- Updater now supports filtering releases by GitHub release title patterns, e.g. to support release channels ([#117](https://github.com/getsentry/github-workflows/pull/117))
- Updater now supports dependencies without changelog files by falling back to git commit messages ([#116](https://github.com/getsentry/github-workflows/pull/116))
- Danger - Improve conventional commit scope handling, and non-conventional PR title support ([#105](https://github.com/getsentry/github-workflows/pull/105))
- Add Proguard artifact endpoint for Android builds in sentry-server ([#100](https://github.com/getsentry/github-workflows/pull/100))
Expand Down
15 changes: 15 additions & 0 deletions updater/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ jobs:
pattern: '^1\.' # Limit to major version '1'
api-token: ${{ secrets.CI_DEPLOY_KEY }}

# Update to stable releases only by filtering GitHub release titles
cocoa-stable:
runs-on: ubuntu-latest
steps:
- uses: getsentry/github-workflows/updater@v3
with:
path: modules/sentry-cocoa
name: Cocoa SDK (Stable)
gh-title-pattern: '\(Stable\)$' # Only releases with "(Stable)" suffix
api-token: ${{ secrets.CI_DEPLOY_KEY }}

# Update a properties file
cli:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -91,6 +102,10 @@ jobs:
* type: string
* required: false
* default: ''
* `gh-title-pattern`: RegEx pattern to match against GitHub release titles. Only releases with matching titles will be considered. Useful for filtering to specific release channels (e.g., stable releases).
* type: string
* required: false
* default: ''
* `changelog-entry`: Whether to add a changelog entry for the update.
* type: boolean
* required: false
Expand Down
12 changes: 11 additions & 1 deletion updater/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ inputs:
description: 'RegEx pattern that will be matched against available versions when picking the latest one.'
required: false
default: ''
gh-title-pattern:
description: 'RegEx pattern to match against GitHub release titles. Only releases with matching titles will be considered.'
required: false
default: ''
changelog-entry:
description: 'Whether to add a changelog entry for the update.'
required: false
Expand Down Expand Up @@ -107,7 +111,9 @@ runs:
env:
DEPENDENCY_PATH: ${{ inputs.path }}
DEPENDENCY_PATTERN: ${{ inputs.pattern }}
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Pattern $env:DEPENDENCY_PATTERN
GH_TITLE_PATTERN: ${{ inputs.gh-title-pattern }}
GH_TOKEN: ${{ inputs.api-token }}
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Pattern $env:DEPENDENCY_PATTERN -GhTitlePattern $env:GH_TITLE_PATTERN

- name: Get the base repo info
if: steps.target.outputs.latestTag != steps.target.outputs.originalTag
Expand Down Expand Up @@ -164,6 +170,8 @@ runs:
- name: Get target changelog
if: ${{ ( steps.target.outputs.latestTag != steps.target.outputs.originalTag ) && ( steps.root.outputs.changed == 'false') }}
shell: pwsh
env:
GH_TOKEN: ${{ inputs.api-token }}
run: |
$changelog = ${{ github.action_path }}/scripts/get-changelog.ps1 `
-RepoUrl '${{ steps.target.outputs.url }}' `
Expand Down Expand Up @@ -223,6 +231,7 @@ runs:
shell: pwsh
env:
DEPENDENCY_PATH: ${{ inputs.path }}
GH_TOKEN: ${{ inputs.api-token }}
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Tag '${{ steps.target.outputs.latestTag }}'

- name: Update Changelog
Expand All @@ -231,6 +240,7 @@ runs:
env:
DEPENDENCY_NAME: ${{ inputs.name }}
CHANGELOG_SECTION: ${{ inputs.changelog-section }}
GH_TOKEN: ${{ inputs.api-token }}
run: |
${{ github.action_path }}/scripts/update-changelog.ps1 `
-Name $env:DEPENDENCY_NAME `
Expand Down
149 changes: 73 additions & 76 deletions updater/scripts/update-dependency.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ param(
[Parameter(Mandatory = $true)][string] $Path,
# RegEx pattern that will be matched against available versions when picking the latest one
[string] $Pattern = '',
# RegEx pattern to match against GitHub release titles. Only releases with matching titles will be considered
[string] $GhTitlePattern = '',
# Specific version - if passed, no discovery is performed and the version is set directly
[string] $Tag = ''
)

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version latest
. "$PSScriptRoot/common.ps1"

Expand All @@ -37,31 +40,24 @@ if ($Path -match '^(.+\.cmake)(#(.+))?$') {
$isCMakeFile = $false
}

if (-not (Test-Path $Path ))
{
if (-not (Test-Path $Path )) {
throw "Dependency $Path doesn't exit";
}

# If it's a directory, we consider it a submodule dependendency. Otherwise, it must a properties-style file or a script.
$isSubmodule = (Test-Path $Path -PathType Container)

function SetOutput([string] $name, $value)
{
if (Test-Path env:GITHUB_OUTPUT)
{
function SetOutput([string] $name, $value) {
if (Test-Path env:GITHUB_OUTPUT) {
"$name=$value" | Tee-Object $env:GITHUB_OUTPUT -Append
}
else
{
} else {
"$name=$value"
}
}

if (-not $isSubmodule)
{
if (-not $isSubmodule) {
$isScript = $Path -match '\.(ps1|sh)$'
function DependencyConfig ([Parameter(Mandatory = $true)][string] $action, [string] $value = $null)
{
function DependencyConfig ([Parameter(Mandatory = $true)][string] $action, [string] $value = $null) {
if ($isCMakeFile) {
# CMake file handling
switch ($action) {
Expand All @@ -82,64 +78,48 @@ if (-not $isSubmodule)
'set-version' {
Update-CMakeFile $Path $cmakeDep $value
}
Default {
default {
throw "Unknown action $action"
}
}
}
elseif ($isScript)
{
if (Get-Command 'chmod' -ErrorAction SilentlyContinue)
{
} elseif ($isScript) {
if (Get-Command 'chmod' -ErrorAction SilentlyContinue) {
chmod +x $Path
if ($LastExitCode -ne 0)
{
if ($LastExitCode -ne 0) {
throw 'chmod failed';
}
}
try
{
try {
$result = & $Path $action $value
$failed = -not $?
}
catch
{
} catch {
$result = $_
$failed = $true
}
if ($failed)
{
if ($failed) {
throw "Script execution failed: $Path $action $value | output: $result"
}
return $result
}
else
{
switch ($action)
{
'get-version'
{
} else {
switch ($action) {
'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 '^(?<prop>version *= *).*$', "`${prop}$value"
$content | Out-File $Path

$readVersion = (Get-Content $Path -Raw | ConvertFrom-StringData).version

if ("$readVersion" -ne "$value")
{
if ("$readVersion" -ne "$value") {
throw "Update failed - read-after-write yielded '$readVersion' instead of expected '$value'"
}
}
Default
{
default {
throw "Unknown action $action"
}
}
Expand All @@ -150,27 +130,20 @@ if (-not $isSubmodule)
. "$PSScriptRoot/cmake-functions.ps1"
}

if ("$Tag" -eq '')
{
if ($isSubmodule)
{
if ("$Tag" -eq '') {
if ($isSubmodule) {
git submodule update --init --no-fetch --single-branch $Path
Push-Location $Path
try
{
try {
$originalTag = $(git describe --tags)
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
}
finally
{
} finally {
Pop-Location
}
}
else
{
} else {
$originalTag = DependencyConfig 'get-version'
$url = DependencyConfig 'get-repo'

Expand All @@ -179,26 +152,58 @@ if ("$Tag" -eq '')
$tags = $tags | ForEach-Object { ($_ -split '\s+')[1] -replace '^refs/tags/', '' }

$headRef = ($(git ls-remote $url HEAD) -split '\s+')[0]
if ("$headRef" -eq '')
{
if ("$headRef" -eq '') {
throw "Couldn't determine repository head (no ref returned by ls-remote HEAD"
}
$mainBranch = (git ls-remote --heads $url | Where-Object { $_.StartsWith($headRef) }) -replace '.*\srefs/heads/', ''
}

$url = $url -replace '\.git$', ''

if ("$Pattern" -eq '')
{
# Filter by GitHub release titles if pattern is provided
if ("$GhTitlePattern" -ne '') {
Write-Host "Filtering tags by GitHub release title pattern '$GhTitlePattern'"

# Parse GitHub repo owner/name from URL
if ($url -notmatch 'github\.com[:/]([^/]+)/([^/]+?)(?:\.git)?$') {
throw "Could not parse GitHub owner/repo from URL: $url"
}

$owner, $repo = $Matches[1], $Matches[2]

# Fetch releases from GitHub API
$releases = @(gh api "repos/$owner/$repo/releases" --paginate --jq '.[] | {tag_name: .tag_name, name: .name}' | ConvertFrom-Json)
if ($LASTEXITCODE -ne 0) {
throw "Failed to fetch GitHub releases from $owner/$repo (exit code: $LASTEXITCODE)"
}

# Find tags that have matching release titles
$validTags = @{}
foreach ($release in $releases) {
if ($release.name -match $GhTitlePattern) {
$validTags[$release.tag_name] = $true
}
}

# Filter tags to only include those with matching release titles
$originalTagCount = $tags.Length
$tags = @($tags | Where-Object { $validTags.ContainsKey($_) })
Write-Host "GitHub release title filtering: $originalTagCount -> $($tags.Count) tags"

if ($tags.Count -eq 0) {
throw "Found no tags with GitHub releases matching title pattern '$GhTitlePattern'"
}
}

if ("$Pattern" -eq '') {
# Use a default pattern that excludes pre-releases
$Pattern = '^v?([0-9.]+)$'
}

Write-Host "Filtering tags with pattern '$Pattern'"
$tags = $tags -match $Pattern

if ($tags.Length -le 0)
{
if ($tags.Length -le 0) {
throw "Found no tags matching pattern '$Pattern'"
}

Expand All @@ -207,14 +212,11 @@ if ("$Tag" -eq '')
Write-Host "Sorted tags: $tags"
$latestTag = $tags[-1]

if (("$originalTag" -ne '') -and ("$latestTag" -ne '') -and ("$latestTag" -ne "$originalTag"))
{
do
{
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))
{
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
Expand All @@ -224,8 +226,7 @@ if ("$Tag" -eq '')
$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)
{
if ($refOriginal -eq $refLatest) {
Write-Host "Latest tag '$latestTag' points to the same commit as the original tag '$originalTag'. Skipping update."
$latestTag = $originalTag
break
Expand All @@ -241,23 +242,19 @@ if ("$Tag" -eq '')
SetOutput 'url' $url
SetOutput 'mainBranch' $mainBranch

if ("$originalTag" -eq "$latestTag")
{
if ("$originalTag" -eq "$latestTag") {
return
}

$Tag = $latestTag
}

if ($isSubmodule)
{
if ($isSubmodule) {
Write-Host "Updating submodule $Path to $Tag"
Push-Location $Path
git checkout $Tag
Pop-Location
}
else
{
} else {
Write-Host "Updating 'version' in $Path to $Tag"
DependencyConfig 'set-version' $tag
}
Loading
Loading