diff --git a/README.md b/README.md index 7578edd20..f76e000b3 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Every argument is optional. | [close-pr-message](#close-pr-message) | Comment on the staled PRs while closed | | | [stale-issue-label](#stale-issue-label) | Label to apply on staled issues | `Stale` | | [close-issue-label](#close-issue-label) | Label to apply on closed issues | | +| [close-issue-reason](#close-issue-reason) | Reason to use when closing issues | | | [stale-pr-label](#stale-pr-label) | Label to apply on staled PRs | `Stale` | | [close-pr-label](#close-pr-label) | Label to apply on closed PRs | | | [exempt-issue-labels](#exempt-issue-labels) | Labels on issues exempted from stale | | @@ -219,6 +220,12 @@ It will be automatically removed if the issues are no longer closed nor locked. Default value: unset Required Permission: `issues: write` +#### close-issue-reason + +Specify the [reason](https://github.blog/changelog/2022-05-19-the-new-github-issues-may-19th-update/) used when closing issues. Valid values are `completed` and `not_planned`. + +Default value: unset + #### stale-pr-label The label that will be added to the pull requests when automatically marked as stale. diff --git a/__tests__/constants/default-processor-options.ts b/__tests__/constants/default-processor-options.ts index b526d12aa..ee3e7306d 100644 --- a/__tests__/constants/default-processor-options.ts +++ b/__tests__/constants/default-processor-options.ts @@ -50,5 +50,6 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({ ignoreUpdates: false, ignoreIssueUpdates: undefined, ignorePrUpdates: undefined, - exemptDraftPr: false + exemptDraftPr: false, + closeIssueReason: '' }); diff --git a/dist/index.js b/dist/index.js index f017e13a3..bec2b12c3 100644 --- a/dist/index.js +++ b/dist/index.js @@ -885,7 +885,8 @@ class IssuesProcessor { owner: github_1.context.repo.owner, repo: github_1.context.repo.repo, issue_number: issue.number, - state: 'closed' + state: 'closed', + state_reason: this.options.closeIssueReason || undefined }); } } @@ -1892,6 +1893,7 @@ var Option; Option["IgnoreIssueUpdates"] = "ignore-issue-updates"; Option["IgnorePrUpdates"] = "ignore-pr-updates"; Option["ExemptDraftPr"] = "exempt-draft-pr"; + Option["CloseIssueReason"] = "close-issue-reason"; })(Option = exports.Option || (exports.Option = {})); @@ -2202,7 +2204,8 @@ function _getAndValidateArgs() { ignoreUpdates: core.getInput('ignore-updates') === 'true', ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'), ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'), - exemptDraftPr: core.getInput('exempt-draft-pr') === 'true' + exemptDraftPr: core.getInput('exempt-draft-pr') === 'true', + closeIssueReason: core.getInput('close-issue-reason') }; for (const numberInput of [ 'days-before-stale', @@ -2225,6 +2228,12 @@ function _getAndValidateArgs() { } } } + const validCloseReasons = ['', 'completed', 'not_planned']; + if (!validCloseReasons.includes(args.closeIssueReason)) { + const errorMessage = `Unrecognized close-issue-reason "${args.closeIssueReason}", valid values are: ${validCloseReasons.filter(Boolean).join(', ')}`; + core.setFailed(errorMessage); + throw new Error(errorMessage); + } return args; } function processOutput(staledIssues, closedIssues) { diff --git a/src/classes/issue.spec.ts b/src/classes/issue.spec.ts index ccd32d51a..0a60d1a58 100644 --- a/src/classes/issue.spec.ts +++ b/src/classes/issue.spec.ts @@ -61,7 +61,8 @@ describe('Issue', (): void => { ignoreUpdates: false, ignoreIssueUpdates: undefined, ignorePrUpdates: undefined, - exemptDraftPr: false + exemptDraftPr: false, + closeIssueReason: '' }; issueInterface = { title: 'dummy-title', diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 89ca2d04e..d603a5f2f 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -865,7 +865,8 @@ export class IssuesProcessor { owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, - state: 'closed' + state: 'closed', + state_reason: this.options.closeIssueReason || undefined }); } } catch (error) { diff --git a/src/enums/option.ts b/src/enums/option.ts index f7167c725..38cfb193d 100644 --- a/src/enums/option.ts +++ b/src/enums/option.ts @@ -46,5 +46,6 @@ export enum Option { IgnoreUpdates = 'ignore-updates', IgnoreIssueUpdates = 'ignore-issue-updates', IgnorePrUpdates = 'ignore-pr-updates', - ExemptDraftPr = 'exempt-draft-pr' + ExemptDraftPr = 'exempt-draft-pr', + CloseIssueReason = 'close-issue-reason' } diff --git a/src/interfaces/issues-processor-options.ts b/src/interfaces/issues-processor-options.ts index 8adbfb4a5..496584e87 100644 --- a/src/interfaces/issues-processor-options.ts +++ b/src/interfaces/issues-processor-options.ts @@ -51,4 +51,5 @@ export interface IIssuesProcessorOptions { ignoreIssueUpdates: boolean | undefined; ignorePrUpdates: boolean | undefined; exemptDraftPr: boolean; + closeIssueReason: string; } diff --git a/src/main.ts b/src/main.ts index af96654c5..770aa1163 100644 --- a/src/main.ts +++ b/src/main.ts @@ -87,7 +87,8 @@ function _getAndValidateArgs(): IIssuesProcessorOptions { ignoreUpdates: core.getInput('ignore-updates') === 'true', ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'), ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'), - exemptDraftPr: core.getInput('exempt-draft-pr') === 'true' + exemptDraftPr: core.getInput('exempt-draft-pr') === 'true', + closeIssueReason: core.getInput('close-issue-reason') }; for (const numberInput of [ @@ -113,6 +114,15 @@ function _getAndValidateArgs(): IIssuesProcessorOptions { } } + const validCloseReasons = ['', 'completed', 'not_planned']; + if (!validCloseReasons.includes(args.closeIssueReason)) { + const errorMessage = `Unrecognized close-issue-reason "${ + args.closeIssueReason + }", valid values are: ${validCloseReasons.filter(Boolean).join(', ')}`; + core.setFailed(errorMessage); + throw new Error(errorMessage); + } + return args; }