Thanks to visit codestin.com
Credit goes to github.com

Skip to content

docs: favor autonomous completion in agent guidance #4620

docs: favor autonomous completion in agent guidance

docs: favor autonomous completion in agent guidance #4620

Workflow file for this run

# Automatically backport merged PRs to every actively supported release branch
# when the "backport" label is applied. Works whether the label is added before
# or after the PR is merged.
#
# Target branches are the union of:
# - the latest 3 release/2.X branches (mainline, stable, security), and
# - the active ESR / ESR-1 branches listed in
# scripts/release_channels/esr_versions.txt.
# The set is de-duplicated, so a branch that is both stable and ESR is
# backported once.
#
# Usage:
# 1. Add the "backport" label to a PR targeting main.
# 2. When the PR merges (or if already merged), the workflow detects the
# target release/* branches and opens one cherry-pick PR per branch.
#
# The created backport PRs follow existing repo conventions:
# - Branch: backport/<pr>-to-<version>
# - Title: <original PR title> (#<pr>)
# - Body: links back to the original PR and merge commit
# - Label: backport/v<version> to identify the target release
name: Backport
on:
pull_request_target:
branches:
- main
types:
- closed
- labeled
permissions: {}
# Prevent duplicate runs for the same PR when both 'closed' and 'labeled'
# fire in quick succession.
concurrency:
group: backport-${{ github.event.pull_request.number }}
jobs:
detect:
name: Detect target branches
permissions:
contents: read
if: >
github.event.pull_request.merged == true &&
contains(github.event.pull_request.labels.*.name, 'backport')
runs-on: ubuntu-latest
outputs:
branches: ${{ steps.find.outputs.branches }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Need all refs to discover release branches.
fetch-depth: 0
persist-credentials: false
- name: Find target release branches
id: find
env:
ESR_VERSIONS_FILE: scripts/release_channels/esr_versions.txt
run: |
set -euo pipefail
# Mainline, stable, security: the latest 3 release/2.X branches
# (exact pattern, no suffixes like release/2.31_hotfix), sorted by
# minor version descending.
TOP3=$(
git branch -r \
| grep -E '^\s*origin/release/2\.[0-9]+$' \
| sed 's|.*origin/||' \
| sort -t. -k2 -n -r \
| head -3
)
# ESR and ESR-1: the active ESR versions from the shared source of
# truth. Each entry maps to the release/<version> branch. Skip
# entries whose branch does not exist.
ESR_BRANCHES=""
if [ -f "$ESR_VERSIONS_FILE" ]; then
while read -r RELEASE; do
BRANCH="release/${RELEASE}"
if git show-ref --verify --quiet "refs/remotes/origin/${BRANCH}"; then
ESR_BRANCHES="${ESR_BRANCHES}${BRANCH}"$'\n'
else
echo "::warning::ESR branch ${BRANCH} not found, skipping."
fi
done < <(grep -vE '^\s*(#|$)' "$ESR_VERSIONS_FILE")
else
echo "::warning::${ESR_VERSIONS_FILE} not found, backporting to latest 3 only."
fi
# Union the two sets and de-duplicate.
BRANCHES=$(printf '%s\n%s\n' "$TOP3" "$ESR_BRANCHES" | sed '/^$/d' | sort -u)
if [ -z "$BRANCHES" ]; then
echo "No release branches found."
echo "branches=[]" >> "$GITHUB_OUTPUT"
exit 0
fi
# Convert to JSON array for the matrix.
JSON=$(echo "$BRANCHES" | jq -Rnc '[inputs | select(length > 0)]')
echo "branches=$JSON" >> "$GITHUB_OUTPUT"
echo "Will backport to: $JSON"
backport:
name: "Backport to ${{ matrix.branch }}"
needs: detect
permissions:
contents: write
pull-requests: write
# Required to create the release-specific backport label if missing.
issues: write
if: needs.detect.outputs.branches != '[]'
runs-on: ubuntu-latest
strategy:
matrix:
branch: ${{ fromJson(needs.detect.outputs.branches) }}
fail-fast: false
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_URL: ${{ github.event.pull_request.html_url }}
MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha }}
SENDER: ${{ github.event.sender.login }}
BRANCH: ${{ matrix.branch }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Full history required for cherry-pick.
fetch-depth: 0
persist-credentials: false
- name: Cherry-pick and open PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# Configure git to authenticate pushes with the job token
# since persist-credentials is disabled on checkout.
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
RELEASE_VERSION="$BRANCH"
# Strip the release/ prefix for naming.
VERSION="${RELEASE_VERSION#release/}"
BACKPORT_BRANCH="backport/${PR_NUMBER}-to-${VERSION}"
# Label applied to the backport PR so PRs for a specific release can
# be filtered easily (e.g. backport/v2.34).
BACKPORT_LABEL="backport/v${VERSION}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Idempotency: if a backport PR already exists for this branch
# (open, closed, or merged), there is nothing to do. This is the
# primary guard so a re-run that previously pushed a branch but
# failed before opening the PR still recovers below.
EXISTING_PR=$(gh pr list --head "$BACKPORT_BRANCH" --base "$RELEASE_VERSION" --state all --json number --jq '.[0].number // empty')
if [ -n "$EXISTING_PR" ]; then
echo "PR #${EXISTING_PR} already exists for ${BACKPORT_BRANCH}, skipping."
exit 0
fi
CONFLICTS=false
if git ls-remote --exit-code origin "refs/heads/${BACKPORT_BRANCH}" >/dev/null 2>&1; then
# The branch exists from an earlier run that failed before opening
# the PR. Reuse it as-is and fall through to PR creation rather
# than starting over or bailing out.
echo "Backport branch ${BACKPORT_BRANCH} already exists; reusing it to open the PR."
else
# Create the backport branch from the target release branch.
git checkout -b "$BACKPORT_BRANCH" "origin/${RELEASE_VERSION}"
# Cherry-pick the merge commit. Use -x to record provenance and
# -m1 to pick the first parent (the main branch side).
#
# Every target branch is validated to exist in the detect job, so a
# failure here is a genuine conflict, not a missing branch. Rather
# than abort the whole backport, leave a placeholder commit and open
# a PR with copy-paste resolution steps so it can be finished by
# hand (or closed) instead of recreated from scratch.
if ! git cherry-pick -x -m1 "$MERGE_SHA"; then
echo "::warning::Cherry-pick to ${RELEASE_VERSION} had conflicts."
CONFLICTS=true
# Abort the failed cherry-pick and create an empty commit
# explaining the situation.
git cherry-pick --abort
git commit --allow-empty -m "Cherry-pick of #${PR_NUMBER} requires manual resolution
The automatic cherry-pick of ${MERGE_SHA} to ${RELEASE_VERSION} had conflicts.
Please cherry-pick manually:
git cherry-pick -x -m1 ${MERGE_SHA}"
fi
git push origin "$BACKPORT_BRANCH"
fi
TITLE="${PR_TITLE} (#${PR_NUMBER})"
BODY=$(cat <<EOF
Backport of ${PR_URL}
Original PR: #${PR_NUMBER} — ${PR_TITLE}
Merge commit: ${MERGE_SHA}
Requested by: @${SENDER}
EOF
)
if [ "$CONFLICTS" = true ]; then
TITLE="${TITLE} (conflicts)"
BODY="${BODY}
> [!WARNING]
> The automatic cherry-pick had conflicts.
> Please resolve manually by cherry-picking the original merge commit:
>
> \`\`\`
> git fetch origin ${BACKPORT_BRANCH}
> git checkout ${BACKPORT_BRANCH}
> git reset --hard origin/${RELEASE_VERSION}
> git cherry-pick -x -m1 ${MERGE_SHA}
> # resolve conflicts, then push
> \`\`\`"
fi
# Ensure the release-specific label exists. Best-effort: label
# problems must never prevent the PR from being opened.
gh label create "$BACKPORT_LABEL" \
--description "Backport PR targeting ${RELEASE_VERSION}" \
--color "D93F0B" \
--force || echo "::warning::Could not create label ${BACKPORT_LABEL}."
# Create the PR first, then attach label/assignee/reviewer
# separately. Requesting a review from (or assigning) the PR author
# is rejected by GitHub, and doing it inline with `gh pr create`
# under `set -e` would abort the job and leave no PR. Attaching them
# afterwards as best-effort guarantees the PR always gets created.
NEW_PR_URL=$(
gh pr create \
--base "$RELEASE_VERSION" \
--head "$BACKPORT_BRANCH" \
--title "$TITLE" \
--body "$BODY"
)
gh pr edit "$NEW_PR_URL" --add-label "$BACKPORT_LABEL" || echo "::warning::Could not add label ${BACKPORT_LABEL} to ${NEW_PR_URL}."
gh pr edit "$NEW_PR_URL" --add-assignee "$SENDER" || echo "::warning::Could not assign @${SENDER} to ${NEW_PR_URL}."
gh pr edit "$NEW_PR_URL" --add-reviewer "$SENDER" || echo "::warning::Could not request review from @${SENDER} on ${NEW_PR_URL}."
# Notify the requester on the original PR which backport was opened,
# flagging conflicts that still need manual resolution. Best-effort:
# don't fail the job if the original PR is locked.
COMMENT="Backport to \`${RELEASE_VERSION}\` created: ${NEW_PR_URL}"
if [ "$CONFLICTS" = true ]; then
COMMENT="${COMMENT} (:warning: conflicts need manual resolution)"
fi
gh pr comment "$PR_NUMBER" --body "$COMMENT" || echo "::warning::Failed to comment on #${PR_NUMBER} (PR may be locked)."