Skip to content
This repository was archived by the owner on Mar 6, 2024. It is now read-only.

Commit c95e4f3

Browse files
authored
add combine dependabot PRs workflow (#32)
<!-- This is an auto-generated comment: release notes by openai --> ### Summary by OpenAI New Feature: A new GitHub Actions workflow file `.github/workflows/combine-prs.yml` has been added that combines multiple Dependabot PRs into a single branch. The workflow is triggered manually and takes inputs such as branch prefix, must be green, combine branch name, and ignore label. It fetches all the open PRs with the given branch prefix, checks if they are green (if required), and have no ignore label. It then merges all the PRs into a single branch and creates a new PR for it. <!-- end of auto-generated comment: release notes by openai -->
1 parent 8866d26 commit c95e4f3

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed

.github/workflows/combine-prs.yml

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
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+
- name: Set variables
34+
env:
35+
DEFAULT_BRANCH_PREFIX: dependabot
36+
DEFAULT_MUST_BE_GREEN: true
37+
DEFAULT_COMBINE_BRANCH_NAME: combine-prs-branch
38+
DEFAULT_IGNORE_LABEL: nocombine
39+
run: |
40+
echo "BRANCH_PREFIX=${{ github.event.inputs.branchPrefix || env.DEFAULT_BRANCH_PREFIX }}" >> $GITHUB_ENV
41+
echo "MUST_BE_GREEN=${{ github.event.inputs.mustBeGreen || env.DEFAULT_MUST_BE_GREEN }}" >> $GITHUB_ENV
42+
echo "COMBINE_BRANCH_NAME=${{ github.event.inputs.combineBranchName || env.DEFAULT_COMBINE_BRANCH_NAME }}" >> $GITHUB_ENV
43+
echo "IGNORE_LABEL=${{ github.event.inputs.ignoreLabel || env.DEFAULT_IGNORE_LABEL }}" >> $GITHUB_ENV
44+
45+
- uses: actions/github-script@v6
46+
id: fetch-branch-names
47+
name: Fetch branch names
48+
with:
49+
github-token: ${{secrets.GITHUB_TOKEN}}
50+
script: |
51+
const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {
52+
owner: context.repo.owner,
53+
repo: context.repo.repo
54+
});
55+
56+
group_labels = ["go", "python", "terraform"];
57+
branches = {};
58+
59+
base_branch = null;
60+
for (const pull of pulls)
61+
{
62+
const branch = pull['head']['ref'];
63+
console.log('Pull for branch: ' + branch);
64+
if (branch.startsWith('${{ env.BRANCH_PREFIX }}')) {
65+
console.log('Branch matched: ' + branch);
66+
statusOK = true;
67+
if(${{ env.MUST_BE_GREEN}}) {
68+
console.log('Checking green status: ' + branch);
69+
const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{ref}/status', {
70+
owner: context.repo.owner,
71+
repo: context.repo.repo,
72+
ref: branch
73+
});
74+
if(statuses.length > 0) {
75+
const latest_status = statuses[0]['state'];
76+
console.log('Validating status: ' + latest_status);
77+
if(latest_status == 'failure') {
78+
console.log('Discarding ' + branch + ' with status ' + latest_status);
79+
statusOK = false;
80+
}
81+
}
82+
}
83+
console.log('Checking labels: ' + branch);
84+
const labels = pull['labels'];
85+
for(const label of labels) {
86+
const labelName = label['name'];
87+
console.log('Checking label: ' + labelName);
88+
if(labelName == '${{ env.IGNORE_LABEL }}') {
89+
console.log('Discarding ' + branch + ' with label ' + labelName);
90+
statusOK = false;
91+
}
92+
}
93+
94+
if (statusOK === true) {
95+
pr_str = '#' + pull['number'] + ' ' + pull['title']
96+
base_branch = pull['base']['ref'];
97+
for (const label of labels) {
98+
const labelName = label['name'];
99+
if(group_labels.includes(labelName)) {
100+
console.log('Added to ' + labelName);
101+
if (branches[labelName]) {
102+
branches[labelName].push(branch);
103+
} else {
104+
branches[labelName] = [branch];
105+
}
106+
break;
107+
}
108+
}
109+
}
110+
}
111+
}
112+
113+
console.log(branches);
114+
115+
if (branches.length == 0) {
116+
core.setFailed('No PRs/branches matched criteria');
117+
return;
118+
}
119+
120+
core.setOutput('base-branch', base_branch);
121+
core.setOutput('branches-go', (branches["go"] || []).join(' '));
122+
core.setOutput('branches-python', (branches["python"] || []).join(' '));
123+
core.setOutput('branches-terraform', (branches["terraform"] || []).join(' '));
124+
125+
return "ok"
126+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
127+
- uses: actions/checkout@v3
128+
with:
129+
fetch-depth: 0
130+
# Creates a branch with other PR branches merged together
131+
- name: Created combined branch and PR
132+
env:
133+
BASE_BRANCH: ${{ steps.fetch-branch-names.outputs.base-branch }}
134+
BRANCHES_1: ${{ steps.fetch-branch-names.outputs.branches-go }}
135+
BRANCHES_2: ${{ steps.fetch-branch-names.outputs.branches-python }}
136+
BRANCHES_3: ${{ steps.fetch-branch-names.outputs.branches-terraform }}
137+
COMBINE_NAME_1: ${{ env.COMBINE_BRANCH_NAME }}-go
138+
COMBINE_NAME_2: ${{ env.COMBINE_BRANCH_NAME }}-python
139+
COMBINE_NAME_3: ${{ env.COMBINE_BRANCH_NAME }}-terraform
140+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
141+
run: |
142+
set -x
143+
basebranch="${BASE_BRANCH%\"}"
144+
basebranch="${basebranch#\"}"
145+
146+
i=1
147+
for branches in "${!BRANCHES_@}"; do
148+
branches_list=${!branches}
149+
name_from_list=COMBINE_NAME_$i
150+
name=${!name_from_list}
151+
152+
echo "Branches: $branches_list"
153+
if [ -z "$branches_list" ]; then
154+
i=$(( i + 1 ))
155+
continue
156+
fi
157+
158+
sourcebranches="${branches_list%\"}"
159+
sourcebranches="${sourcebranches#\"}"
160+
161+
git config pull.rebase false
162+
git config user.name github-actions
163+
git config user.email [email protected]
164+
165+
git checkout $basebranch
166+
git checkout -b $name
167+
168+
prs_list=""
169+
for branch in ${sourcebranches[@]}; do
170+
if git pull origin $branch --no-ff --no-commit; then
171+
git commit --no-edit
172+
173+
if pr_view=$(gh pr view $branch); then
174+
title=$(echo "$pr_view" | sed -nE 's/^title:\s(.*)$/\1/p')
175+
number=$(echo "$pr_view" | sed -nE 's/^number:\s(.*)$/\1/p')
176+
desc='#'"$number $title"$'\n'
177+
prs_list="$prs_list$desc"
178+
gh pr close $branch -d
179+
fi
180+
181+
else
182+
git merge --abort
183+
fi
184+
done
185+
186+
git push origin $name
187+
i=$(( i + 1 ))
188+
189+
if [ -z "$prs_list" ]; then
190+
continue
191+
fi
192+
193+
prs_string="This PR was created by the Combine PRs action by combining the following PRs:"$'\n'"${prs_list}"
194+
title="Combined PR from dependabot's branch $name"
195+
gh pr create --base $basebranch --head $name --title "$title" --body "$prs_string"
196+
done

0 commit comments

Comments
 (0)