diff --git a/action.yml b/action.yml index 4eb9363..61f9e4c 100644 --- a/action.yml +++ b/action.yml @@ -52,6 +52,7 @@ runs: ACTION_MODE: ${{ steps.check.outputs.mode }} SQUASH_COMMIT: ${{ github.event.pull_request.merge_commit_sha }} MERGED_BRANCH: ${{ github.event.pull_request.head.ref }} + MERGED_PR_NUMBER: ${{ github.event.pull_request.number }} TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} PR_BRANCH: ${{ github.event.pull_request.head.ref }} run: | diff --git a/update-pr-stack.sh b/update-pr-stack.sh index c000f41..2161f6d 100755 --- a/update-pr-stack.sh +++ b/update-pr-stack.sh @@ -45,14 +45,29 @@ has_squash_commit() { && git merge-base --is-ancestor SQUASH_COMMIT "$BRANCH" } -format_branch_list_for_text() { +# Render a conflict ref for the prose. The merged parent branch is shown as a +# "#N" reference that GitHub links to its PR (MERGED_PR_NUMBER comes straight +# from the event payload); the pre-squash trunk state is a bare commit with no +# PR, so it stays in backticks. The bash recipe still uses the raw ref, which +# `git merge` needs. +format_conflict_ref_for_text() { + local ref="$1" + if [[ "$ref" == "origin/$MERGED_BRANCH" && -n "${MERGED_PR_NUMBER:-}" ]]; then + printf '#%s' "$MERGED_PR_NUMBER" + else + printf '`%s`' "$ref" + fi +} + +format_conflict_list_for_text() { + local separator for ((i=1; i<=$#; i++)); do case $i in - 1) format='`%s`';; - $#) format=', and `%s`';; - *) format=', `%s`';; + 1) separator='';; + $#) separator=', and ';; + *) separator=', ';; esac - printf "$format" "${!i}" + printf '%s%s' "$separator" "$(format_conflict_ref_for_text "${!i}")" done } @@ -107,7 +122,7 @@ update_direct_target() { echo "### ⚠️ Automatic update blocked by merge conflicts" echo echo -n "I tried to merge " - format_branch_list_for_text "${CONFLICTS[@]}" + format_conflict_list_for_text "${CONFLICTS[@]}" echo " into this branch while updating the pull request stack and hit conflicts." echo echo "#### How to resolve" @@ -196,13 +211,13 @@ continue_after_resolution() { echo "Current base branch: $OLD_BASE" # The synchronize payload is the child PR, so SQUASH_COMMIT / MERGED_BRANCH / - # TARGET_BRANCH from the original squash-merge run are not in the environment. - # Reconstruct them from the merged parent PR: OLD_BASE is the parent branch, - # and the merged PR whose head is OLD_BASE gives the new target (its base) and - # the squash commit (its merge commit). - local NEW_TARGET SQUASH_HASH - read -r NEW_TARGET SQUASH_HASH < <(gh pr list --head "$OLD_BASE" --state merged \ - --json baseRefName,mergeCommit --jq '.[0] | "\(.baseRefName // "") \(.mergeCommit.oid // "")"') + # TARGET_BRANCH / MERGED_PR_NUMBER from the original squash-merge run are not + # in the environment. Reconstruct them from the merged parent PR: OLD_BASE is + # the parent branch, and the merged PR whose head is OLD_BASE gives the new + # target (its base), the squash commit (its merge commit), and its number. + local NEW_TARGET SQUASH_HASH MERGED_PR_NUMBER + read -r NEW_TARGET SQUASH_HASH MERGED_PR_NUMBER < <(gh pr list --head "$OLD_BASE" --state merged \ + --json baseRefName,mergeCommit,number --jq '.[0] | "\(.baseRefName // "") \(.mergeCommit.oid // "") \(.number // "")"') if [[ -z "$NEW_TARGET" || -z "$SQUASH_HASH" ]]; then echo "⚠️ Could not find where '$OLD_BASE' was merged to; skipping base branch and deletion updates"