From 0de5baca00948c091db701345ac19f7869ad8342 Mon Sep 17 00:00:00 2001 From: Nick Josevski Date: Tue, 4 Aug 2026 18:43:11 +1000 Subject: [PATCH 1/2] fix: open a pull request when publishing the homebrew formula The deployment step cloned the tap, committed the regenerated formula and pushed a releases/ branch, then stopped. Nothing ever opened a pull request, so the branch sat unmerged and master kept serving an older formula. The tap has accumulated a branch per release since 0.3.2 while `brew install octopus-cli` has been stuck on 2.20.0. Open the pull request over the GitHub API once the branch is pushed, and treat "a pull request already exists" as success so re-running a release is harmless. Also make the step fail loudly rather than quietly. $LASTEXITCODE is now checked after each git call, ErrorActionPreference is Stop, and the argument guard uses -or rather than ||, which is a pipeline chain operator and was never evaluating as a boolean. Fixes #541 Co-Authored-By: Claude Opus 5 (1M context) --- .octopus/deployment_process.ocl | 70 ++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/.octopus/deployment_process.ocl b/.octopus/deployment_process.ocl index 93459e1e..75b68026 100644 --- a/.octopus/deployment_process.ocl +++ b/.octopus/deployment_process.ocl @@ -74,7 +74,11 @@ step "push-homebrew-formula-updates-to-the-homebrew-taps-repo" { [String]$githubtoken ) - $origin="https://github.com/OctopusDeploy/homebrew-taps" + $ErrorActionPreference = "Stop" + + $repo = "OctopusDeploy/homebrew-taps" + $defaultBranch = "master" + $origin = "https://github.com/$repo" if ($OctopusParameters) { $packageVersion = $OctopusParameters["Octopus.Action.Package[cli].PackageVersion"] @@ -83,18 +87,19 @@ step "push-homebrew-formula-updates-to-the-homebrew-taps-repo" { $gitUserEmail = $OctopusParameters["Publish:HomeBrew:UserEmail"] $githubtoken = $OctopusParameters["Publish:HomeBrew:ApiKey"] - $origin="https://$($gitUserName):$($githubtoken)@github.com/OctopusDeploy/homebrew-taps" + $origin = "https://$($gitUserName):$($githubtoken)@github.com/$repo" } - if (!$packageVersion || !$extractedPath) { + if ([string]::IsNullOrWhiteSpace($packageVersion) -or [string]::IsNullOrWhiteSpace($extractedPath)) { throw "Error: packageVersion or extractedPath are not set" - exit - } else { - write-host "Using: packageVersion $packageVersion from $extractedPath" } + Write-Host "Using: packageVersion $packageVersion from $extractedPath" + git clone --depth 1 $origin octopus-homebrew-taps + if ($LASTEXITCODE -ne 0) { throw "Failed to clone $repo" } + Set-Location octopus-homebrew-taps if ($gitUserName) { @@ -104,12 +109,59 @@ step "push-homebrew-formula-updates-to-the-homebrew-taps-repo" { $branchName = "releases/$packageVersion" git checkout -b $branchName + if ($LASTEXITCODE -ne 0) { throw "Failed to create branch $branchName" } Copy-Item -Path "$extractedPath/homebrew/*" -Filter "*.rb" -Destination "." -Force - git diff-index --quiet HEAD || (git commit -a -m "Update for release $packageVersion" ` - && git push --repo $origin --set-upstream origin $branchName ` - ) + git diff-index --quiet HEAD + if ($LASTEXITCODE -eq 0) { + Write-Host "Formula already matches $packageVersion; nothing to publish." + Set-Location .. + exit 0 + } + + git commit -a -m "Update for release $packageVersion" + if ($LASTEXITCODE -ne 0) { throw "Failed to commit the formula update" } + + git push --repo $origin --set-upstream origin $branchName + if ($LASTEXITCODE -ne 0) { throw "Failed to push $branchName" } + + # Pushing the branch on its own leaves the tap untouched, so open a + # pull request for it. Without this the formula is never updated and + # `brew install octopus-cli` keeps serving the previous release. + $headers = @{ + "Accept" = "application/vnd.github+json" + "X-GitHub-Api-Version" = "2022-11-28" + "Authorization" = "Bearer $githubtoken" + } + + $pullRequest = @{ + title = "Update for release $packageVersion" + head = $branchName + base = $defaultBranch + body = "Automated formula update for octopus-cli $packageVersion." + } | ConvertTo-Json + + try { + $response = Invoke-RestMethod -Method Post -Headers $headers ` + -Uri "https://api.github.com/repos/$repo/pulls" ` + -Body $pullRequest -ContentType "application/json" + + Write-Host "Opened pull request $($response.html_url)" + } + catch { + # A re-run of the same release finds its pull request already open, + # which is not a failure worth stopping the deployment for. + $statusCode = $_.Exception.Response.StatusCode.value__ + $alreadyExists = $statusCode -eq 422 -and $_.ErrorDetails.Message -match "already exists" + + if ($alreadyExists) { + Write-Host "A pull request for $branchName is already open." + } + else { + throw "Failed to open a pull request against $repo`: $($_.Exception.Message)" + } + } Set-Location .. EOT From 8b523025a4f0abdfb7b81e12ad5967913f5ae800 Mon Sep 17 00:00:00 2001 From: Nick Josevski Date: Wed, 5 Aug 2026 15:12:38 +1000 Subject: [PATCH 2/2] fix: force-push the release branch and surface GitHub's error detail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-running a release failed at the push. The step clones master shallowly and branches from it each time, so its commit is a sibling of any existing releases/ rather than a descendant, and a plain push is rejected as non-fast-forward — before the already-exists handling was ever reached. Also throw with the response body. Exception.Message only ever says "Response status code does not indicate success"; the body names the field GitHub rejected. Both verified against a scratch tap under pwsh 7 on Unix. Co-Authored-By: Claude Opus 5 (1M context) --- .octopus/deployment_process.ocl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.octopus/deployment_process.ocl b/.octopus/deployment_process.ocl index 75b68026..028ed434 100644 --- a/.octopus/deployment_process.ocl +++ b/.octopus/deployment_process.ocl @@ -123,7 +123,10 @@ step "push-homebrew-formula-updates-to-the-homebrew-taps-repo" { git commit -a -m "Update for release $packageVersion" if ($LASTEXITCODE -ne 0) { throw "Failed to commit the formula update" } - git push --repo $origin --set-upstream origin $branchName + # Force, because a re-run branches from master again and so its commit is a + # sibling of any existing releases/$packageVersion, not a descendant of it. + # A plain push is rejected as non-fast-forward and the release fails. + git push --force --repo $origin --set-upstream origin $branchName if ($LASTEXITCODE -ne 0) { throw "Failed to push $branchName" } # Pushing the branch on its own leaves the tap untouched, so open a @@ -159,7 +162,10 @@ step "push-homebrew-formula-updates-to-the-homebrew-taps-repo" { Write-Host "A pull request for $branchName is already open." } else { - throw "Failed to open a pull request against $repo`: $($_.Exception.Message)" + # Exception.Message is only ever "Response status code does not indicate + # success"; the response body is what says which field GitHub rejected. + $detail = if ($_.ErrorDetails.Message) { $_.ErrorDetails.Message } else { $_.Exception.Message } + throw "Failed to open a pull request against $repo`: $detail" } }