Skip to content

Commit 9027463

Browse files
committed
Support closing PR
1 parent 2027bba commit 9027463

File tree

1 file changed

+88
-57
lines changed

1 file changed

+88
-57
lines changed

index.js

Lines changed: 88 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@ async function run() {
1616

1717
// Merge if they say they have access
1818
if (context.eventName === "issue_comment" || context.eventName === "pull_request_review") {
19-
mergeIfLGTMAndHasAccess()
19+
const bodyLower = getPayloadBody().toLowerCase();
20+
if (bodyLower.includes("lgtm")) {
21+
new Actor().mergeIfHasAccess();
22+
} else if (bodyLower.includes("@github-actions close")) {
23+
new Actor().closeIfHasAccess();
24+
} else {
25+
console.log("Doing nothing because the body does not include a command")
26+
}
2027
}
2128
}
2229

@@ -97,77 +104,101 @@ ${ourSignature}`
97104
}
98105
}
99106

100-
async function mergeIfLGTMAndHasAccess() {
107+
function getPayloadBody() {
101108
const body = context.payload.comment ? context.payload.comment.body : context.payload.review.body
102-
if (!body) {
103-
// For debugging #8
104-
console.log(JSON.stringify(context))
109+
if (body == null) {
110+
throw new Error(`No body found, ${JSON.stringify(context)}`)
105111
}
112+
return body;
113+
}
106114

107-
if (!body || !body.toLowerCase().includes("lgtm")) {
108-
console.log("Comment does not include LGTM ('looks good to me') so not merging")
109-
process.exit(0)
115+
class Actor {
116+
constructor() {
117+
this.cwd = core.getInput('cwd') || process.cwd()
118+
this.octokit = getOctokit(process.env.GITHUB_TOKEN)
119+
this.thisRepo = { owner: context.repo.owner, repo: context.repo.repo }
120+
this.issue = context.payload.issue || context.payload.pull_request
121+
this.sender = context.payload.sender.login
110122
}
111123

112-
// Setup
113-
const cwd = core.getInput('cwd') || process.cwd()
114-
const octokit = getOctokit(process.env.GITHUB_TOKEN)
115-
const thisRepo = { owner: context.repo.owner, repo: context.repo.repo }
116-
const issue = context.payload.issue || context.payload.pull_request
117-
const sender = context.payload.sender.login
124+
async getTargetPRIfHasAccess() {
125+
const { octokit, thisRepo, sender, issue, cwd } = this;
126+
core.info(`\n\nLooking at the ${context.eventName} from ${sender} in '${issue.title}' to see if we can proceed`)
118127

119-
core.info(`\n\nLooking at the ${context.eventName} from ${sender} in '${issue.title}' to see if we can merge`)
128+
const changedFiles = await getPRChangedFiles(octokit, thisRepo, issue.number)
129+
core.info(`Changed files: \n - ${changedFiles.join("\n - ")}`)
120130

121-
const changedFiles = await getPRChangedFiles(octokit, thisRepo, issue.number)
122-
core.info(`Changed files: \n - ${changedFiles.join("\n - ")}`)
131+
const filesWhichArentOwned = getFilesNotOwnedByCodeOwner("@" + sender, changedFiles, cwd)
132+
if (filesWhichArentOwned.length !== 0) {
133+
console.log(`@${sender} does not have access to \n - ${filesWhichArentOwned.join("\n - ")}\n`)
134+
listFilesWithOwners(changedFiles, cwd)
135+
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, you don't have access to these files: ${filesWhichArentOwned.join(", ")}.` })
136+
return
137+
}
123138

124-
const filesWhichArentOwned = getFilesNotOwnedByCodeOwner("@" + sender, changedFiles, cwd)
125-
if (filesWhichArentOwned.length !== 0) {
126-
console.log(`@${sender} does not have access to merge \n - ${filesWhichArentOwned.join("\n - ")}\n`)
127-
listFilesWithOwners(changedFiles, cwd)
128-
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, you don't have access to merge: ${filesWhichArentOwned.join(", ")}.` });
129-
return
139+
const prInfo = await octokit.pulls.get({ ...thisRepo, pull_number: issue.number })
140+
if (prInfo.data.state.toLowerCase() !== "open") {
141+
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR isn't open.` });
142+
return
143+
}
144+
return prInfo
130145
}
131146

