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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Unreleased

### Features

- Updater - Add `post-update-script` input parameter to run custom scripts after dependency updates ([#130](https://github.com/getsentry/github-workflows/pull/130))
- Scripts receive original and new version as arguments
- Support both bash (`.sh`) and PowerShell (`.ps1`) scripts
- Enables workflows like updating lock files, running code generators, or modifying configuration files

### Fixes

- Updater - Fix boolean input handling for `changelog-entry` parameter and add input validation ([#127](https://github.com/getsentry/github-workflows/pull/127))
Expand Down
45 changes: 45 additions & 0 deletions updater/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ jobs:
target-branch: v7
pattern: '^1\.' # Limit to major version '1'
api-token: ${{ secrets.CI_DEPLOY_KEY }}

# Use a post-update script (sh or ps1) to make additional changes after dependency update
# The script receives two arguments: original version and new version
post-update-script:
runs-on: ubuntu-latest
steps:
- uses: getsentry/github-workflows/updater@v3
with:
path: modules/sentry-cocoa
name: Cocoa SDK
post-update-script: scripts/post-update.sh # Receives args: $1=old version, $2=new version
api-token: ${{ secrets.CI_DEPLOY_KEY }}
```

## Inputs
Expand Down Expand Up @@ -135,12 +147,45 @@ jobs:
* type: string
* required: false
* default: '' (uses repository default branch)
* `post-update-script`: Optional script to run after successful dependency update. Can be a bash script (`.sh`) or PowerShell script (`.ps1`). The script will be executed in the repository root directory before PR creation. The script receives two arguments:
* `$1` / `$args[0]` - The original version (version before update)
* `$2` / `$args[1]` - The new version (version after update)
* type: string
* required: false
* default: ''
* `api-token`: Token for the repo. Can be passed in using `${{ secrets.GITHUB_TOKEN }}`.
If you provide the usual `${{ github.token }}`, no followup CI will run on the created PR.
If you want CI to run on the PRs created by the Updater, you need to provide custom user-specific auth token.
* type: string
* required: true

### Post-Update Script Example

**Bash script** (`scripts/post-update.sh`):

```bash
#!/usr/bin/env bash
set -euo pipefail

ORIGINAL_VERSION="$1"
NEW_VERSION="$2"

echo "Updated from $ORIGINAL_VERSION to $NEW_VERSION"
# Make additional changes to repository files here
```

**PowerShell script** (`scripts/post-update.ps1`):

```powershell
param(
[Parameter(Mandatory = $true)][string] $OriginalVersion,
[Parameter(Mandatory = $true)][string] $NewVersion
)

Write-Output "Updated from $OriginalVersion to $NewVersion"
# Make additional changes to repository files here
```

## Outputs

* `prUrl`: The created/updated PR's URL.
Expand Down
21 changes: 19 additions & 2 deletions updater/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ inputs:
api-token:
description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
required: true
post-update-script:
description: 'Optional script to run after successful dependency update. Can be a bash script (.sh) or PowerShell script (.ps1). The script will be executed in the caller-repo directory before PR creation.'
required: false
default: ''

outputs:
prUrl:
Expand Down Expand Up @@ -102,6 +106,17 @@ runs:
}
Write-Output "✓ PR strategy value '${{ inputs.pr-strategy }}' is valid"

- name: Validate post-update-script
if: ${{ inputs.post-update-script != '' }}
shell: pwsh
run: |
# Validate that inputs.post-update-script contains only safe characters
if ('${{ inputs.post-update-script }}' -notmatch '^[a-zA-Z0-9_\./#\s-]+$') {
Write-Output "::error::Invalid post-update-script path: '${{ inputs.post-update-script }}'. Only alphanumeric characters, spaces, and _-./# are allowed."
exit 1
}
Write-Output "✓ Post-update script path '${{ inputs.post-update-script }}' is valid"

# What we need to accomplish:
# * update to the latest tag
# * create a PR
Expand Down Expand Up @@ -134,8 +149,9 @@ runs:
DEPENDENCY_PATH: ${{ inputs.path }}
DEPENDENCY_PATTERN: ${{ inputs.pattern }}
GH_TITLE_PATTERN: ${{ inputs.gh-title-pattern }}
POST_UPDATE_SCRIPT: ${{ inputs.post-update-script }}
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
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Pattern $env:DEPENDENCY_PATTERN -GhTitlePattern $env:GH_TITLE_PATTERN -PostUpdateScript $env:POST_UPDATE_SCRIPT

- name: Get the base repo info
if: steps.target.outputs.latestTag != steps.target.outputs.originalTag
Expand Down Expand Up @@ -270,8 +286,9 @@ runs:
working-directory: caller-repo
env:
DEPENDENCY_PATH: ${{ inputs.path }}
POST_UPDATE_SCRIPT: ${{ inputs.post-update-script }}
GH_TOKEN: ${{ inputs.api-token }}
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Tag '${{ steps.target.outputs.latestTag }}'
run: ${{ github.action_path }}/scripts/update-dependency.ps1 -Path $env:DEPENDENCY_PATH -Tag '${{ steps.target.outputs.latestTag }}' -PostUpdateScript $env:POST_UPDATE_SCRIPT

- name: Update Changelog
if: ${{ inputs.changelog-entry == 'true' && ( steps.target.outputs.latestTag != steps.target.outputs.originalTag ) && ( steps.root.outputs.changed == 'false') }}
Expand Down
30 changes: 29 additions & 1 deletion updater/scripts/update-dependency.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ param(
# 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 = ''
[string] $Tag = '',
# Optional post-update script to run after successful dependency update
# The script receives the original and new version as arguments
[string] $PostUpdateScript = ''
)

$ErrorActionPreference = 'Stop'
Expand Down Expand Up @@ -249,6 +252,9 @@ if ("$Tag" -eq '') {
$Tag = $latestTag
}

$originalTagForPostUpdate = if ($originalTag) { $originalTag } else { '' }
$newTagForPostUpdate = $Tag

if ($isSubmodule) {
Write-Host "Updating submodule $Path to $Tag"
Push-Location $Path
Expand All @@ -258,3 +264,25 @@ if ($isSubmodule) {
Write-Host "Updating 'version' in $Path to $Tag"
DependencyConfig 'set-version' $tag
}

# Run post-update script if provided
if ("$PostUpdateScript" -ne '') {
Write-Host "Running post-update script: $PostUpdateScript"
if (-not (Test-Path $PostUpdateScript)) {
throw "Post-update script not found: $PostUpdateScript"
}

if (Get-Command 'chmod' -ErrorAction SilentlyContinue) {
chmod +x $PostUpdateScript
if ($LastExitCode -ne 0) {
throw 'chmod failed';
}
}

& $PostUpdateScript "$originalTag" "$tag"
if ($LastExitCode -ne 0) {
throw "Post-update script failed with exit code $LastExitCode"
}

Write-Host '✓ Post-update script completed successfully'
}
122 changes: 121 additions & 1 deletion updater/tests/update-dependency.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
BeforeAll {
function UpdateDependency([Parameter(Mandatory = $true)][string] $path, [string] $pattern = $null, [string] $ghTitlePattern = $null)
function UpdateDependency([Parameter(Mandatory = $true)][string] $path, [string] $pattern = $null, [string] $ghTitlePattern = $null, [string] $postUpdateScript = $null)
{
$params = @{ Path = $path }
if ($pattern) { $params.Pattern = $pattern }
if ($ghTitlePattern) { $params.GhTitlePattern = $ghTitlePattern }
if ($postUpdateScript) { $params.PostUpdateScript = $postUpdateScript }

$result = & "$PSScriptRoot/../scripts/update-dependency.ps1" @params
if (-not $?)
Expand Down Expand Up @@ -488,4 +489,123 @@ FetchContent_Declare(
$version | Should -Match '^8\.'
}
}

Context 'post-update-script' {
It 'runs PowerShell post-update script with version arguments' {
$testFile = "$testDir/test.properties"
$repo = 'https://github.com/getsentry/sentry-cli'
@("repo=$repo", 'version=0') | Out-File $testFile

$postUpdateScript = "$testDir/post-update-test.ps1"
$markerFile = "$testDir/post-update-marker.txt"
@'
param([string] $originalVersion, [string] $newVersion)
"$originalVersion|$newVersion" | Out-File
'@ + " '$markerFile'" | Out-File $postUpdateScript

UpdateDependency $testFile '^0\.' -postUpdateScript $postUpdateScript

# Verify post-update script was executed
Test-Path $markerFile | Should -Be $true
$markerContent = Get-Content $markerFile
$markerContent | Should -Match '^0\|0\.28\.0$'

# Clean up
Remove-Item $markerFile -ErrorAction SilentlyContinue
Remove-Item $postUpdateScript -ErrorAction SilentlyContinue
}

It 'runs bash post-update script with version arguments' -Skip:$IsWindows {
$testFile = "$testDir/test.properties"
$repo = 'https://github.com/getsentry/sentry-cli'
@("repo=$repo", 'version=0') | Out-File $testFile

$postUpdateScript = "$testDir/post-update-test.sh"
$markerFile = "$testDir/post-update-marker.txt"
@"
#!/usr/bin/env bash
set -euo pipefail
echo "`$1|`$2" > '$markerFile'
"@ | Out-File $postUpdateScript

UpdateDependency $testFile '^0\.' -postUpdateScript $postUpdateScript

# Verify post-update script was executed
Test-Path $markerFile | Should -Be $true
$markerContent = Get-Content $markerFile
$markerContent | Should -Match '^0\|0\.28\.0$'

# Clean up
Remove-Item $markerFile -ErrorAction SilentlyContinue
Remove-Item $postUpdateScript -ErrorAction SilentlyContinue
}

It 'fails when post-update script does not exist' {
$testFile = "$testDir/test.properties"
$repo = 'https://github.com/getsentry/sentry-cli'
@("repo=$repo", 'version=0') | Out-File $testFile

$postUpdateScript = "$testDir/nonexistent-script.ps1"

{ UpdateDependency $testFile '^0\.' -postUpdateScript $postUpdateScript } | Should -Throw '*Post-update script not found*'
}

It 'fails when PowerShell post-update script exits with error' {
$testFile = "$testDir/test.properties"
$repo = 'https://github.com/getsentry/sentry-cli'
@("repo=$repo", 'version=0') | Out-File $testFile

$postUpdateScript = "$testDir/failing-post-update.ps1"
@'
param([string] $originalVersion, [string] $newVersion)
throw "Post-update script failed intentionally"
'@ | Out-File $postUpdateScript

{ UpdateDependency $testFile '^0\.' -postUpdateScript $postUpdateScript } | Should -Throw '*Post-update script failed*'

# Clean up
Remove-Item $postUpdateScript -ErrorAction SilentlyContinue
}

It 'fails when bash post-update script exits with error' -Skip:$IsWindows {
$testFile = "$testDir/test.properties"
$repo = 'https://github.com/getsentry/sentry-cli'
@("repo=$repo", 'version=0') | Out-File $testFile

$postUpdateScript = "$testDir/failing-post-update.sh"
@'
#!/usr/bin/env bash
exit 1
'@ | Out-File $postUpdateScript

{ UpdateDependency $testFile '^0\.' -postUpdateScript $postUpdateScript } | Should -Throw '*Post-update script failed*'

# Clean up
Remove-Item $postUpdateScript -ErrorAction SilentlyContinue
}

It 'receives empty string for original version when updating from scratch' {
$testFile = "$testDir/test.properties"
$repo = 'https://github.com/getsentry/sentry-cli'
@("repo=$repo", 'version=') | Out-File $testFile

$postUpdateScript = "$testDir/post-update-empty-original.ps1"
$markerFile = "$testDir/post-update-marker-empty.txt"
@'
param([string] $originalVersion, [string] $newVersion)
"original=[$originalVersion]|new=[$newVersion]" | Out-File
'@ + " '$markerFile'" | Out-File $postUpdateScript

UpdateDependency $testFile '^0\.' -postUpdateScript $postUpdateScript

# Verify post-update script received empty original version
Test-Path $markerFile | Should -Be $true
$markerContent = Get-Content $markerFile
$markerContent | Should -Match 'original=\[\]\|new=\[0\.28\.0\]'

# Clean up
Remove-Item $markerFile -ErrorAction SilentlyContinue
Remove-Item $postUpdateScript -ErrorAction SilentlyContinue
}
}
}