From 9412d86b7209b4647125f2350ff49137c39795c5 Mon Sep 17 00:00:00 2001 From: Shohei Ueda <30958501+peaceiris@users.noreply.github.com> Date: Wed, 25 Nov 2020 13:47:09 +0900 Subject: [PATCH] feat: lock or unlock issue or pull-request (#317) Pull Request for #308 Related: - https://octokit.github.io/rest.js/v18#issues-lock - https://octokit.github.io/rest.js/v18#issues-unlock - https://github.com/octokit/webhooks.js/blob/master/src/generated/event-payloads.ts - https://github.com/octokit/types.ts --- package-lock.json | 6 +-- package.json | 1 + src/issues-helper.ts | 69 ++++++++++++++++++++++++++ src/main.ts | 112 ++++++++++++++++++++++++++----------------- 4 files changed, 140 insertions(+), 48 deletions(-) create mode 100644 src/issues-helper.ts diff --git a/package-lock.json b/package-lock.json index 9af09f81..3a81842d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1049,9 +1049,9 @@ } }, "@octokit/types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.0.1.tgz", - "integrity": "sha512-GorvORVwp244fGKEt3cgt/P+M0MGy4xEDbckw+K5ojEezxyMDgCaYPKVct+/eWQfZXOT7uq0xRpmrl/+hliabA==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", + "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", "requires": { "@types/node": ">= 8" } diff --git a/package.json b/package.json index 57b31c19..edd72a43 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "dependencies": { "@actions/core": "^1.2.6", "@actions/github": "^4.0.0", + "@octokit/types": "^5.5.0", "@octokit/webhooks": "^7.15.1", "js-yaml": "^3.14.0", "mustache": "^4.0.1" diff --git a/src/issues-helper.ts b/src/issues-helper.ts new file mode 100644 index 00000000..e81b4faf --- /dev/null +++ b/src/issues-helper.ts @@ -0,0 +1,69 @@ +import {context} from '@actions/github'; +import {GitHub} from '@actions/github/lib/utils'; + +export async function closeIssue( + githubClient: InstanceType, + issueNumber: number +): Promise { + await githubClient.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + state: 'closed' + }); + return; +} + +export async function openIssue( + githubClient: InstanceType, + issueNumber: number +): Promise { + await githubClient.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + state: 'open' + }); + return; +} + +export async function lockIssue( + githubClient: InstanceType, + issueNumber: number, + lockReason?: string + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): Promise { + const reason = (() => { + switch (lockReason) { + case 'off-topic': + return 'off-topic'; + case 'too heated': + return 'too heated'; + case 'resolved': + return 'resolved'; + case 'spam': + return 'spam'; + default: + return 'resolved'; + } + })(); + + return await githubClient.issues.lock({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + lock_reason: reason + }); +} + +export async function unlockIssue( + githubClient: InstanceType, + issueNumber: number + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): Promise { + return await githubClient.issues.unlock({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber + }); +} diff --git a/src/main.ts b/src/main.ts index 01998903..e0bd5773 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,37 +1,21 @@ import * as core from '@actions/core'; import {context, getOctokit} from '@actions/github'; -import {GitHub} from '@actions/github/lib/utils'; import {EventPayloads} from '@octokit/webhooks'; import {Inputs} from './interfaces'; import {getInputs} from './get-inputs'; import fs from 'fs'; import yaml from 'js-yaml'; import Mustache from 'mustache'; - -async function closeIssue( - githubClient: InstanceType, - issueNumber: number -): Promise { - await githubClient.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issueNumber, - state: 'closed' - }); - return; -} - -async function openIssue( - githubClient: InstanceType, - issueNumber: number -): Promise { - await githubClient.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issueNumber, - state: 'open' - }); - return; +import {openIssue, closeIssue, unlockIssue, lockIssue} from './issues-helper'; +import {IssuesCreateCommentResponseData, OctokitResponse} from '@octokit/types'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function consoleDebug(groupTitle: string, body: any): void { + if (core.isDebug()) { + core.startGroup(groupTitle); + console.log(body); + core.endGroup(); + } } export async function run(): Promise { @@ -40,11 +24,7 @@ export async function run(): Promise { const inps: Inputs = getInputs(); - if (core.isDebug()) { - core.startGroup('Dump GitHub context'); - console.log(context); - core.endGroup(); - } + consoleDebug('Dump GitHub context', context); const eventName: string = context.eventName; const payload = context.payload as @@ -135,6 +115,8 @@ export async function run(): Promise { } } + const parentFieldName = `labels.${labelName}.${labelEvent}.${eventType}`; + const logURL = `${process.env['GITHUB_SERVER_URL']}/${process.env['GITHUB_REPOSITORY']}/actions/runs/${process.env['GITHUB_RUN_ID']}`; const commentBody = config.labels[labelIndex][`${labelEvent}`][`${eventType}`].body + @@ -151,7 +133,7 @@ export async function run(): Promise { `); if (commentBody === '' || commentBody === void 0) { - core.info(`[INFO] no configuration labels.${labelName}.${labelEvent}.${eventType}.body`); + core.info(`[INFO] no configuration ${parentFieldName}.body`); } // Render template @@ -184,28 +166,68 @@ export async function run(): Promise { })(); const commentBodyRendered = Mustache.render(commentBody, commentBodyView); - // Post comment + // Create octokit client const githubToken = inps.GithubToken; const githubClient = getOctokit(githubToken); - await githubClient.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: commentBodyRendered - }); - // Close or Open issue + // Get locking config + const locking = config.labels[labelIndex][`${labelEvent}`][`${eventType}`].locking; + if (locking === 'lock' || locking === 'unlock') { + core.info(`[INFO] ${parentFieldName}.locking is ${locking}`); + } else if (locking === '' || locking === void 0) { + core.info(`[INFO] no configuration ${parentFieldName}.locking`); + } else { + throw new Error(`invalid value "${locking}" ${parentFieldName}.locking`); + } + + // Unlock an issue + if (locking === 'unlock') { + const unlockResult = await unlockIssue(githubClient, issueNumber); + consoleDebug('Unlock issue', unlockResult); + } + + // Post comment + const locked: boolean = (() => { + if (locking === 'unlock') { + return false; + } else if (eventName === 'issues') { + const payloadIssuesIssue = (payload as EventPayloads.WebhookPayloadIssues) + .issue as EventPayloads.WebhookPayloadIssuesIssue; + return payloadIssuesIssue.locked; + } else { + // if (eventName === 'pull_request' || eventName === 'pull_request_target') + return (payload as EventPayloads.WebhookPayloadPullRequest).pull_request.locked; + } + })(); + + if (!locked) { + const issuesCreateCommentResponse: OctokitResponse = await githubClient.issues.createComment( + { + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBodyRendered + } + ); + consoleDebug('issuesCreateCommentResponse', issuesCreateCommentResponse); + } + + // Close or Open an issue if (finalAction === 'close') { await closeIssue(githubClient, issueNumber); } else if (finalAction === 'open') { await openIssue(githubClient, issueNumber); } else if (finalAction === '' || finalAction === void 0) { - core.info(`[INFO] no configuration labels.${labelName}.${labelEvent}.${eventType}.action`); - return; + core.info(`[INFO] no configuration ${parentFieldName}.action`); } else { - throw new Error( - `invalid value "${finalAction}" labels.${labelName}.${labelEvent}.${eventType}.action` - ); + throw new Error(`invalid value "${finalAction}" ${parentFieldName}.action`); + } + + // Lock an issue + if (locking === 'lock') { + const lockReason = config.labels[labelIndex][`${labelEvent}`][`${eventType}`].lock_reason; + const lockResult = await lockIssue(githubClient, issueNumber, lockReason); + consoleDebug('Lock issue', lockResult); } return;