Skip to content

Commit fd8082a

Browse files
authored
ci(workflow): add Combine PRs workflow
1 parent 43b94af commit fd8082a

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+
if (branches.length == 0) {
87+
core.setFailed('No PRs/branches matched criteria');
88+
return;
89+
}
90+
core.setOutput('base-branch', base_branch);
91+
core.setOutput('prs-string', prs.join('\n'));
92+
93+
combined = branches.join(' ')
94+
console.log('Combined: ' + combined);
95+
return combined
96+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
97+
- uses: actions/[email protected]
98+
with:
99+
fetch-depth: 0
100+
# Creates a branch with other PR branches merged together
101+
- name: Created combined branch
102+
env:
103+
BASE_BRANCH: ${{ steps.fetch-branch-names.outputs.base-branch }}
104+
BRANCHES_TO_COMBINE: ${{ steps.fetch-branch-names.outputs.result }}
105+
COMBINE_BRANCH_NAME: ${{ github.event.inputs.combineBranchName }}
106+
run: |
107+
echo "$BRANCHES_TO_COMBINE"
108+
sourcebranches="${BRANCHES_TO_COMBINE%\"}"
109+
sourcebranches="${sourcebranches#\"}"
110+
111+
basebranch="${BASE_BRANCH%\"}"
112+
basebranch="${basebranch#\"}"
113+
114+
git config pull.rebase false
115+
git config user.name github-actions
116+
git config user.email [email protected]
117+
118+
git branch $COMBINE_BRANCH_NAME $basebranch
119+
git checkout $COMBINE_BRANCH_NAME
120+
git pull origin $sourcebranches --no-edit
121+
git push origin $COMBINE_BRANCH_NAME
122+
# Creates a PR with the new combined branch
123+
- uses: actions/github-script@v3
124+
name: Create Combined Pull Request
125+
env:
126+
PRS_STRING: ${{ steps.fetch-branch-names.outputs.prs-string }}
127+
with:
128+
github-token: ${{secrets.GITHUB_TOKEN}}
129+
script: |
130+
const prString = process.env.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)