Skip to content

Commit 008ae93

Browse files
[infra] Improve cherry-pick workflow (#234)
1 parent 01ada7b commit 008ae93

File tree

2 files changed

+40
-73
lines changed

2 files changed

+40
-73
lines changed

.github/workflows/prs_create-cherry-pick-pr.yml

+18-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Cherry pick onto target branch
1+
name: Cherry pick onto target branches
22

33
on:
44
pull_request_target:
@@ -11,17 +11,18 @@ on:
1111
permissions: {}
1212

1313
jobs:
14-
detect_cherry_pick_target:
14+
detect_cherry_pick_targets:
1515
runs-on: ubuntu-latest
16-
name: Detect cherry-pick target branch
16+
name: Detect cherry-pick targets
1717
permissions:
1818
issues: write
1919
pull-requests: write
2020
contents: write
2121
if: ${{ contains(github.event.pull_request.labels.*.name, 'needs cherry-pick') && github.event.pull_request.merged == true }}
2222
outputs:
23-
targetBranch: ${{ steps.detect.outputs.TARGET_BRANCH }}
24-
transferLabels: ${{ steps.detect.outputs.TRANSFER_LABELS }}
23+
targetBranches: ${{ steps.detect.outputs.TARGET_BRANCHES }}
24+
reviewers: ${{ steps.detect.outputs.REVIEWERS }}
25+
labels: ${{ steps.detect.outputs.LABELS }}
2526
steps:
2627
- name: Check out mui-public repo
2728
id: checkout
@@ -40,12 +41,15 @@ jobs:
4041
open_cherry_pick_pr:
4142
runs-on: ubuntu-latest
4243
name: Open cherry-pick PR with target branch
44+
if: needs.detect_cherry_pick_targets.outputs.targetBranches != ''
45+
strategy:
46+
matrix:
47+
branch: ${{ needs.detect_cherry_pick_targets.outputs.targetBranches }}
4348
permissions:
4449
issues: write
4550
pull-requests: write
4651
contents: write
47-
needs: detect_cherry_pick_target
48-
if: needs.detect_cherry_pick_target.outputs.targetBranch != ''
52+
needs: detect_cherry_pick_targets
4953
steps:
5054
- name: Checkout
5155
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -56,8 +60,13 @@ jobs:
5660
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5761
uses: carloscastrojumo/github-cherry-pick-action@503773289f4a459069c832dc628826685b75b4b3 # v1.0.10
5862
with:
59-
branch: ${{ needs.detect_cherry_pick_target.outputs.targetBranch }}
63+
# the action will run for each value in matrix.branch
64+
branch: ${{ matrix.branch }}
6065
body: 'Cherry-pick of #{old_pull_request_id}'
6166
cherry-pick-branch: ${{ format('cherry-pick-{0}', github.event.number) }}
6267
title: '{old_title} (@${{ github.event.pull_request.user.login }})'
63-
labels: ${{ needs.detect_cherry_pick_target.outputs.transferLabels }}
68+
# assigning the original reviewers to the new PR
69+
reviewers: ${{ needs.detect_cherry_pick_targets.outputs.reviewers }}
70+
# instead of inheriting labels (including target branch label, etc.), we filter and set the labels explicitly
71+
inherit_labels: false
72+
labels: ${{ needs.detect_cherry_pick_targets.outputs.labels }}

.github/workflows/scripts/prs/detectTargetBranch.js

+22-64
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @ts-check
22
const vBranchRegex = /^v\d{1,3}\.x$/;
3-
const transferLabels = ['cherry-pick'];
3+
const targetBranches = [];
44

55
/**
66
* @param {Object} params
@@ -22,90 +22,48 @@ module.exports = async ({ core, context, github }) => {
2222

2323
core.info(`>>> PR fetched: ${pr.number}`);
2424

25-
const targetLabels = pr.labels
26-
?.map((label) => label.name)
27-
.filter((label) => vBranchRegex.test(label));
25+
const prLabels = pr.labels.map((label) => label.name);
26+
27+
// filter the target labels from the original PR
28+
const targetLabels = prLabels.filter((label) => vBranchRegex.test(label));
29+
const otherLabels = prLabels.filter(
30+
(label) => label !== 'needs cherry-pick' && !vBranchRegex.test(label),
31+
);
2832

2933
if (targetLabels.length === 0) {
3034
// there was no target branch present
31-
core.info('>>> No target branch label found');
35+
core.info('>>> No target label found');
3236

3337
if (vBranchRegex.test(pr.head_ref)) {
3438
// the branch this is coming from is a version branch, so the cherry-pick target should be master
3539
core.info('>>> Head Ref is a version branch, setting `master` as target');
36-
core.setOutput('TARGET_BRANCH', 'master');
37-
core.setOutput('TRANSFER_LABELS', transferLabels.join(','));
40+
core.setOutput('TARGET_BRANCHES', 'master');
3841
return;
3942
}
4043

41-
core.setOutput('TARGET_BRANCH', '');
42-
core.setOutput('TRANSFER_LABELS', transferLabels.join(','));
44+
// the PR is not coming from a version branch
45+
core.setOutput('TARGET_BRANCHES', '');
4346
return;
4447
}
4548

4649
core.info(`>>> Target labels found: ${targetLabels.join(', ')}`);
47-
let target = '';
48-
49-
// there was a target branch label present
50-
// filter the highest available target number and remove the others from the PR when present
51-
if (targetLabels.length > 1) {
52-
core.info(`>>> Multiple target labels found.`);
53-
targetLabels.sort((a, b) => {
54-
const aNum = parseInt(a.match(/\d+/)[0], 10);
55-
const bNum = parseInt(b.match(/\d+/)[0], 10);
56-
return bNum - aNum;
57-
});
58-
59-
target = targetLabels.shift();
60-
61-
core.info(`>>> Sorting and setting the highest as 'TARGET_BRANCH' output.`);
62-
core.setOutput('TARGET_BRANCH', target);
63-
64-
// since we have multiple targets we need to add the "needs cherry-pick" label
65-
// this makes this workflow de-facto recursive
66-
transferLabels.push('needs cherry-pick');
6750

68-
// add the other targets to the transfer labels
69-
transferLabels.push(...targetLabels);
70-
core.setOutput('TRANSFER_LABELS', transferLabels.join(','));
71-
72-
// the others will be removed from the PR
73-
core.info(`>>> Removing the other target labels from the PR`);
74-
for (const label of targetLabels) {
75-
await github.rest.issues.removeLabel({
76-
owner,
77-
repo,
78-
issue_number: pullNumber,
79-
name: label,
80-
});
81-
}
82-
83-
core.info(`>>> Creating explanatory comment on PR`);
84-
await github.rest.issues.createComment({
85-
owner,
86-
repo,
87-
issue_number: pullNumber,
88-
body: [
89-
`The target branch for the cherry-pick PR has been set to \`${target}\`.`,
90-
`Branches that will be created after merging are: ${targetLabels.join(', ')}`,
91-
`Thank you!`,
92-
].join('\n\n'),
93-
});
94-
return;
95-
}
51+
// get a list of the original reviewers
52+
const reviewers = pr.requested_reviewers.map((reviewer) => reviewer.login);
53+
core.info(`>>> Reviewers from original PR: ${reviewers.join(', ')}`);
9654

97-
core.info(`>>> Removing the "needs cherry-pick" label from the PR`);
98-
await github.rest.issues.removeLabel({
55+
core.info(`>>> Creating explanatory comment on PR`);
56+
await github.rest.issues.createComment({
9957
owner,
10058
repo,
10159
issue_number: pullNumber,
102-
name: 'needs cherry-pick',
60+
body: `Cherry-pick PRs will be created targeting branches: ${targetLabels.join(', ')}`,
10361
});
10462

105-
target = targetLabels[0];
106-
core.info(`>>> Setting found 'TARGET_BRANCH' output.`);
107-
core.setOutput('TARGET_BRANCH', target);
108-
core.setOutput('TRANSFER_LABELS', transferLabels.join(','));
63+
// set the target branches as output to be used as an input for the next step
64+
core.setOutput('TARGET_BRANCHES', targetLabels.join(','));
65+
core.setOutput('LABELS', ['cherry-pick', ...otherLabels].join(','));
66+
core.setOutput('REVIEWERS', reviewers.join(','));
10967
} catch (error) {
11068
core.error(`>>> Workflow failed with: ${error.message}`);
11169
core.setFailed(error.message);

0 commit comments

Comments
 (0)