Skip to content

Commit fd66f93

Browse files
authored
Create combinedabot.yml
1 parent 82b4d1d commit fd66f93

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

.github/workflows/combinedabot.yml

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
name: 'Combine Dependabot 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). Set to false if repo does not run checks'
13+
type: boolean
14+
required: true
15+
default: true
16+
combineBranchName:
17+
description: 'Name of the branch to combine PRs into'
18+
required: true
19+
default: 'combine-prs-branch'
20+
ignoreLabel:
21+
description: 'Exclude PRs with this label'
22+
required: true
23+
default: 'nocombine'
24+
25+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
26+
jobs:
27+
# This workflow contains a single job called "combine-prs"
28+
combine-prs:
29+
# The type of runner that the job will run on
30+
runs-on: ubuntu-latest
31+
32+
# Steps represent a sequence of tasks that will be executed as part of the job
33+
steps:
34+
- uses: actions/github-script@v6
35+
id: create-combined-pr
36+
name: Create Combined PR
37+
with:
38+
github-token: ${{secrets.GITHUB_TOKEN}}
39+
script: |
40+
const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {
41+
owner: context.repo.owner,
42+
repo: context.repo.repo
43+
});
44+
let branchesAndPRStrings = [];
45+
let baseBranch = null;
46+
let baseBranchSHA = null;
47+
for (const pull of pulls) {
48+
const branch = pull['head']['ref'];
49+
console.log('Pull for branch: ' + branch);
50+
if (branch.startsWith('${{ github.event.inputs.branchPrefix }}')) {
51+
console.log('Branch matched prefix: ' + branch);
52+
let statusOK = true;
53+
if(${{ github.event.inputs.mustBeGreen }}) {
54+
console.log('Checking green status: ' + branch);
55+
const stateQuery = `query($owner: String!, $repo: String!, $pull_number: Int!) {
56+
repository(owner: $owner, name: $repo) {
57+
pullRequest(number:$pull_number) {
58+
commits(last: 1) {
59+
nodes {
60+
commit {
61+
statusCheckRollup {
62+
state
63+
}
64+
}
65+
}
66+
}
67+
}
68+
}
69+
}`
70+
const vars = {
71+
owner: context.repo.owner,
72+
repo: context.repo.repo,
73+
pull_number: pull['number']
74+
};
75+
const result = await github.graphql(stateQuery, vars);
76+
const [{ commit }] = result.repository.pullRequest.commits.nodes;
77+
const state = commit.statusCheckRollup.state
78+
console.log('Validating status: ' + state);
79+
if(state != 'SUCCESS') {
80+
console.log('Discarding ' + branch + ' with status ' + state);
81+
statusOK = false;
82+
}
83+
}
84+
console.log('Checking labels: ' + branch);
85+
const labels = pull['labels'];
86+
for(const label of labels) {
87+
const labelName = label['name'];
88+
console.log('Checking label: ' + labelName);
89+
if(labelName == '${{ github.event.inputs.ignoreLabel }}') {
90+
console.log('Discarding ' + branch + ' with label ' + labelName);
91+
statusOK = false;
92+
}
93+
}
94+
if (statusOK) {
95+
console.log('Adding branch to array: ' + branch);
96+
const prString = '#' + pull['number'] + ' ' + pull['title'];
97+
branchesAndPRStrings.push({ branch, prString });
98+
baseBranch = pull['base']['ref'];
99+
baseBranchSHA = pull['base']['sha'];
100+
}
101+
}
102+
}
103+
if (branchesAndPRStrings.length == 0) {
104+
core.setFailed('No PRs/branches matched criteria');
105+
return;
106+
}
107+
try {
108+
await github.rest.git.createRef({
109+
owner: context.repo.owner,
110+
repo: context.repo.repo,
111+
ref: 'refs/heads/' + '${{ github.event.inputs.combineBranchName }}',
112+
sha: baseBranchSHA
113+
});
114+
} catch (error) {
115+
console.log(error);
116+
core.setFailed('Failed to create combined branch - maybe a branch by that name already exists?');
117+
return;
118+
}
119+
120+
let combinedPRs = [];
121+
let mergeFailedPRs = [];
122+
for(const { branch, prString } of branchesAndPRStrings) {
123+
try {
124+
await github.rest.repos.merge({
125+
owner: context.repo.owner,
126+
repo: context.repo.repo,
127+
base: '${{ github.event.inputs.combineBranchName }}',
128+
head: branch,
129+
});
130+
console.log('Merged branch ' + branch);
131+
combinedPRs.push(prString);
132+
} catch (error) {
133+
console.log('Failed to merge branch ' + branch);
134+
mergeFailedPRs.push(prString);
135+
}
136+
}
137+
138+
console.log('Creating combined PR');
139+
const combinedPRsString = combinedPRs.join('\n');
140+
let body = '✅ This PR was created by the Combine PRs action by combining the following PRs:\n' + combinedPRsString;
141+
if(mergeFailedPRs.length > 0) {
142+
const mergeFailedPRsString = mergeFailedPRs.join('\n');
143+
body += '\n\n⚠️ The following PRs were left out due to merge conflicts:\n' + mergeFailedPRsString
144+
}
145+
await github.rest.pulls.create({
146+
owner: context.repo.owner,
147+
repo: context.repo.repo,
148+
title: 'Combined PR',
149+
head: '${{ github.event.inputs.combineBranchName }}',
150+
base: baseBranch,
151+
body: body
152+
});

0 commit comments

Comments
 (0)