132-
// Don't try merge unmergable stuff
133-
const prInfo = await octokit.pulls.get({ ...thisRepo, pull_number: issue.number })
134-
if (!prInfo.data.mergeable) {
135-
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR has merge conflicts. They'll need to be fixed before this can be merged.` });
136-
return
137-
}
147+
async mergeIfHasAccess() {
148+
const prInfo = await this.getTargetPRIfHasAccess()
149+
if (!prInfo) {
150+
return
151+
}
138152

139-
if (prInfo.data.state.toLowerCase() !== "open") {
140-
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR isn't open.` });
141-
return
142-
}
153+
const { octokit, thisRepo, issue, sender } = this;
154+
155+
// Don't try merge unmergable stuff
156+
if (!prInfo.data.mergeable) {
157+
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR has merge conflicts. They'll need to be fixed before this can be merged.` });
158+
return
159+
}
160+
161+
// Don't merge red PRs
162+
const statusInfo = await octokit.repos.listCommitStatusesForRef({ ...thisRepo, ref: prInfo.data.head.sha })
163+
const failedStatus = statusInfo.data
164+
// Check only the most recent for a set of duplicated statuses
165+
.filter(
166+
(thing, index, self) =>
167+
index === self.findIndex((t) => t.target_url === thing.target_url)
168+
)
169+
.find(s => s.state !== "success")
170+
171+
if (failedStatus) {
172+
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR could not be merged because it wasn't green. Blocked by [${failedStatus.context}](${failedStatus.target_url}): '${failedStatus.description}'.` });
173+
return
174+
}
143175

144-
// Don't merge red PRs
145-
const statusInfo = await octokit.repos.listCommitStatusesForRef({ ...thisRepo, ref: prInfo.data.head.sha })
146-
const failedStatus = statusInfo.data
147-
// Check only the most recent for a set of duplicated statuses
148-
.filter(
149-
(thing, index, self) =>
150-
index === self.findIndex((t) => t.target_url === thing.target_url)
151-
)
152-
.find(s => s.state !== "success")
153-
154-
if (failedStatus) {
155-
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR could not be merged because it wasn't green. Blocked by [${failedStatus.context}](${failedStatus.target_url}): '${failedStatus.description}'.` });
156-
return
176+
core.info(`Creating comments and merging`)
177+
try {
178+
// @ts-ignore
179+
await octokit.pulls.merge({ ...thisRepo, pull_number: issue.number, merge_method: core.getInput('merge_method') || 'merge' });
180+
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Merging because @${sender} is a code-owner of all the changes - thanks!` });
181+
} catch (error) {
182+
core.info(`Merging (or commenting) failed:`)
183+
core.error(error)
184+
core.setFailed("Failed to merge")
185+
186+
const linkToCI = `https://github.com/${thisRepo.owner}/${thisRepo.repo}/runs/${process.env.GITHUB_RUN_ID}?check_suite_focus=true`
187+
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `There was an issue merging, maybe try again ${sender}. <a href="${linkToCI}">Details</a>` });
188+
}
157189
}
158190

159-
core.info(`Creating comments and merging`)
160-
try {
161-
// @ts-ignore
162-
await octokit.pulls.merge({ ...thisRepo, pull_number: issue.number, merge_method: core.getInput('merge_method') || 'merge' });
163-
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Merging because @${sender} is a code-owner of all the changes - thanks!` });
164-
} catch (error) {
165-
core.info(`Merging (or commenting) failed:`)
166-
core.error(error)
167-
core.setFailed("Failed to merge")
191+
async closeIfHasAccess() {
192+
const prInfo = await this.getTargetPRIfHasAccess()
193+
if (!prInfo) {
194+
return
195+
}
196+
197+
const { octokit, thisRepo, issue, sender } = this;
168198

169-
const linkToCI = `https://github.com/${thisRepo.owner}/${thisRepo.repo}/runs/${process.env.GITHUB_RUN_ID}?check_suite_focus=true`
170-
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `There was an issue merging, maybe try again ${sender}. <a href="${linkToCI}">Details</a>` });
199+
core.info(`Creating comments and closing`)
200+
await octokit.pulls.update({ ...thisRepo, pull_number: issue.number, state: "closed" });
201+
await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Closing because @${sender} is a code-owner of all the changes.` });
171202
}
172203
}
173204

0 commit comments

Comments
 (0)