diff --git a/index.js b/index.js
index 3f11005c..2881452e 100644
--- a/index.js
+++ b/index.js
@@ -16,7 +16,14 @@ async function run() {
// Merge if they say they have access
if (context.eventName === "issue_comment" || context.eventName === "pull_request_review") {
- mergeIfLGTMAndHasAccess()
+ const bodyLower = getPayloadBody().toLowerCase();
+ if (bodyLower.includes("lgtm")) {
+ new Actor().mergeIfHasAccess();
+ } else if (bodyLower.includes("@github-actions close")) {
+ new Actor().closeIfHasAccess();
+ } else {
+ console.log("Doing nothing because the body does not include a command")
+ }
}
}
@@ -104,77 +111,101 @@ function pathListToMarkdown(files) {
return files.map(i => `* [\`${i}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/tree/HEAD${i})`).join("\n");
}
-async function mergeIfLGTMAndHasAccess() {
+function getPayloadBody() {
const body = context.payload.comment ? context.payload.comment.body : context.payload.review.body
- if (!body) {
- // For debugging #8
- console.log(JSON.stringify(context))
+ if (body == null) {
+ throw new Error(`No body found, ${JSON.stringify(context)}`)
}
+ return body;
+}
- if (!body || !body.toLowerCase().includes("lgtm")) {
- console.log("Comment does not include LGTM ('looks good to me') so not merging")
- process.exit(0)
+class Actor {
+ constructor() {
+ this.cwd = core.getInput('cwd') || process.cwd()
+ this.octokit = getOctokit(process.env.GITHUB_TOKEN)
+ this.thisRepo = { owner: context.repo.owner, repo: context.repo.repo }
+ this.issue = context.payload.issue || context.payload.pull_request
+ this.sender = context.payload.sender.login
}
- // Setup
- const cwd = core.getInput('cwd') || process.cwd()
- const octokit = getOctokit(process.env.GITHUB_TOKEN)
- const thisRepo = { owner: context.repo.owner, repo: context.repo.repo }
- const issue = context.payload.issue || context.payload.pull_request
- const sender = context.payload.sender.login
+ async getTargetPRIfHasAccess() {
+ const { octokit, thisRepo, sender, issue, cwd } = this;
+ core.info(`\n\nLooking at the ${context.eventName} from ${sender} in '${issue.title}' to see if we can proceed`)
- core.info(`\n\nLooking at the ${context.eventName} from ${sender} in '${issue.title}' to see if we can merge`)
+ const changedFiles = await getPRChangedFiles(octokit, thisRepo, issue.number)
+ core.info(`Changed files: \n - ${changedFiles.join("\n - ")}`)
- const changedFiles = await getPRChangedFiles(octokit, thisRepo, issue.number)
- core.info(`Changed files: \n - ${changedFiles.join("\n - ")}`)
+ const filesWhichArentOwned = getFilesNotOwnedByCodeOwner("@" + sender, changedFiles, cwd)
+ if (filesWhichArentOwned.length !== 0) {
+ console.log(`@${sender} does not have access to \n - ${filesWhichArentOwned.join("\n - ")}\n`)
+ listFilesWithOwners(changedFiles, cwd)
+ await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, you don't have access to these files: ${pathListToMarkdown(filesWhichArentOwned)}.` })
+ return
+ }
- const filesWhichArentOwned = getFilesNotOwnedByCodeOwner("@" + sender, changedFiles, cwd)
- if (filesWhichArentOwned.length !== 0) {
- console.log(`@${sender} does not have access to merge \n - ${filesWhichArentOwned.join("\n - ")}\n`)
- listFilesWithOwners(changedFiles, cwd)
- await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, you don't have access to merge:\n${pathListToMarkdown(filesWhichArentOwned)}` });
- return
+ const prInfo = await octokit.pulls.get({ ...thisRepo, pull_number: issue.number })
+ if (prInfo.data.state.toLowerCase() !== "open") {
+ await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR isn't open.` });
+ return
+ }
+ return prInfo
}
- // Don't try merge unmergable stuff
- const prInfo = await octokit.pulls.get({ ...thisRepo, pull_number: issue.number })
- if (!prInfo.data.mergeable) {
- 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.` });
- return
- }
+ async mergeIfHasAccess() {
+ const prInfo = await this.getTargetPRIfHasAccess()
+ if (!prInfo) {
+ return
+ }
- if (prInfo.data.state.toLowerCase() !== "open") {
- await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Sorry @${sender}, this PR isn't open.` });
- return
- }
+ const { octokit, thisRepo, issue, sender } = this;
+
+ // Don't try merge unmergable stuff
+ if (!prInfo.data.mergeable) {
+ 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.` });
+ return
+ }
+
+ // Don't merge red PRs
+ const statusInfo = await octokit.repos.listCommitStatusesForRef({ ...thisRepo, ref: prInfo.data.head.sha })
+ const failedStatus = statusInfo.data
+ // Check only the most recent for a set of duplicated statuses
+ .filter(
+ (thing, index, self) =>
+ index === self.findIndex((t) => t.target_url === thing.target_url)
+ )
+ .find(s => s.state !== "success")
+
+ if (failedStatus) {
+ 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}'.` });
+ return
+ }
- // Don't merge red PRs
- const statusInfo = await octokit.repos.listCommitStatusesForRef({ ...thisRepo, ref: prInfo.data.head.sha })
- const failedStatus = statusInfo.data
- // Check only the most recent for a set of duplicated statuses
- .filter(
- (thing, index, self) =>
- index === self.findIndex((t) => t.target_url === thing.target_url)
- )
- .find(s => s.state !== "success")
-
- if (failedStatus) {
- 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}'.` });
- return
+ core.info(`Creating comments and merging`)
+ try {
+ // @ts-ignore
+ await octokit.pulls.merge({ ...thisRepo, pull_number: issue.number, merge_method: core.getInput('merge_method') || 'merge' });
+ await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Merging because @${sender} is a code-owner of all the changes - thanks!` });
+ } catch (error) {
+ core.info(`Merging (or commenting) failed:`)
+ core.error(error)
+ core.setFailed("Failed to merge")
+
+ const linkToCI = `https://github.com/${thisRepo.owner}/${thisRepo.repo}/runs/${process.env.GITHUB_RUN_ID}?check_suite_focus=true`
+ await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `There was an issue merging, maybe try again ${sender}. Details` });
+ }
}
- core.info(`Creating comments and merging`)
- try {
- // @ts-ignore
- await octokit.pulls.merge({ ...thisRepo, pull_number: issue.number, merge_method: core.getInput('merge_method') || 'merge' });
- await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Merging because @${sender} is a code-owner of all the changes - thanks!` });
- } catch (error) {
- core.info(`Merging (or commenting) failed:`)
- core.error(error)
- core.setFailed("Failed to merge")
+ async closeIfHasAccess() {
+ const prInfo = await this.getTargetPRIfHasAccess()
+ if (!prInfo) {
+ return
+ }
+
+ const { octokit, thisRepo, issue, sender } = this;
- const linkToCI = `https://github.com/${thisRepo.owner}/${thisRepo.repo}/runs/${process.env.GITHUB_RUN_ID}?check_suite_focus=true`
- await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `There was an issue merging, maybe try again ${sender}. Details` });
+ core.info(`Creating comments and closing`)
+ await octokit.pulls.update({ ...thisRepo, pull_number: issue.number, state: "closed" });
+ await octokit.issues.createComment({ ...thisRepo, issue_number: issue.number, body: `Closing because @${sender} is a code-owner of all the changes.` });
}
}