(cherry picked from commit c57fe6af02)
Signed-off-by: matttrach <matt.trachier@suse.com>
Co-authored-by: Matt Trachier <matt.trachier@suse.com>
This commit is contained in:
parent
a1e577a99c
commit
7300e97fd2
|
|
@ -0,0 +1,123 @@
|
|||
name: 'Auto Cherry-Pick to Release Branches'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
merge_commit_sha:
|
||||
description: 'The sha of the merge commit from the main PR.'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
create-cherry-pick-prs:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
actions: write
|
||||
steps:
|
||||
- name: 'Wait for merge to settle'
|
||||
run: sleep 10
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 https://github.com/actions/checkout
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 'Find Issues and Create Cherry-Pick PRs'
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 https://github.com/actions/github-script
|
||||
env:
|
||||
MERGE_COMMIT_SHA: ${{ inputs.merge_commit_sha }}
|
||||
with:
|
||||
script: |
|
||||
const execSync = require('child_process').execSync;
|
||||
const owner = github.repository_owner;
|
||||
const repo = github.repository;
|
||||
const mergeCommitSha = process.env.MERGE_COMMIT_SHA;
|
||||
const assignees = ['matttrach', 'jiaqiluo', 'HarrisonWAffel'];
|
||||
|
||||
const { data: associatedPrs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
|
||||
owner,
|
||||
repo,
|
||||
commit_sha: mergeCommitSha
|
||||
});
|
||||
const pr = associatedPrs.find(p => p.base.ref === 'main' && p.merged_at);
|
||||
if (!pr) {
|
||||
core.info(`No merged PR found for commit ${mergeCommitSha}. This may have been a direct push. Exiting.`);
|
||||
return;
|
||||
}
|
||||
core.info(`Found associated PR: #${pr.number}`);
|
||||
|
||||
// https://docs.github.com/en/rest/search/search?apiVersion=2022-11-28#search-issues-and-pull-requests
|
||||
core.info(`Searching for 'internal/main' issue linked to PR #${pr.number}`);
|
||||
const { data: searchResults } = await github.request('GET /search/issues', {
|
||||
q: `is:issue state:open label:"internal/main" repo:${owner}/${repo} in:body #${pr.number}`,
|
||||
advanced_search: true,
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
});
|
||||
if (searchResults.total_count === 0) {
|
||||
core.info(`No 'internal/main' issue found for PR #${pr.number}. Exiting.`);
|
||||
return;
|
||||
}
|
||||
const mainIssue = searchResults.items[0];
|
||||
core.info(`Found main issue: #${mainIssue.number}`);
|
||||
|
||||
// https://docs.github.com/en/rest/issues/sub-issues?apiVersion=2022-11-28#add-sub-issue
|
||||
core.info(`Fetching sub-issues for main issue #${mainIssue.number}`);
|
||||
const { data: subIssues } = await github.request('GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues', {
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: mainIssue.number,
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
});
|
||||
if (subIssues.length === 0) {
|
||||
core.info(`No sub-issues found for issue #${mainIssue.number}. Exiting.`);
|
||||
return;
|
||||
}
|
||||
core.info(`Found ${subIssues.length} sub-issues.`);
|
||||
|
||||
for (const subIssue of subIssues) {
|
||||
const subIssueNumber = subIssue.number;
|
||||
// Find the release label directly on the sub-issue object
|
||||
const releaseLabel = subIssue.labels.find(label => label.name.startsWith('release/v'));
|
||||
if (!releaseLabel) {
|
||||
core.warning(`Sub-issue #${subIssueNumber} has no 'release/v...' label. Skipping.`);
|
||||
continue;
|
||||
}
|
||||
const targetBranch = releaseLabel.name
|
||||
core.info(`Processing sub-issue #${subIssueNumber} for target branch: ${targetBranch}`);
|
||||
const newBranchName = `backport-${pr.number}-${targetBranch.replace(/\//g, '-')}`;
|
||||
execSync(`git config user.name "github-actions[bot]"`);
|
||||
execSync(`git config user.email "github-actions[bot]@users.noreply.github.com"`);
|
||||
execSync(`git fetch origin ${targetBranch}`);
|
||||
execSync(`git checkout -b ${newBranchName} origin/${targetBranch}`);
|
||||
execSync(`git cherry-pick -x ${mergeCommitSha} -X theirs`);
|
||||
execSync(`git push origin ${newBranchName}`);
|
||||
|
||||
core.info(`Creating pull request for branch ${newBranchName} targeting ${targetBranch}...`);
|
||||
const { data: newPr } = await github.rest.pulls.create({
|
||||
owner,
|
||||
repo,
|
||||
title: pr.title,
|
||||
head: newBranchName,
|
||||
base: targetBranch,
|
||||
body: [
|
||||
`This pull request cherry-picks the changes from #${pr.number} into ${targetBranch}`,
|
||||
`Addresses #${subIssueNumber} for #${mainIssue.number}`,
|
||||
`**WARNING!**: to avoid having to resolve merge conflicts this PR is generated with 'git cherry-pick -X theirs'.`,
|
||||
`Please make sure to carefully inspect this PR so that you don't accidentally revert anything!`,
|
||||
`Please add the proper milestone to this PR`,
|
||||
`Copied from main PR:`,
|
||||
`${pr.body}`
|
||||
].join("\n\n")
|
||||
});
|
||||
const prNumber = newPr.number
|
||||
await github.rest.issues.addAssignees({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
assignees: assignees
|
||||
});
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ jobs:
|
|||
`Backport #${prNumber} to ${labelName} for #${parentIssueNumber}`,
|
||||
`Copied from PR:`,
|
||||
`${pr.body}`
|
||||
].join("\n\n")
|
||||
].join("\n\n"),
|
||||
labels: [labelName],
|
||||
assignees: assignees
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue