Skip to content

Commit 24610cb

Browse files
authored
Add combine-prs workflow (#4176)
1 parent 9a3bff0 commit 24610cb

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed

.github/workflows/combine-prs.yml

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
name: 'Combine PRs'
2+
3+
# Controls when the action will run - in this case triggered manually
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
branchPrefix:
8+
description: 'Branch prefix to find combinable PRs based on'
9+
required: true
10+
default: 'dependabot'
11+
mustBeGreen:
12+
description: 'Only combine PRs that are green (status is success)'
13+
required: true
14+
default: 'true'
15+
combineBranchName:
16+
description: 'Name of the branch to combine PRs into'
17+
required: true
18+
default: 'combine-prs-branch'
19+
ignoreLabel:
20+
description: 'Exclude PRs with this label'
21+
required: true
22+
default: 'nocombine'
23+
24+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
25+
jobs:
26+
# This workflow contains a single job called "combine-prs"
27+
combine-prs:
28+
# The type of runner that the job will run on
29+
runs-on: ubuntu-latest
30+
31+
# Steps represent a sequence of tasks that will be executed as part of the job
32+
steps:
33+
- uses: actions/github-script@v3
34+
id: fetch-branch-names
35+
name: Fetch branch names
36+
with:
37+
github-token: ${{secrets.GITHUB_TOKEN}}
38+
script: |
39+
const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {
40+
owner: context.repo.owner,
41+
repo: context.repo.repo
42+
});
43+
branches = [];
44+
prs = [];
45+
base_branch = null;
46+
for (const pull of pulls) {
47+
const branch = pull['head']['ref'];
48+
console.log('Pull for branch: ' + branch);
49+
if (branch.startsWith('${{ github.event.inputs.branchPrefix }}')) {
50+
console.log('Branch matched: ' + branch);
51+
statusOK = true;
52+
if(${{ github.event.inputs.mustBeGreen }}) {
53+
console.log('Checking green status: ' + branch);
54+
const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{ref}/status', {
55+
owner: context.repo.owner,
56+
repo: context.repo.repo,
57+
ref: branch
58+
});
59+
if(statuses.length > 0) {
60+
const latest_status = statuses[0]['state'];
61+
console.log('Validating status: ' + latest_status);
62+
if(latest_status != 'success') {
63+
console.log('Discarding ' + branch + ' with status ' + latest_status);
64+
statusOK = false;
65+
}
66+
}
67+
}
68+
console.log('Checking labels: ' + branch);
69+
const labels = pull['labels'];
70+
for(const label of labels) {
71+
const labelName = label['name'];
72+
console.log('Checking label: ' + labelName);
73+
if(labelName == '${{ github.event.inputs.ignoreLabel }}') {
74+
console.log('Discarding ' + branch + ' with label ' + labelName);
75+
statusOK = false;
76+
}
77+
}
78+
if (statusOK) {
79+
console.log('Adding branch to array: ' + branch);
80+
branches.push(branch);
81+
prs.push('#' + pull['number'] + ' ' + pull['title']);
82+
base_branch = pull['base']['ref'];
83+
}
84+
}
85+
}
86+
87+
if (branches.length == 0) {
88+
core.setFailed('No PRs/branches matched criteria');
89+
return;
90+
}
91+
92+
core.setOutput('base-branch', base_branch);
93+
core.setOutput('prs-string', prs.join('\n'));
94+
95+
combined = branches.join(' ')
96+
console.log('Combined: ' + combined);
97+
return combined
98+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
99+
- uses: actions/[email protected]
100+
with:
101+
fetch-depth: 0
102+
# Creates a branch with other PR branches merged together
103+
- name: Created combined branch
104+
env:
105+
BASE_BRANCH: ${{ steps.fetch-branch-names.outputs.base-branch }}
106+
BRANCHES_TO_COMBINE: ${{ steps.fetch-branch-names.outputs.result }}
107+
COMBINE_BRANCH_NAME: ${{ github.event.inputs.combineBranchName }}
108+
run: |
109+
echo "${{steps.fetch-branch-names.outputs.result}}"
110+
sourcebranches="${BRANCHES_TO_COMBINE%\"}"
111+
sourcebranches="${sourcebranches#\"}"
112+
113+
basebranch="${BASE_BRANCH%\"}"
114+
basebranch="${basebranch#\"}"
115+
116+
git config pull.rebase false
117+
git config user.name github-actions
118+
git config user.email [email protected]
119+
120+
git branch $COMBINE_BRANCH_NAME $basebranch
121+
git checkout $COMBINE_BRANCH_NAME
122+
git pull origin $sourcebranches --no-edit
123+
git push origin $COMBINE_BRANCH_NAME
124+
# Creates a PR with the new combined branch
125+
- uses: actions/github-script@v3
126+
name: Create Combined Pull Request
127+
with:
128+
github-token: ${{secrets.GITHUB_TOKEN}}
129+
script: |
130+
const prString = `${{ steps.fetch-branch-names.outputs.prs-string }}`;
131+
const body = 'This PR was created by the Combine PRs action by combining the following PRs:\n' + prString;
132+
await github.pulls.create({
133+
owner: context.repo.owner,
134+
repo: context.repo.repo,
135+
title: 'Combined PR',
136+
head: '${{ github.event.inputs.combineBranchName }}',
137+
base: '${{ steps.fetch-branch-names.outputs.base-branch }}',
138+
body: body
139+
});

0 commit comments

Comments
 (0)