fix(release): reuse only an OPEN promote PR, not one in any state - #3424
Conversation
The promote step guarded PR creation with `gh pr view <branch>`, which resolves a pull request by head branch in any state. A closed one satisfied the guard, so creation was skipped while the step still exited 0 — a promotion that reports success and leaves nothing to merge, the same silent-skip shape as the enumeration bug fixed in #3404. STABLE_BRANCH is derived from the stable version, so every rc promoted to that version shares it. Both re-dispatch paths this workflow documents as supported are therefore wedged once any promote PR for that version has been closed: re-dispatching the same rc, and promoting a newer rc to the same version. Neither recovers by reopening the old PR, because the step's own force-push makes its head unreachable and GitHub refuses with "state cannot be changed. The <branch> branch was force-pushed or recreated." Hit live while promoting v1.6.0-rc.4 after #3397 had been closed: the run went green and opened no PR. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
📝 WalkthroughWalkthroughThe release workflow now detects existing open PRs for the stable branch using ChangesRelease PR detection
Estimated code review effort: 1 (Trivial) | ~5 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8).github/workflows/promote-rc.yamlTraceback (most recent call last): Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/promote-rc.yaml (1)
273-279: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winFail closed on PR lookup errors.
gh pr listis only checked for non-empty output here, so an API/auth failure that returns no stdout still falls through togh pr createand can hide the real error. Capture the command status first and exit before treating the result as “no open PR”.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/promote-rc.yaml around lines 273 - 279, Update the PR lookup logic around gh pr list to capture its exit status separately from its output. If the lookup fails, report the error and stop the workflow; only proceed to gh pr create when the lookup succeeds and returns no open PR, preserving the existing message and creation arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/promote-rc.yaml:
- Line 273: Update the PR lookup condition in the promotion workflow to filter
by both STABLE_BRANCH as the head and BASE as the base, and capture the gh pr
list result/status separately so command failures are handled explicitly rather
than treated as an empty result. Only continue the existing “PR exists” logic on
a successful lookup with a matching open PR; propagate or fail on lookup errors.
---
Outside diff comments:
In @.github/workflows/promote-rc.yaml:
- Around line 273-279: Update the PR lookup logic around gh pr list to capture
its exit status separately from its output. If the lookup fails, report the
error and stop the workflow; only proceed to gh pr create when the lookup
succeeds and returns no open PR, preserving the existing message and creation
arguments.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f2cfac93-3469-4425-9117-7f03d693ce00
📒 Files selected for processing (1)
.github/workflows/promote-rc.yaml
| # version. Neither can recover by reopening, since the force-push | ||
| # below makes the old pr's head unreachable and GitHub then refuses | ||
| # the reopen outright ("branch was force-pushed or recreated"). | ||
| if [ -n "$(gh pr list --head "${STABLE_BRANCH}" --state open --json number --jq '.[0].number')" ]; then |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE=".github/workflows/promote-rc.yaml"
# Show the relevant workflow section with line numbers.
sed -n '240,290p' "$FILE" | cat -n
# Search for the PR-listing and PR-creation logic nearby.
rg -n 'gh pr list|gh pr create|BASE|STABLE_BRANCH' "$FILE"Repository: cozystack/cozystack
Length of output: 4456
🏁 Script executed:
python3 - <<'PY'
import subprocess, textwrap, tempfile, os, sys
script = r'''#!/bin/bash
set -euo pipefail
echo before
if [ -n "$(false)" ]; then
echo nonempty
else
echo empty
fi
echo after
'''
p = subprocess.run(["bash", "-lc", script], capture_output=True, text=True)
print("exit:", p.returncode)
print(p.stdout)
print(p.stderr)
PYRepository: cozystack/cozystack
Length of output: 186
Scope the PR lookup to BASE and handle gh errors explicitly.
gh pr list currently matches only on STABLE_BRANCH, so an open PR on the same head but a different base can suppress the PR this run needs. And if gh pr list fails, [ -n "$(…)" ] treats it like “no PR”, which can hide the failure and create duplicates.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/promote-rc.yaml at line 273, Update the PR lookup
condition in the promotion workflow to filter by both STABLE_BRANCH as the head
and BASE as the base, and capture the gh pr list result/status separately so
command failures are handled explicitly rather than treated as an empty result.
Only continue the existing “PR exists” logic on a successful lookup with a
matching open PR; propagate or fail on lookup errors.
What this PR does
The promote step guarded PR creation with
gh pr view <branch>, which resolves a pull request by head branch in any state. A closed one satisfied the guard, so creation was skipped while the step still exited 0 — a promotion that reports success and leaves nothing to merge. Same silent-skip shape as the enumeration bug fixed in #3404: the run is green, the artifact is missing, and nothing says so.STABLE_BRANCHis derived from the stable version (release-${version}), not from the rc number, so every rc promoted to that version shares it. Once any promote PR for a version has been closed, both re-dispatch paths this workflow documents as supported are wedged: re-dispatching the same rc, and promoting a newer rc to the same version. That second one is named in the workflow's own header as the reason a leftover draft is tolerated — the tolerance was implemented for the release draft and missed for the PR.Neither path recovers by reopening the old PR, because the step's own
git checkout -Bplus force-push makes that PR's head unreachable, and GitHub then refuses:The fix asks the question the guard meant to ask — is there an open PR for this head — and creates one otherwise.
Hit live. Promoting
v1.6.0-rc.4after #3397 had been closed: run 29917852639 went green, loggedPR already open for release-1.6.0, and opened no PR. This currently blocks the v1.6.0 release.Verified in both directions against live data, so the change is not vacuous:
release-1.6.0TRUE→ skip (bug)FALSE→ create ✅chore/gitignoreTRUE→ skipTRUE→ skip ✅actionlintexits 0 andzizmorreports no findings. The guard reads${STABLE_BRANCH}as a shell variable from the step'senv:block rather than as a${{ }}expansion insiderun:, so no expression-injection surface is added.Screenshots
N/A — no UI change.
Downstream repositories
Walked the trigger map in
docs/agents/contributing.mdagainst the diff, which is one file:.github/workflows/promote-rc.yaml. The only workflow-related trigger in the map is cozystack/ccp on "change release-prep behaviour in.github/workflows/tags.yaml", which this does not touch. This change also restores the documented behaviour ofpromote-rc.yamlrather than altering its contract, so nothing downstream sees a result different from what the docs already promise.Release note
Summary by CodeRabbit