backport: add pre-merge label-on-comment support; add copilot-instructions and auto-labeler for changelog exemptions (#10211)

* Initial plan

* chore: commit backport.yml pre-merge labeling enhancement

Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com>

* chore: auto-label kind/changelog-not-required for non-shipping PRs; add copilot-instructions.md

Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com>

* chore: add changelog naming convention to copilot-instructions; tighten labeler exclusions

Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com>

* fix: use # as sed delimiter to avoid conflict with | in alternation group

Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com>
This commit is contained in:
Copilot
2026-08-11 15:23:56 -04:00
committed by GitHub
co-authored by kaovilai copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
parent 105350b78b
commit 1832f099f2
3 changed files with 181 additions and 4 deletions
+89 -4
View File
@@ -1,8 +1,21 @@
name: Backport merged pull request
# Automates cherry-picking merged PRs onto release branches.
# - Label a merged PR with e.g. `backport release-1.17` to backport on merge.
# - Or comment `/backport release-1.17` or `/cherrypick release-1.17` on a merged PR.
#
# Pre-merge (open PR):
# An authorized /backport or /cherrypick comment adds one `backport <branch>`
# label per requested branch. These labels are then picked up automatically
# when the PR is merged (see the pull_request_target: closed trigger below).
#
# Post-merge (merged PR):
# - Label a PR with e.g. `backport release-1.17` before merging; the label
# triggers the backport automatically when the PR closes as merged.
# - Comment `/backport release-1.17` or `/cherrypick release-1.17` on an
# already-merged PR to create the backport PR immediately.
#
# In both cases multiple target branches can be space-delimited in a comment:
# /backport release-1.17 release-1.18
#
# See: https://github.com/velero-io/velero/issues/9603
on:
@@ -13,7 +26,78 @@ on:
permissions: {}
# Shared condition for authorized /backport or /cherrypick comments.
# Used by both jobs below to avoid duplicating the gate logic.
env:
AUTHORIZED_COMMENT: >-
${{
github.event_name == 'issue_comment' &&
github.event.issue.pull_request != '' &&
github.event.comment.user.id != 97796249 &&
contains(
fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'),
github.event.comment.author_association
) &&
(
startsWith(github.event.comment.body, '/backport') ||
startsWith(github.event.comment.body, '/cherrypick')
)
}}
jobs:
# ── Pre-merge: convert a /backport or /cherrypick comment into labels ───────
# When the PR is still open the backport-action cannot run (it requires a
# merged commit). Instead, add one `backport <branch>` label per requested
# branch so that the post-merge job picks them up automatically on close.
label-for-backport:
name: Label PR for deferred backport
# Run only when an authorized command is posted on an *open* (unmerged) PR.
if: >
github.repository == 'velero-io/velero' &&
github.event_name == 'issue_comment' &&
github.event.issue.pull_request != '' &&
github.event.issue.state == 'open' &&
github.event.comment.user.id != 97796249 &&
contains(
fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'),
github.event.comment.author_association
) &&
(
startsWith(github.event.comment.body, '/backport') ||
startsWith(github.event.comment.body, '/cherrypick')
)
runs-on: ubuntu-latest
permissions:
issues: write # apply labels to the PR (PRs share the issues API)
steps:
- name: Parse branches and apply labels
env:
COMMENT_BODY: ${{ github.event.comment.body }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.issue.number }}
run: |
# Extract branch names from the first line of the comment.
# Strip the /backport or /cherrypick prefix; what remains is a
# space-delimited list of target branch names.
line=$(printf '%s' "$COMMENT_BODY" | head -n1 | tr -d '\r')
branches=$(printf '%s' "$line" | sed -E 's#^/(backport|cherrypick)[[:space:]]*##')
if [ -z "$branches" ]; then
echo "No target branches specified in comment; nothing to label."
exit 0
fi
for branch in $branches; do
label="backport ${branch}"
echo "Applying label: '${label}'"
# Create the label if it does not exist yet (idempotent).
gh label create "${label}" --repo "${REPO}" --color "0075ca" \
--description "Backport to ${branch}" 2>/dev/null || true
gh issue edit "${PR_NUMBER}" --repo "${REPO}" --add-label "${label}"
done
# ── Post-merge: create backport PRs ─────────────────────────────────────────
backport:
name: Backport pull request
# Exclude comments from the backport-action bot (user id 97796249) to prevent
@@ -28,7 +112,8 @@ jobs:
contains(toJSON(github.event.pull_request.labels.*.name), '"backport ')
) || (
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.issue.pull_request != '' &&
github.event.issue.state == 'closed' &&
github.event.comment.user.id != 97796249 &&
contains(
fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'),
@@ -55,7 +140,7 @@ jobs:
# Remaining text is a space-delimited list of target branches
# (may be empty, falls back to labels).
line=$(printf '%s' "$COMMENT_BODY" | head -n1 | tr -d '\r')
branches=$(printf '%s' "$line" | sed -E 's|^/(backport|cherrypick)[[:space:]]*||')
branches=$(printf '%s' "$line" | sed -E 's#^/(backport|cherrypick)[[:space:]]*##')
echo "branches=${branches}" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@v7