Skip to content

Commit 219b5ca

Browse files
committed
ci: add automated backport workflow
This commit introduces an automated GitHub Actions workflow to streamline the backporting process for merged PRs from master to release branches. Key features: - Triggers on merged PRs with labels matching 'backport-v*' pattern (e.g., backport-v0.20.x-branch) - Validates that target branches exist before attempting backport - Creates separate backport PRs for each target branch - Automatically adds 'no-changelog' label to backport PRs - Handles merge conflicts by creating draft PRs with conflict markers - Supports multiple simultaneous backports via multiple labels Workflow steps: 1. Checkout repository with full git history 2. Validate all target branches exist in the remote repository 3. For each valid backport label: - Create a new branch (backport-<pr-num>-to-<target-branch>) - Cherry-pick commits from the master PR - Create a new PR targeting the release branch - Link back to the original PR 4. If conflicts occur, create a draft PR for manual resolution Label format: - Valid: backport-v0.20.x-branch, backport-v0.19.x-branch - Invalid: backport candidate, backport-candidate, backport-needed This automation reduces manual work and ensures consistency in the backporting process while maintaining full visibility and control for maintainers.
1 parent cb3991e commit 219b5ca

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

.github/workflows/backport.yml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Backport
2+
3+
on:
4+
pull_request_target:
5+
types: [closed, labeled]
6+
7+
permissions:
8+
contents: write
9+
pull-requests: write
10+
issues: read
11+
12+
jobs:
13+
backport:
14+
name: Backport PR
15+
runs-on: ubuntu-latest
16+
# Only run on merged PRs with backport labels
17+
# Labels must match pattern: backport-v* (e.g., backport-v0.20.x-branch)
18+
# This excludes labels like "backport candidate" or "backport-candidate"
19+
if: |
20+
github.event.pull_request.merged == true &&
21+
contains(join(github.event.pull_request.labels.*.name, ','), 'backport-v')
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v5
26+
with:
27+
fetch-depth: 0
28+
ref: ${{ github.event.pull_request.base.ref }}
29+
30+
- name: Validate target branches exist
31+
id: validate
32+
shell: bash
33+
run: |
34+
# Extract all backport labels
35+
labels='${{ toJSON(github.event.pull_request.labels.*.name) }}'
36+
echo "All labels: $labels"
37+
38+
# Parse labels and extract branch names
39+
# Only match labels starting with "backport-v" to exclude labels like
40+
# "backport candidate" or "backport-candidate"
41+
backport_labels=$(echo "$labels" | jq -r '.[] | select(startswith("backport-v"))')
42+
43+
if [ -z "$backport_labels" ]; then
44+
echo "::error::No valid backport labels found (must start with 'backport-v')"
45+
exit 1
46+
fi
47+
48+
echo "Found backport labels:"
49+
echo "$backport_labels"
50+
51+
# Check each target branch exists
52+
missing_branches=()
53+
while IFS= read -r label; do
54+
# Extract branch name (everything after "backport-")
55+
branch_name="${label#backport-}"
56+
echo "Checking if branch exists: $branch_name"
57+
58+
# Check if branch exists in remote
59+
if ! git ls-remote --heads origin "$branch_name" | grep -q "$branch_name"; then
60+
echo "::error::Target branch '$branch_name' does not exist (from label '$label')"
61+
missing_branches+=("$branch_name")
62+
else
63+
echo "✓ Branch '$branch_name' exists"
64+
fi
65+
done <<< "$backport_labels"
66+
67+
# Fail if any branches are missing
68+
if [ ${#missing_branches[@]} -gt 0 ]; then
69+
echo "::error::The following target branches do not exist: ${missing_branches[*]}"
70+
echo "::error::Please ensure the branch exists before adding the backport label"
71+
exit 1
72+
fi
73+
74+
echo "✓ All target branches validated successfully"
75+
76+
- name: Create backport PRs
77+
uses: korthout/backport-action@v3
78+
with:
79+
# Automatically detect target branches from labels
80+
# Labels must be in format: backport-v0.20.x-branch (must start with "backport-v")
81+
# This excludes labels like "backport candidate" or "backport-candidate"
82+
# The pattern extracts everything after "backport-" as the branch name
83+
label_pattern: '^backport-(v.+)$'
84+
85+
# GitHub token for creating PRs
86+
github_token: ${{ secrets.GITHUB_TOKEN }}
87+
88+
# PR title format - shows it's a backport with original PR number
89+
pull_title: '[${target_branch}] Backport #${pull_number}: ${pull_title}'
90+
91+
# PR description template - links back to original PR
92+
pull_description: |-
93+
Backport of #${pull_number}
94+
95+
---
96+
97+
${pull_description}
98+
99+
# Automatically add labels to backport PRs
100+
# The 'no-changelog' label skips the release notes check in CI
101+
labels: no-changelog
102+
103+
# Merge strategy - skip merge commits, use cherry-pick only
104+
merge_commits: skip
105+
106+
# If conflicts occur, create a draft PR with conflict markers
107+
experimental: '{"conflict_resolution": "draft_commit_conflicts"}'

0 commit comments

Comments
 (0)