diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 002f9694..6b8f3da2 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -210,6 +210,7 @@ test('processing a stale issue containing a space in the label will close it', a const processor = new IssueProcessor( opts, + async () => 'abot', async p => (p == 1 ? TestIssueList : []), async (num, dt) => [], async (issue, label) => new Date().toDateString() @@ -240,6 +241,7 @@ test('processing a stale issue containing a slash in the label will close it', a const processor = new IssueProcessor( opts, + async () => 'abot', async p => (p == 1 ? TestIssueList : []), async (num, dt) => [], async (issue, label) => new Date().toDateString() @@ -430,8 +432,8 @@ test('stale closed prs will not be closed', async () => { DefaultProcessorOptions, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -457,7 +459,7 @@ test('locked issues will not be marked stale', async () => { const processor = new IssueProcessor( DefaultProcessorOptions, async () => 'abot', - async p => p == 1 ? TestIssueList : [] + async p => (p == 1 ? TestIssueList : []) ); // process our fake issue list @@ -484,8 +486,8 @@ test('stale locked issues will not be closed', async () => { DefaultProcessorOptions, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -511,7 +513,7 @@ test('locked prs will not be marked stale', async () => { const processor = new IssueProcessor( DefaultProcessorOptions, async () => 'abot', - async p => p == 1 ? TestIssueList : [] + async p => (p == 1 ? TestIssueList : []) ); // process our fake issue list @@ -538,8 +540,8 @@ test('stale locked prs will not be closed', async () => { DefaultProcessorOptions, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -563,8 +565,8 @@ test('exempt issue labels will not be marked stale', async () => { opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -586,8 +588,8 @@ test('exempt issue labels will not be marked stale (multi issue label with space opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -609,8 +611,8 @@ test('exempt issue labels will not be marked stale (multi issue label)', async ( opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -635,8 +637,8 @@ test('exempt pr labels will not be marked stale', async () => { opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -661,8 +663,8 @@ test('stale issues should not be closed if days is set to -1', async () => { opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -690,8 +692,8 @@ test('stale label should be removed if a comment was added to a stale issue', as opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [{user: {login: 'notme', type: 'User'}}], // return a fake comment to indicate there was an update - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [{user: {login: 'notme', type: 'User'}}], // return a fake comment to indicate there was an update + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -721,8 +723,8 @@ test('stale label should not be removed if a comment was added by the bot (and t opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [{user: {login: 'abot', type: 'User'}}], // return a fake comment to indicate there was an update by the bot - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [{user: {login: 'abot', type: 'User'}}], // return a fake comment to indicate there was an update by the bot + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -752,9 +754,10 @@ test('stale label containing a space should be removed if a comment was added to const processor = new IssueProcessor( opts, + async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [{user: {login: 'notme', type: 'User'}}], // return a fake comment to indicate there was an update - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [{user: {login: 'notme', type: 'User'}}], // return a fake comment to indicate there was an update + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -818,8 +821,8 @@ test('stale issues should be closed if the closed nubmer of days (additive) is a opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // process our fake issue list @@ -883,8 +886,8 @@ test('skips stale message on issues when skip-stale-issue-message is set', async opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // for sake of testing, mocking private function @@ -928,8 +931,8 @@ test('skips stale message on prs when skip-stale-pr-message is set', async () => opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); // for sake of testing, mocking private function @@ -974,8 +977,8 @@ test('not providing state takes precedence over skipStaleIssueMessage', async () opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); await processor.processIssues(1); @@ -1008,8 +1011,8 @@ test('not providing stalePrMessage takes precedence over skipStalePrMessage', as opts, async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); await processor.processIssues(1); @@ -1035,9 +1038,10 @@ test('git branch is deleted when option is enabled', async () => { const processor = new IssueProcessor( opts, + async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); await processor.processIssues(1); @@ -1063,9 +1067,10 @@ test('git branch is not deleted when issue is not pull request', async () => { const processor = new IssueProcessor( opts, + async () => 'abot', async p => (p == 1 ? TestIssueList : []), - async (num, dt) => [], - async (issue, label) => new Date().toDateString() + async (num: number, dt: string) => [], + async (issue: Issue, label: string) => new Date().toDateString() ); await processor.processIssues(1); diff --git a/dist/index.js b/dist/index.js index d711bb8c..201ea3ec 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49,6 +49,7 @@ class IssueProcessor { this.operationsLeft = 0; this.staleIssues = []; this.closedIssues = []; + this.deletedBranchIssues = []; this.removedLabelIssues = []; this.options = options; this.operationsLeft = options.operationsPerRun; @@ -119,6 +120,12 @@ class IssueProcessor { } // does this issue have a stale label? let isStale = is_labeled_1.isLabeled(issue, staleLabel); + if (isStale) { + core.info(`This issue has a stale label`); + } + else { + core.info(`This issue hasn't a stale label`); + } // should this issue be marked stale? const shouldBeStale = !IssueProcessor.updatedSince(issue.updated_at, this.options.daysBeforeStale); // determine if this issue needs to be marked stale first @@ -162,6 +169,11 @@ class IssueProcessor { if (!issueHasComments && !issueHasUpdate) { core.info(`Closing ${issueType} because it was last updated on ${issue.updated_at}`); yield this.closeIssue(issue, closeMessage, closeLabel); + if (this.options.deleteBranch && issue.pull_request) { + core.info(`Deleting branch for #${issue.number} as delete-branch option was specified`); + yield this.deleteBranch(issue); + this.deletedBranchIssues.push(issue); + } } else { core.info(`Stale ${issueType} is not old enough to close yet (hasComments? ${issueHasComments}, hasUpdate? ${issueHasUpdate})`); @@ -325,12 +337,56 @@ class IssueProcessor { } }); } + getPullRequest(pullNumber) { + return __awaiter(this, void 0, void 0, function* () { + this.operationsLeft -= 1; + try { + const pullRequest = yield this.client.pulls.get({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + pull_number: pullNumber + }); + return pullRequest.data; + } + catch (error) { + core.error(`Error getting pull request ${pullNumber}: ${error.message}`); + } + }); + } + // Delete the branch on closed pull request + deleteBranch(issue) { + return __awaiter(this, void 0, void 0, function* () { + core.info(`Delete branch from closed issue #${issue.number} - ${issue.title}`); + if (this.options.debugOnly) { + return; + } + const pullRequest = yield this.getPullRequest(issue.number); + if (!pullRequest) { + core.info(`Not deleting branch as pull request not found for issue ${issue.number}`); + return; + } + const branch = pullRequest.head.ref; + core.info(`Deleting branch ${branch} from closed issue #${issue.number}`); + this.operationsLeft -= 1; + try { + yield this.client.git.deleteRef({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + ref: `heads/${branch}` + }); + } + catch (error) { + core.error(`Error deleting branch ${branch} from issue #${issue.number}: ${error.message}`); + } + }); + } // Remove a label from an issue removeLabel(issue, label) { return __awaiter(this, void 0, void 0, function* () { - core.info(`Removing label from issue #${issue.number}`); + core.info(`Removing label "${label}" from issue #${issue.number}`); this.removedLabelIssues.push(issue); this.operationsLeft -= 1; + // @todo remove the debug only to be able to test the code below if (this.options.debugOnly) { return; } @@ -339,7 +395,7 @@ class IssueProcessor { owner: github_1.context.repo.owner, repo: github_1.context.repo.repo, issue_number: issue.number, - name: encodeURIComponent(label) // A label can have a "?" in the name + name: label }); } catch (error) { @@ -517,7 +573,8 @@ function getAndValidateArgs() { debugOnly: core.getInput('debug-only') === 'true', ascending: core.getInput('ascending') === 'true', skipStalePrMessage: core.getInput('skip-stale-pr-message') === 'true', - skipStaleIssueMessage: core.getInput('skip-stale-issue-message') === 'true' + skipStaleIssueMessage: core.getInput('skip-stale-issue-message') === 'true', + deleteBranch: core.getInput('delete-branch') === 'true' }; for (const numberInput of [ 'days-before-stale', diff --git a/src/IssueProcessor.ts b/src/IssueProcessor.ts index 0ea7814d..78b9b90c 100644 --- a/src/IssueProcessor.ts +++ b/src/IssueProcessor.ts @@ -309,8 +309,7 @@ export class IssueProcessor { const comments = await this.listIssueComments(issue.number, sinceDate); const filteredComments = comments.filter( - comment => - comment.user.type === 'User' && comment.user.login !== actor + comment => comment.user.type === 'User' && comment.user.login !== actor ); core.info( @@ -347,10 +346,10 @@ export class IssueProcessor { try { actor = await this.client.users.getAuthenticated(); } catch (error) { - return context.actor + return context.actor; } - return actor.data.login + return actor.data.login; } // grab issues from github in baches of 100