-
Notifications
You must be signed in to change notification settings - Fork 5
181 lines (160 loc) · 7.96 KB
/
upmerge.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
name: Create upmerge pull requests
# **What it does**: Loops through protected branches and creates pull requests to upmerge them if there are any commits between them.
# **Why we have it**: To automate the process of upmerging branches.
env:
FALLBACK_REVIEWERS: '["brian.bolt@schrodinger.com", "brian.frost@schrodinger.com"]'
on:
# Run every 3 hours on the hour
schedule:
- cron: "0 */3 * * *"
# Trigger on demand
workflow_dispatch:
# Trigger on new commits to release branches for acas repo
push:
branches: [ "release/**" ]
jobs:
create-upmerge-pull-requests:
runs-on: ubuntu-latest
strategy:
matrix:
repo: [ acas, acas-roo-server, racas ]
owner: [ mcneilco ]
steps:
- name: Create pull requests to upmerge branches to main
uses: actions/github-script@v7
with:
github-token: ${{ secrets.ACAS_WORKFLOWS_TOKEN }}
script: |
// Current token user
const getAuthenticatedUserResponse = await github.rest.users.getAuthenticated();
const apiUser = getAuthenticatedUserResponse.data.login;
// Get all protected branches
const protectedBranches = await github.rest.repos.listBranches({
owner: "${{ matrix.owner }}",
repo: "${{ matrix.repo }}",
protected: true
})
// Sort the branches by name but always have master or main at the end
protectedBranches.data.sort((a, b) => {
if (a.name === "master" || a.name === "main") {
return 1
}
if (b.name === "master" || b.name === "main") {
return -1
}
return a.name.localeCompare(b.name)
})
console.log(`Protected branches to check for diff commits: ${protectedBranches.data.map(branch => branch.name).join(", ")}`)
// Loop through the branches and create required PRs based on diffs
for (let i = 0; i < protectedBranches.data.length - 1; i++) {
const sourceBranch = protectedBranches.data[i].name
const targetBranch = protectedBranches.data[i + 1].name
console.log(`Checking commits between ${sourceBranch} to ${targetBranch}`)
// Check if there are diffs between the 2 branches
const diff = await github.rest.repos.compareCommits({
owner: "${{ matrix.owner }}",
repo: "${{ matrix.repo }}",
base: targetBranch,
head: sourceBranch
})
if (diff.data.files.length === 0) {
console.log(`No diffs between ${sourceBranch} and ${targetBranch}`)
continue
} else {
// List the commits in the diff
console.log(`Diffs commits between ${sourceBranch} to ${targetBranch}: ${diff.data.commits.map(commit => commit.sha).join(", ")}}`)
}
// Check if a pull request already exists for these branches
const pullRequests = await github.rest.pulls.list({
owner: "${{ matrix.owner }}",
repo: "${{ matrix.repo }}",
state: "open",
head: sourceBranch,
base: targetBranch
})
// Create a unique set of reviewers: Reviewers for the PR should be anyone with commits in the diff
let reviewers = diff.data.commits
.filter(commit => commit.author !== null)
.map(commit => commit.author.login)
// Fallback to the reviewers if no commits are found
if (reviewers.length === 0) {
reviewers = JSON.parse(process.env.FALLBACK_REVIEWERS);
console.log(`No reviewers found. Falling back to: ${reviewers}`);
}
// Get the most recent commit author to be the assignee
const assignee = reviewers[reviewers.length - 1]
// Remove any duplicate reviewers
let uniqueReviewers = [...new Set(reviewers)]
// If apiUser is a reviewer, remove them but tag them in the description
let addApiUser = false
console.log(`API user: ${apiUser}`)
console.log(`Unique reviewers: ${uniqueReviewers.join(", ")}`)
if (uniqueReviewers.includes(apiUser)) {
console.log(`API user is a reviewer. Removing them from the reviewers list`)
uniqueReviewers.splice(uniqueReviewers.indexOf(apiUser), 1)
addApiUser = true
}
// If the assignee is the pull request author, remove them from the reviewers list
if (assignee === apiUser) {
const index = uniqueReviewers.indexOf(assignee);
if (index !== -1) {
uniqueReviewers.splice(index, 1);
}
}
// If the PR doesn't exist then create it
if (pullRequests.data.length == 0) {
console.log(`Creating pull request from ${sourceBranch} to ${targetBranch}`)
// Create the description for the pull request
const description = "## Description\n\n" +
"This pull request was created by the upmerge workflow.\n\n" +
// Add additional reviewers if the api user is one
(addApiUser ? `## Additional reviewer\n\n*tagged here because the api user for github actions owns the PR and cannot be a reviewer*\n\n@${apiUser}` : "")
// Create the pull request
const createPullRequestResponse = await github.rest.pulls.create({
owner: "${{ matrix.owner }}",
repo: "${{ matrix.repo }}",
title: `⬆️ Upmerge ${sourceBranch} to ${targetBranch}`,
body: description,
head: sourceBranch,
base: targetBranch
})
pullRequest = createPullRequestResponse.data
console.log(`Created pull request ${pullRequest.number}`)
} else {
// Set the pull request to the existing one
var pullRequest = pullRequests.data[0]
console.log(`Pull request ${pullRequest.number} already exists between ${sourceBranch} and ${targetBranch}`)
}
// Add the upmerge label to the pull request
await github.rest.issues.addLabels({
owner: "${{ matrix.owner }}",
repo: "${{ matrix.repo }}",
issue_number: pullRequest.number,
labels: ["upmerge"]
})
// Add the reviewers to the pull request if there are any
// Remove the author from the reviewers list
if (uniqueReviewers.includes(pullRequest.user.login)) {
uniqueReviewers.splice(uniqueReviewers.indexOf(pullRequest.user.login), 1)
}
if (uniqueReviewers.length > 0) {
await github.rest.pulls.requestReviewers({
owner: "${{ matrix.owner }}",
repo: "${{ matrix.repo }}",
pull_number: pullRequest.number,
reviewers: uniqueReviewers
})
console.log(`Added reviewers to pull request ${pullRequest.number}: ${uniqueReviewers.join(", ")}`)
}
// If the PR doesn't already have an assignee then add it
if (pullRequest.assignee == null) {
// Assign the pull request to the assignee
await github.rest.issues.addAssignees({
owner: "${{ matrix.owner }}",
repo: "${{ matrix.repo }}",
issue_number: pullRequest.number,
assignees: [assignee]
})
console.log(`Assigned pull request ${pullRequest.number} to ${assignee}`)
}
}