-
Notifications
You must be signed in to change notification settings - Fork 812
feat: Github Actions Backport PR #5181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces an automated GitHub Actions workflow to create backport pull requests for releases. When a PR is labeled with backport/3.X, the workflow automatically creates a corresponding backport PR targeting the appropriate release branch.
Changes:
- Added a new GitHub Actions workflow that automates the backporting process by cherry-picking changes from labeled PRs to release branches
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pull_request: | ||
| types: [ labeled ] |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using both pull_request and pull_request_target triggers is potentially dangerous. The pull_request_target event runs in the context of the base repository with write permissions, which can be exploited if the workflow checks out code from a fork. Since this workflow uses actions/checkout@v5 with a ref from the base repository (line 50) and fetches from head_repo (line 60), using only pull_request_target would be more appropriate and secure.
| pull_request: | |
| types: [ labeled ] |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| echo "Fetching changes from origin PR..." | ||
| git fetch "https://github.com/${{ steps.pr_info.outputs.head_repo }}" "${{ steps.pr_info.outputs.head_sha }}" |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fetching from an untrusted fork repository (head_repo) could introduce malicious code. If a PR comes from a fork, this fetches commits from that fork's repository. Consider restricting backports to only work when the PR is from the same repository or add validation to ensure head_repo matches the current repository.
| git log --pretty=format:"Co-authored-by: %an <%ae>" HEAD..$HEAD_SHA > coauthors.tmp | ||
|
|
||
| git log --pretty=format:"%(trailers:key=Co-authored-by,valueonly=false,separator=%n)" HEAD..$HEAD_SHA >> coauthors.tmp |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The git log range syntax HEAD..$HEAD_SHA will show commits reachable from HEAD_SHA that are not reachable from HEAD. Since HEAD is checked out to the target release branch and HEAD_SHA is from the source PR, this range is likely empty or incorrect. The correct syntax should be $HEAD_SHA alone (to show all commits in that SHA) or use a proper merge-base to find the common ancestor.
| git log --pretty=format:"Co-authored-by: %an <%ae>" HEAD..$HEAD_SHA > coauthors.tmp | |
| git log --pretty=format:"%(trailers:key=Co-authored-by,valueonly=false,separator=%n)" HEAD..$HEAD_SHA >> coauthors.tmp | |
| git log --pretty=format:"Co-authored-by: %an <%ae>" "$HEAD_SHA" > coauthors.tmp | |
| git log --pretty=format:"%(trailers:key=Co-authored-by,valueonly=false,separator=%n)" "$HEAD_SHA" >> coauthors.tmp |
| git log --pretty=format:"Co-authored-by: %an <%ae>" HEAD..$HEAD_SHA > coauthors.tmp | ||
|
|
||
| git log --pretty=format:"%(trailers:key=Co-authored-by,valueonly=false,separator=%n)" HEAD..$HEAD_SHA >> coauthors.tmp | ||
|
|
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as the previous git log command - the range HEAD..$HEAD_SHA is incorrect. Additionally, this command appends to the same file, potentially duplicating co-author information. Consider using a single git log command or ensuring proper deduplication.
| git log --pretty=format:"Co-authored-by: %an <%ae>" HEAD..$HEAD_SHA > coauthors.tmp | |
| git log --pretty=format:"%(trailers:key=Co-authored-by,valueonly=false,separator=%n)" HEAD..$HEAD_SHA >> coauthors.tmp | |
| git log --pretty=format:"Co-authored-by: %an <%ae>%n%(trailers:key=Co-authored-by,valueonly=false,separator=%n)" "$HEAD_SHA"^! > coauthors.tmp | |
| if git diff --cached --quiet; then | ||
| echo "No changes to commit. Skipping." | ||
| exit 0 | ||
| fi |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this condition is true and the script exits with code 0, subsequent steps (Push backport branch and Create Backport Pull Request) will still execute because the step itself succeeded. This will cause failures in later steps when trying to push a branch that doesn't exist. Consider using continue-on-error with proper conditional checks in subsequent steps, or setting an output flag to skip later steps.
|
|
||
| let title = `[release/${version}] ${{ steps.pr_info.outputs.title }}`; |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The title interpolation uses GitHub Actions expression syntax inside a JavaScript template literal, which won't work correctly. The value ${{ steps.pr_info.outputs.title }} should be extracted as a variable or passed differently. Consider using const title = core.getInput('title') with the value passed as an input parameter, or construct the full title in the shell script before calling this step.
| let title = `[release/${version}] ${{ steps.pr_info.outputs.title }}`; | |
| const prTitle = "${{ steps.pr_info.outputs.title }}"; | |
| let title = `[release/${version}] ${prTitle}`; |
|
|
||
| let title = `[release/${version}] ${{ steps.pr_info.outputs.title }}`; | ||
| if (hasConflicts) { | ||
| title = `[Conflict] ${title}`; | ||
| } | ||
|
|
||
| let body = `[Backport] #${originalPrNumber} -> \`${{ steps.extract.outputs.branch }}\`\n\n`; |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as the title - GitHub Actions expression syntax cannot be directly used inside JavaScript template literals. The value ${{ steps.extract.outputs.branch }} needs to be passed as a proper variable or input parameter.
| let title = `[release/${version}] ${{ steps.pr_info.outputs.title }}`; | |
| if (hasConflicts) { | |
| title = `[Conflict] ${title}`; | |
| } | |
| let body = `[Backport] #${originalPrNumber} -> \`${{ steps.extract.outputs.branch }}\`\n\n`; | |
| const originalTitle = "${{ steps.pr_info.outputs.title }}"; | |
| const targetBranch = "${{ steps.extract.outputs.branch }}"; | |
| let title = `[release/${version}] ${originalTitle}`; | |
| if (hasConflicts) { | |
| title = `[Conflict] ${title}`; | |
| } | |
| let body = `[Backport] #${originalPrNumber} -> \`${targetBranch}\`\n\n`; |
| owner, | ||
| repo, | ||
| title, | ||
| head: "${{ steps.push.outputs.backport_branch }}", |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub Actions expressions in the script block of actions/github-script are evaluated before the JavaScript runs, but referencing step outputs this way inside JavaScript object literals may not work as expected. Consider extracting this value as a const variable at the beginning of the script block for clarity and correctness.
| startsWith(github.event.label.name, 'backport/3.') && | ||
| github.event.action == 'labeled' |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition checks github.event.action == 'labeled' redundantly since the workflow already triggers only on the labeled event type (lines 5 and 7). This check is unnecessary and can be removed for clarity.
| startsWith(github.event.label.name, 'backport/3.') && | |
| github.event.action == 'labeled' | |
| startsWith(github.event.label.name, 'backport/3.') |
|
|
||
| git log --pretty=format:"%(trailers:key=Co-authored-by,valueonly=false,separator=%n)" HEAD..$HEAD_SHA >> coauthors.tmp | ||
|
|
||
| COAUTHORS=$(cat coauthors.tmp | sort | uniq | grep -v "github-actions\[bot\]" | sed '/^$/d') |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using cat to pipe to other commands is an unnecessary use of cat (UUOC). The command can be simplified to sort coauthors.tmp | uniq | grep -v 'github-actions\[bot\]' | sed '/^$/d' for better efficiency.
| COAUTHORS=$(cat coauthors.tmp | sort | uniq | grep -v "github-actions\[bot\]" | sed '/^$/d') | |
| COAUTHORS=$(sort coauthors.tmp | uniq | grep -v "github-actions\[bot\]" | sed '/^$/d') |
给需要 backport 的 pr 添加
backport/3.X标签