Skip to content

Commit 9884e0b

Browse files
committed
Give up cleanly when the recorded target branch is gone
The missing-target backstop returned silently, leaving the PR labeled with no explanation and no path to ever resume. It now posts a comment and drops the label like the other two dead-end cases, routed through a shared abandon_resume helper.
1 parent f7f7d03 commit 9884e0b

2 files changed

Lines changed: 33 additions & 8 deletions

File tree

tests/test_conflict_resolution_resume.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,20 @@ label_line=$(grep -n "remove-label" "$CALLS" | head -1 | cut -d: -f1)
136136
[[ "$base_line" -lt "$label_line" ]] || fail "C: base edit must come before label removal"
137137
ok "C: resume retargets base then removes label"
138138

139+
# ---------------------------------------------------------------------------
140+
echo "### Scenario D: recorded target branch is gone -> give up cleanly"
141+
setup_repo
142+
MOCK_LABELS="autorestack-needs-conflict-resolution"
143+
MOCK_BASE="parent" # matches marker -> not a manual retarget
144+
MOCK_COMMENTS_FILE="$WORK/comments.txt"
145+
{ echo "### conflict"; echo; marker parent ghost-target "$SQUASH"; } > "$MOCK_COMMENTS_FILE"
146+
run_resume
147+
148+
grep -q "remove-label autorestack-needs-conflict-resolution" "$CALLS" || fail "D: label not removed"
149+
grep -q "gh pr comment" "$CALLS" || fail "D: no explanatory comment posted"
150+
grep -q -- "--base" "$CALLS" && fail "D: base must NOT be edited"
151+
[[ "$(git -C "$ORIGIN" rev-parse child)" == "$CHILD_BEFORE" ]] || fail "D: child was pushed"
152+
ok "D: missing target detected, no branch mutation, label removed"
153+
139154
echo
140155
echo "All conflict-resume tests passed 🎉 ($PASS scenarios)"

update-pr-stack.sh

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,16 @@ has_sibling_conflicts() {
207207
return 1 # No siblings with same base
208208
}
209209

210+
# Give up on resuming the stack update: tell the user why on the PR, then drop
211+
# the conflict label so this action stops re-triggering. Used for the dead-end
212+
# cases where we cannot or must not finish automatically.
213+
abandon_resume() {
214+
local PR_BRANCH="$1"
215+
local MESSAGE="$2"
216+
echo "$MESSAGE" | log_cmd gh pr comment "$PR_BRANCH" -F -
217+
log_cmd gh pr edit "$PR_BRANCH" --remove-label "$CONFLICT_LABEL"
218+
}
219+
210220
# Continue processing after user manually resolved conflicts
211221
continue_after_resolution() {
212222
check_env_var "PR_BRANCH"
@@ -229,9 +239,7 @@ continue_after_resolution() {
229239
MARKER=$(read_state_marker "$PR_BRANCH")
230240
if [[ -z "$MARKER" ]]; then
231241
echo "⚠️ No autorestack state marker on $PR_BRANCH; cannot resume safely. Removing the label."
232-
{ echo "ℹ️ autorestack could not find its state marker on this PR, so it will not update the stack automatically. If this PR still needs its base updated, do it manually."; } \
233-
| log_cmd gh pr comment "$PR_BRANCH" -F -
234-
log_cmd gh pr edit "$PR_BRANCH" --remove-label "$CONFLICT_LABEL"
242+
abandon_resume "$PR_BRANCH" "ℹ️ autorestack could not find its state marker on this PR, so it will not update the stack automatically. If this PR still needs its base updated, update its base manually."
235243
return
236244
fi
237245

@@ -249,15 +257,17 @@ continue_after_resolution() {
249257
CURRENT_BASE=$(gh pr view "$PR_BRANCH" --json baseRefName --jq '.baseRefName')
250258
if [[ "$CURRENT_BASE" != "$RECORDED_BASE" ]]; then
251259
echo "⚠️ Base of $PR_BRANCH changed manually ($RECORDED_BASE -> $CURRENT_BASE); not updating the stack."
252-
{ echo "ℹ️ The base branch of this PR was changed manually, so autorestack stepped back and will not update it automatically."; } \
253-
| log_cmd gh pr comment "$PR_BRANCH" -F -
254-
log_cmd gh pr edit "$PR_BRANCH" --remove-label "$CONFLICT_LABEL"
260+
abandon_resume "$PR_BRANCH" "ℹ️ The base branch of this PR was changed manually, so autorestack stepped back and will not update it automatically."
255261
return
256262
fi
257263

258-
# Defense in depth: never act on a target branch that no longer exists.
264+
# Defense in depth: never act on a target branch that no longer exists. The
265+
# action checks out with full history (fetch-depth: 0), so a missing origin
266+
# ref means the branch is really gone, not just unfetched; no future resume
267+
# can succeed, so give up cleanly rather than stranding the PR under the label.
259268
if ! git rev-parse --verify --quiet "origin/$NEW_TARGET" >/dev/null; then
260-
echo "⚠️ Recorded target branch '$NEW_TARGET' no longer exists; leaving $PR_BRANCH untouched."
269+
echo "⚠️ Recorded target branch '$NEW_TARGET' no longer exists; abandoning resume of $PR_BRANCH."
270+
abandon_resume "$PR_BRANCH" "ℹ️ The branch this PR was being retargeted onto (\`$NEW_TARGET\`) no longer exists, so autorestack stepped back. If this PR still needs its base updated, update its base manually."
261271
return
262272
fi
263273

0 commit comments

Comments
 (0)