From 6a493760cf77905dc2bc605b38b4d88c5704c192 Mon Sep 17 00:00:00 2001 From: Geoffrey Testelin Date: Tue, 16 Feb 2021 12:18:48 +0100 Subject: [PATCH] feat(milestones): add new options to exempt all milestones (#291) * refactor: move and rename the interfaces/classes closes #272 * docs: update the readme and action to describe the new options for milestones * refactor: split the tests into multiple files * feat(milestones): add new options to exempt all milestones * test: add coverage for the default values * test(milestones): add more coverage (wip) * test(milestones): add more coverage for the multiple exempt milestones * test: reduce duplicated code * test: change some describes * test: add more coverage * test: add more coverage * test: add final coverage * build(tsc): add missing project flag to build with the right tsconfig * test(milestones): use each to reduce the complexity of the tests * chore: fix an eslint issue with prettier on windows the end of line was wrong each time the os process the files * docs: move the contribution section to a dedicated file add more content to help the debug * chore: make sure the rebase is ok --- .eslintrc.json | 12 +- .prettierrc.json | 3 +- .vscode/launch.json | 4 +- CONTRIBUTING.md | 19 + README.md | 122 +- .../constants/default-processor-options.ts | 36 + __tests__/functions/generate-issue.ts | 34 + __tests__/{main.test.ts => main.spec.ts} | 338 +- __tests__/milestones.spec.ts | 3413 +++++++++++++++++ action.yml | 26 +- dist/index.js | 52 +- package.json | 2 +- src/classes/issue.spec.ts | 5 +- src/classes/milestones.spec.ts | 5 +- src/classes/milestones.ts | 34 + src/interfaces/issues-processor-options.ts | 3 + src/main.ts | 27 +- tsconfig.app.json | 5 + tsconfig.json | 3 +- tsconfig.spec.json | 5 + 20 files changed, 3728 insertions(+), 420 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 __tests__/constants/default-processor-options.ts create mode 100644 __tests__/functions/generate-issue.ts rename __tests__/{main.test.ts => main.spec.ts} (86%) create mode 100644 __tests__/milestones.spec.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.spec.json diff --git a/.eslintrc.json b/.eslintrc.json index 5f707a9a..d4ca3d2f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -14,7 +14,9 @@ "@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/explicit-member-accessibility": [ "error", - {"accessibility": "no-public"} + { + "accessibility": "no-public" + } ], "@typescript-eslint/no-require-imports": "error", "@typescript-eslint/array-type": "error", @@ -47,7 +49,13 @@ "@typescript-eslint/type-annotation-spacing": "error", "@typescript-eslint/unbound-method": "off", "no-shadow": "off", - "@typescript-eslint/no-shadow": "error" + "@typescript-eslint/no-shadow": "error", + "prettier/prettier": [ + "error", + { + "endOfLine": "auto" + } + ] }, "env": { "node": true, diff --git a/.prettierrc.json b/.prettierrc.json index b243c2ff..8f6dcc5e 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -6,5 +6,6 @@ "singleQuote": true, "trailingComma": "none", "bracketSpacing": false, - "arrowParens": "avoid" + "arrowParens": "avoid", + "endOfLine": "auto" } diff --git a/.vscode/launch.json b/.vscode/launch.json index 6acf9bed..27f75ded 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "args": [ "-i" ], - "preLaunchTask": "tsc: build - tsconfig.json", + "preLaunchTask": "tsc: build - tsconfig.app.json", "internalConsoleOptions": "openOnSessionStart", "console": "integratedTerminal", "outFiles": [ @@ -17,4 +17,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..34b5a69d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,19 @@ +### Building and testing + +Install the dependencies. + +```bash +$ npm install +``` + +Build the typescript and package it for distribution. + +```bash +$ npm run build && npm run pack +``` + +Run the tests :heavy_check_mark: + +```bash +$ npm test +``` diff --git a/README.md b/README.md index dab01a8c..5c1852e5 100644 --- a/README.md +++ b/README.md @@ -2,59 +2,42 @@ Warns and then closes issues and PRs that have had no activity for a specified amount of time. -### Building and testing - -Install the dependencies - -```bash -$ npm install -``` - -Build the typescript and package it for distribution - -```bash -$ npm run build && npm run pack -``` - -Run the tests :heavy_check_mark: - -```bash -$ npm test -``` - ### Arguments -| Input | Description | Usage | -| --------------------------- | -------------------------------------------------------------------------------------------- | -------- | -| `repo-token` | PAT(Personal Access Token) for authorizing repository. _Defaults to **${{ github.token }}**_ | Optional | -| `days-before-stale` | Idle number of days before marking an issue/pr as stale. _Defaults to **60**_ | Optional | -| `days-before-issue-stale` | Idle number of days before marking an issue as stale (override `days-before-stale`). | Optional | -| `days-before-pr-stale` | Idle number of days before marking an pr as stale (override `days-before-stale`). | Optional | -| `days-before-close` | Idle number of days before closing an stale issue/pr. _Defaults to **7**_ | Optional | -| `days-before-issue-close` | Idle number of days before closing an stale issue (override `days-before-close`). | Optional | -| `days-before-pr-close` | Idle number of days before closing an stale pr (override `days-before-close`). | Optional | -| `stale-issue-message` | Message to post on the stale issue. | Optional | -| `stale-pr-message` | Message to post on the stale pr. | Optional | -| `close-issue-message` | Message to post on the stale issue while closing it. | Optional | -| `close-pr-message` | Message to post on the stale pr while closing it. | Optional | -| `stale-issue-label` | Label to apply on the stale issue. _Defaults to **stale**_ | Optional | -| `close-issue-label` | Label to apply on closing issue. | Optional | -| `stale-pr-label` | Label to apply on the stale pr. | Optional | -| `close-pr-label` | Label to apply on the closing pr. | Optional | -| `exempt-issue-labels` | Labels on an issue exempted from being marked as stale. | Optional | -| `exempt-pr-labels` | Labels on the pr exempted from being marked as stale. | Optional | -| `exempt-milestones` | Milestones on an issue or a pr exempted from being marked as stale. | Optional | -| `exempt-issue-milestones` | Milestones on an issue exempted from being marked as stale (override `exempt-milestones`). | Optional | -| `exempt-pr-milestones` | Milestones on the pr exempted from being marked as stale (override `exempt-milestones`). | Optional | -| `only-labels` | Only labels checked for stale issue/pr. | Optional | -| `operations-per-run` | Maximum number of operations per run (GitHub API CRUD related). _Defaults to **30**_ | Optional | -| `remove-stale-when-updated` | Remove stale label from issue/pr on updates or comments. _Defaults to **true**_ | Optional | -| `debug-only` | Dry-run on action. _Defaults to **false**_ | Optional | -| `ascending` | Order to get issues/pr. _Defaults to **false**_ | Optional | -| `skip-stale-issue-message` | Skip adding stale message on stale issue. _Defaults to **false**_ | Optional | -| `skip-stale-pr-message` | Skip adding stale message on stale pr. _Defaults to **false**_ | Optional | -| `delete-branch` | Delete the git branch after closing a stale pull request. _Defaults to **false**_ | Optional | -| `start-date` | The date used to skip the stale action on issue/pr created before it (ISO 8601 or RFC 2822). | Optional | +| Input | Description | Usage | +| ----------------------------- | --------------------------------------------------------------------------------------------------------------- | -------- | +| `repo-token` | PAT(Personal Access Token) for authorizing repository. _Defaults to **${{ github.token }}**_ | Optional | +| `days-before-stale` | Idle number of days before marking an issue/PR as stale. _Defaults to **60**_ | Optional | +| `days-before-issue-stale` | Idle number of days before marking an issue as stale (override `days-before-stale`). | Optional | +| `days-before-pr-stale` | Idle number of days before marking an PR as stale (override `days-before-stale`). | Optional | +| `days-before-close` | Idle number of days before closing an stale issue/PR. _Defaults to **7**_ | Optional | +| `days-before-issue-close` | Idle number of days before closing an stale issue (override `days-before-close`). | Optional | +| `days-before-pr-close` | Idle number of days before closing an stale PR (override `days-before-close`). | Optional | +| `stale-issue-message` | Message to post on the stale issue. | Optional | +| `stale-pr-message` | Message to post on the stale PR. | Optional | +| `close-issue-message` | Message to post on the stale issue while closing it. | Optional | +| `close-pr-message` | Message to post on the stale PR while closing it. | Optional | +| `stale-issue-label` | Label to apply on the stale issue. _Defaults to **stale**_ | Optional | +| `close-issue-label` | Label to apply on closing issue. | Optional | +| `stale-pr-label` | Label to apply on the stale PR. | Optional | +| `close-pr-label` | Label to apply on the closing PR. | Optional | +| `exempt-issue-labels` | Labels on an issue exempted from being marked as stale. | Optional | +| `exempt-pr-labels` | Labels on the PR exempted from being marked as stale. | Optional | +| `exempt-milestones` | Milestones on an issue or a PR exempted from being marked as stale. | Optional | +| `exempt-issue-milestones` | Milestones on an issue exempted from being marked as stale (override `exempt-milestones`). | Optional | +| `exempt-pr-milestones` | Milestones on the PR exempted from being marked as stale (override `exempt-milestones`). | Optional | +| `exempt-all-milestones` | Exempt all issues and PRs with milestones from being marked as stale. (priority over `exempt-milestones` rules) | Optional | +| `exempt-all-issue-milestones` | Exempt all issues with milestones from being marked as stale. (override `exempt-all-milestones`). | Optional | +| `exempt-all-pr-milestones` | Exempt all PRs with milestones from being marked as stale. (override `exempt-all-milestones`). | Optional | +| `only-labels` | Only labels checked for stale issue/PR. | Optional | +| `operations-per-run` | Maximum number of operations per run (GitHub API CRUD related). _Defaults to **30**_ | Optional | +| `remove-stale-when-updated` | Remove stale label from issue/PR on updates or comments. _Defaults to **true**_ | Optional | +| `debug-only` | Dry-run on action. _Defaults to **false**_ | Optional | +| `ascending` | Order to get issues/PR. _Defaults to **false**_ | Optional | +| `skip-stale-issue-message` | Skip adding stale message on stale issue. _Defaults to **false**_ | Optional | +| `skip-stale-pr-message` | Skip adding stale message on stale PR. _Defaults to **false**_ | Optional | +| `start-date` | The date used to skip the stale action on issue/PR created before it (ISO 8601 or RFC 2822). | Optional | +| `delete-branch` | Delete the git branch after closing a stale pull request. _Defaults to **false**_ | Optional | ### Usage @@ -97,7 +80,7 @@ jobs: days-before-close: 5 ``` -Configure different stale timeouts but never close a pr: +Configure different stale timeouts but never close a PR: ```yaml name: 'Close stale issues and PR' @@ -113,7 +96,7 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' - stale-pr-message: 'This pr is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.' + stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.' close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' days-before-stale: 30 days-before-close: 5 @@ -136,9 +119,9 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' - stale-pr-message: 'This pr is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.' + stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.' close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' - close-pr-message: 'This pr was closed because it has been stalled for 10 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' days-before-issue-stale: 30 days-before-pr-stale: 45 days-before-issue-close: 5 @@ -168,7 +151,7 @@ jobs: only-labels: 'awaiting-feedback,awaiting-answers' ``` -Configure the stale action to only stale issue/pr created after the 18th april 2020: +Configure the stale action to only stale issue/PR created after the 18th april 2020: ```yaml name: 'Close stale issues and PRs' @@ -203,6 +186,31 @@ jobs: exempt-pr-milestones: 'bugfix,improvement' ``` +Avoid stale for all PR with milestones: + +```yaml +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + exempt-all-pr-milestones: true +``` + ### Debugging -To see debug output from this action, you must set the secret `ACTIONS_STEP_DEBUG` to `true` in your repository. You can run this action in debug only mode (no actions will be taken on your issues) by passing `debug-only` `true` as an argument to the action. +To see the debug output from this action, you must set the secret `ACTIONS_STEP_DEBUG` to `true` in your repository. +You can run this action in debug only mode (no actions will be taken on your issues and pull requests) by passing `debug-only` to `true` as an argument to the action. +You can also increase the maximum number of operations per run by passing `operations-per-run` to `100` for example. +Finally, you could also change the cron job frequency in the stale workflow to run stale more often. + +### Contributing + +You wish to contribute? +Check out the [contributing](CONTRIBUTING.md) file before helping us. diff --git a/__tests__/constants/default-processor-options.ts b/__tests__/constants/default-processor-options.ts new file mode 100644 index 00000000..941fac41 --- /dev/null +++ b/__tests__/constants/default-processor-options.ts @@ -0,0 +1,36 @@ +import {IIssuesProcessorOptions} from '../../src/interfaces/issues-processor-options'; + +export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({ + repoToken: 'none', + staleIssueMessage: 'This issue is stale', + stalePrMessage: 'This PR is stale', + closeIssueMessage: 'This issue is being closed', + closePrMessage: 'This PR is being closed', + daysBeforeStale: 1, + daysBeforeIssueStale: NaN, + daysBeforePrStale: NaN, + daysBeforeClose: 30, + daysBeforeIssueClose: NaN, + daysBeforePrClose: NaN, + staleIssueLabel: 'Stale', + closeIssueLabel: '', + exemptIssueLabels: '', + stalePrLabel: 'Stale', + closePrLabel: '', + exemptPrLabels: '', + onlyLabels: '', + operationsPerRun: 100, + debugOnly: true, + removeStaleWhenUpdated: false, + ascending: false, + skipStaleIssueMessage: false, + skipStalePrMessage: false, + deleteBranch: false, + startDate: '', + exemptMilestones: '', + exemptIssueMilestones: '', + exemptPrMilestones: '', + exemptAllMilestones: false, + exemptAllIssueMilestones: undefined, + exemptAllPrMilestones: undefined +}); diff --git a/__tests__/functions/generate-issue.ts b/__tests__/functions/generate-issue.ts new file mode 100644 index 00000000..90aabc04 --- /dev/null +++ b/__tests__/functions/generate-issue.ts @@ -0,0 +1,34 @@ +import {Issue} from '../../src/classes/issue'; +import {IIssuesProcessorOptions} from '../../src/interfaces/issues-processor-options'; +import {IsoDateString} from '../../src/types/iso-date-string'; + +export function generateIssue( + options: IIssuesProcessorOptions, + id: number, + title: string, + updatedAt: IsoDateString, + createdAt: IsoDateString = updatedAt, + isPullRequest = false, + labels: string[] = [], + isClosed = false, + isLocked = false, + milestone: string | undefined = undefined +): Issue { + return new Issue(options, { + number: id, + labels: labels.map(l => { + return {name: l}; + }), + title, + created_at: createdAt, + updated_at: updatedAt, + pull_request: isPullRequest ? {} : null, + state: isClosed ? 'closed' : 'open', + locked: isLocked, + milestone: milestone + ? { + title: milestone + } + : undefined + }); +} diff --git a/__tests__/main.test.ts b/__tests__/main.spec.ts similarity index 86% rename from __tests__/main.test.ts rename to __tests__/main.spec.ts index 2d387939..46ea62fb 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.spec.ts @@ -1,70 +1,9 @@ import * as github from '@actions/github'; import {Issue} from '../src/classes/issue'; - import {IssuesProcessor} from '../src/classes/issues-processor'; import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options'; -import {IsoDateString} from '../src/types/iso-date-string'; - -function generateIssue( - options: IIssuesProcessorOptions, - id: number, - title: string, - updatedAt: IsoDateString, - createdAt: IsoDateString = updatedAt, - isPullRequest = false, - labels: string[] = [], - isClosed = false, - isLocked = false, - milestone = '' -): Issue { - return new Issue(options, { - number: id, - labels: labels.map(l => { - return {name: l}; - }), - title, - created_at: createdAt, - updated_at: updatedAt, - pull_request: isPullRequest ? {} : null, - state: isClosed ? 'closed' : 'open', - locked: isLocked, - milestone: { - title: milestone - } - }); -} - -const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({ - repoToken: 'none', - staleIssueMessage: 'This issue is stale', - stalePrMessage: 'This PR is stale', - closeIssueMessage: 'This issue is being closed', - closePrMessage: 'This PR is being closed', - daysBeforeStale: 1, - daysBeforeIssueStale: NaN, - daysBeforePrStale: NaN, - daysBeforeClose: 30, - daysBeforeIssueClose: NaN, - daysBeforePrClose: NaN, - staleIssueLabel: 'Stale', - closeIssueLabel: '', - exemptIssueLabels: '', - stalePrLabel: 'Stale', - closePrLabel: '', - exemptPrLabels: '', - onlyLabels: '', - operationsPerRun: 100, - debugOnly: true, - removeStaleWhenUpdated: false, - ascending: false, - skipStaleIssueMessage: false, - skipStalePrMessage: false, - deleteBranch: false, - startDate: '', - exemptMilestones: '', - exemptIssueMilestones: '', - exemptPrMilestones: '' -}); +import {DefaultProcessorOptions} from './constants/default-processor-options'; +import {generateIssue} from './functions/generate-issue'; test('empty issue list results in 1 operation', async () => { const processor = new IssuesProcessor( @@ -1991,279 +1930,6 @@ test('an issue with an exempted milestone and with an exempted issue milestone w expect(processor.removedLabelIssues.length).toStrictEqual(0); }); -test('a PR without a milestone will be marked as stale', async () => { - expect.assertions(3); - const TestIssueList: Issue[] = [ - generateIssue( - DefaultProcessorOptions, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - '' - ) - ]; - const processor = new IssuesProcessor( - DefaultProcessorOptions, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(1); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - -test('a PR without an exempted milestone will be marked as stale', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptMilestones = 'Milestone1'; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - 'Milestone' - ) - ]; - const processor = new IssuesProcessor( - opts, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(1); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - -test('a PR with an exempted milestone will not be marked as stale', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptMilestones = 'Milestone1'; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - 'Milestone1' - ) - ]; - const processor = new IssuesProcessor( - opts, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(0); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - -test('a PR with an exempted milestone will not be marked as stale (multi milestones with spaces)', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptMilestones = 'Milestone1, Milestone2'; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - 'Milestone2' - ) - ]; - const processor = new IssuesProcessor( - opts, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(0); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - -test('a PR with an exempted milestone will not be marked as stale (multi milestones without spaces)', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptMilestones = 'Milestone1,Milestone2'; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - 'Milestone2' - ) - ]; - const processor = new IssuesProcessor( - opts, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(0); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - -test('a PR with an exempted milestone but without an exempted issue milestone will not be marked as stale', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptMilestones = 'Milestone1'; - opts.exemptPrMilestones = ''; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - 'Milestone1' - ) - ]; - const processor = new IssuesProcessor( - opts, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(0); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - -test('a PR with an exempted milestone but with another exempted issue milestone will be marked as stale', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptMilestones = 'Milestone1'; - opts.exemptPrMilestones = 'Milestone2'; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - 'Milestone1' - ) - ]; - const processor = new IssuesProcessor( - opts, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(1); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - -test('a PR with an exempted milestone and with an exempted issue milestone will not be marked as stale', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptMilestones = 'Milestone1'; - opts.exemptPrMilestones = 'Milestone1'; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - true, - undefined, - undefined, - undefined, - 'Milestone1' - ) - ]; - const processor = new IssuesProcessor( - opts, - async () => 'abot', - async p => (p == 1 ? TestIssueList : []), - async (num: number, dt: string) => [], - async (issue: Issue, label: string) => new Date().toDateString() - ); - - // process our fake issue list - await processor.processIssues(1); - - expect(processor.staleIssues.length).toStrictEqual(0); - expect(processor.closedIssues.length).toStrictEqual(0); - expect(processor.removedLabelIssues.length).toStrictEqual(0); -}); - test('processing an issue opened since 2 days and with the option "daysBeforeIssueStale" at 3 will not make it stale', async () => { expect.assertions(2); const opts: IIssuesProcessorOptions = { diff --git a/__tests__/milestones.spec.ts b/__tests__/milestones.spec.ts new file mode 100644 index 00000000..d19412d8 --- /dev/null +++ b/__tests__/milestones.spec.ts @@ -0,0 +1,3413 @@ +import {Issue} from '../src/classes/issue'; +import {IssuesProcessor} from '../src/classes/issues-processor'; +import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options'; +import {DefaultProcessorOptions} from './constants/default-processor-options'; +import {generateIssue} from './functions/generate-issue'; + +interface ITestData { + isPullRequest: boolean; + milestone: string; + name: string; + shouldStale: boolean; + exemptAllMilestones: boolean; +} + +describe('milestones options', (): void => { + let opts: IIssuesProcessorOptions; + let testIssueList: Issue[]; + let processor: IssuesProcessor; + + const setTestIssueList = ( + isPullRequest: boolean, + milestone: string | undefined + ) => { + testIssueList = [ + generateIssue( + opts, + 1, + 'My first issue', + '2020-01-01T17:00:00Z', + '2020-01-01T17:00:00Z', + isPullRequest, + undefined, + undefined, + undefined, + milestone + ) + ]; + }; + + const setProcessor = () => { + processor = new IssuesProcessor( + opts, + async () => 'abot', + async p => (p === 1 ? testIssueList : []), + async () => [], + async () => new Date().toDateString() + ); + }; + + beforeEach((): void => { + opts = {...DefaultProcessorOptions}; + }); + + describe('when all the issues and pull requests milestones should not exempt', (): void => { + beforeEach((): void => { + opts.exemptAllMilestones = false; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones are not configured to exempt', (): void => { + beforeEach((): void => { + opts.exemptAllIssueMilestones = undefined; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the issues milestones should not exempt', (): void => { + beforeEach((): void => { + opts.exemptAllIssueMilestones = false; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the issues milestones should exempt', (): void => { + beforeEach((): void => { + opts.exemptAllIssueMilestones = true; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the pull requests milestones are not configured to exempt', (): void => { + beforeEach((): void => { + opts.exemptAllPrMilestones = undefined; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the pull requests milestones should not exempt', (): void => { + beforeEach((): void => { + opts.exemptAllPrMilestones = false; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the pull requests milestones should exempt', (): void => { + beforeEach((): void => { + opts.exemptAllPrMilestones = true; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + }); + + describe('when all the issues and pull requests milestones should exempt', (): void => { + beforeEach((): void => { + opts.exemptAllMilestones = true; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones are not configured to exempt', (): void => { + beforeEach((): void => { + opts.exemptAllIssueMilestones = undefined; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the issues milestones should not exempt', (): void => { + beforeEach((): void => { + opts.exemptAllIssueMilestones = false; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${true} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${true} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${true} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the issues milestones should exempt', (): void => { + beforeEach((): void => { + opts.exemptAllIssueMilestones = true; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the pull requests milestones are not configured to exempt', (): void => { + beforeEach((): void => { + opts.exemptAllPrMilestones = undefined; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the pull requests milestones should not exempt', (): void => { + beforeEach((): void => { + opts.exemptAllPrMilestones = false; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${true} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${true} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${true} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + + describe('when all the pull requests milestones should exempt', (): void => { + beforeEach((): void => { + opts.exemptAllPrMilestones = true; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues and pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = 'dummy-issue-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = 'dummy-pull-request-milestone'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + + describe('when all the issues and pull requests milestones should exempt some milestones', (): void => { + beforeEach((): void => { + opts.exemptMilestones = 'dummy-milestone1, dummy-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + + describe('when all the issues milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptIssueMilestones = + 'dummy-issue-milestone1, dummy-issue-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-issue-milestone2'} | ${'the issue does have a milestone matching the specific issue exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-issue-milestone2'} | ${'the PR does have a milestone matching the specific issue exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + + describe('when all the pull requests milestones should exempt a specific milestone', (): void => { + beforeEach((): void => { + opts.exemptPrMilestones = + 'dummy-pull-request-milestone1, dummy-pull-request-milestone2'; + }); + + describe.each` + isPullRequest | milestone | name | shouldStale + ${false} | ${''} | ${'the issue does not have a milestone'} | ${true} + ${false} | ${'dummy-milestone-not-exempted'} | ${'the issue does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-pull-request-milestone2'} | ${'the issue does have a milestone matching the specific pull request exempted one'} | ${false} + ${false} | ${'dummy-milestone2'} | ${'the issue does have a milestone matching the specific exempted one'} | ${false} + ${true} | ${''} | ${'the PR does not have a milestone'} | ${true} + ${true} | ${'dummy-milestone-not-exempted'} | ${'the PR does have a milestone but not matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-pull-request-milestone2'} | ${'the PR does have a milestone matching the specific pull request exempted one'} | ${false} + ${true} | ${'dummy-milestone2'} | ${'the PR does have a milestone matching the specific exempted one'} | ${false} + `( + 'when $name', + ({isPullRequest, milestone, shouldStale}: ITestData): void => { + beforeEach((): void => { + setTestIssueList(isPullRequest, milestone); + setProcessor(); + }); + + test(`should${ + shouldStale ? '' : ' not' + } be marked as stale`, async () => { + expect.assertions(3); + + await processor.processIssues(1); + + expect(processor.staleIssues.length).toStrictEqual( + shouldStale ? 1 : 0 + ); + expect(processor.closedIssues.length).toStrictEqual(0); + expect(processor.removedLabelIssues.length).toStrictEqual(0); + }); + } + ); + }); + }); + }); + }); +}); diff --git a/action.yml b/action.yml index 41f667a7..4847e782 100644 --- a/action.yml +++ b/action.yml @@ -10,13 +10,13 @@ inputs: description: 'The message to post on the issue when tagging it. If none provided, will not mark issues stale.' required: false stale-pr-message: - description: 'The message to post on the pr when tagging it. If none provided, will not mark pull requests stale.' + description: 'The message to post on the pull request when tagging it. If none provided, will not mark pull requests stale.' required: false close-issue-message: description: 'The message to post on the issue when closing it. If none provided, will not comment when closing an issue.' required: false close-pr-message: - description: 'The message to post on the pr when closing it. If none provided, will not comment when closing a pull requests.' + description: 'The message to post on the pull request when closing it. If none provided, will not comment when closing a pull requests.' required: false days-before-stale: description: 'The number of days old an issue or a pull request can be before marking it stale. Set to -1 to never mark issues or pull requests as stale automatically.' @@ -57,19 +57,31 @@ inputs: description: 'The label to apply when a pull request is closed.' required: false exempt-pr-labels: - description: 'The labels that mean a pull request is exempt from being marked stale. Separate multiple labels with commas (eg. "label1,label2")' + description: 'The labels that mean a pull request is exempt from being marked as stale. Separate multiple labels with commas (eg. "label1,label2")' default: '' required: false exempt-milestones: - description: 'The milestones that mean an issue or a pr is exempt from being marked stale. Separate multiple milestones with commas (eg. "milestone1,milestone2")' + description: 'The milestones that mean an issue or a pull request is exempt from being marked as stale. Separate multiple milestones with commas (eg. "milestone1,milestone2")' default: '' required: false exempt-issue-milestones: - description: 'The milestones that mean an issue is exempt from being marked stale. Separate multiple milestones with commas (eg. "milestone1,milestone2"). Override "exempt-milestones" option regarding only the issue.' + description: 'The milestones that mean an issue is exempt from being marked as stale. Separate multiple milestones with commas (eg. "milestone1,milestone2"). Override "exempt-milestones" option regarding only the issues.' default: '' required: false exempt-pr-milestones: - description: 'The milestones that mean a pull request is exempt from being marked stale. Separate multiple milestones with commas (eg. "milestone1,milestone2"). Override "exempt-milestones" option regarding only the pull requests.' + description: 'The milestones that mean a pull request is exempt from being marked as stale. Separate multiple milestones with commas (eg. "milestone1,milestone2"). Override "exempt-milestones" option regarding only the pull requests.' + default: '' + required: false + exempt-all-milestones: + description: 'Exempt all issues and pull requests with milestones from being marked as stale. Default to false.' + default: 'false' + required: false + exempt-all-issue-milestones: + description: 'Exempt all issues with milestones from being marked as stale. Override "exempt-all-milestones" option regarding only the issues.' + default: '' + required: false + exempt-all-pr-milestones: + description: 'Exempt all pull requests with milestones from being marked as stale. Override "exempt-all-milestones" option regarding only the pull requests.' default: '' required: false only-labels: @@ -105,7 +117,7 @@ inputs: default: 'false' required: false start-date: - description: 'The date used to skip the stale action on issue/pr created before it (ISO 8601 or RFC 2822).' + description: 'The date used to skip the stale action on issue/pull request created before it (ISO 8601 or RFC 2822).' default: '' required: false runs: diff --git a/dist/index.js b/dist/index.js index cc038801..ad4c58da 100644 --- a/dist/index.js +++ b/dist/index.js @@ -660,6 +660,9 @@ class Milestones { return lodash_deburr_1.default(label.toLowerCase()); } shouldExemptMilestones() { + if (this._shouldExemptAllMilestones()) { + return true; + } const exemptMilestones = this._getExemptMilestones(); return exemptMilestones.some((exemptMilestone) => this._hasMilestone(exemptMilestone)); } @@ -685,6 +688,32 @@ class Milestones { return (Milestones._cleanMilestone(milestone) === Milestones._cleanMilestone(this._issue.milestone.title)); } + _shouldExemptAllMilestones() { + if (this._issue.milestone) { + return this._issue.isPullRequest + ? this._shouldExemptAllPullRequestMilestones() + : this._shouldExemptAllIssueMilestones(); + } + return false; + } + _shouldExemptAllIssueMilestones() { + if (this._options.exemptAllIssueMilestones === true) { + return true; + } + else if (this._options.exemptAllIssueMilestones === false) { + return false; + } + return this._options.exemptAllMilestones; + } + _shouldExemptAllPullRequestMilestones() { + if (this._options.exemptAllPrMilestones === true) { + return true; + } + else if (this._options.exemptAllPrMilestones === false) { + return false; + } + return this._options.exemptAllMilestones; + } } exports.Milestones = Milestones; @@ -925,10 +954,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); const core = __importStar(__nccwpck_require__(2186)); const is_valid_date_1 = __nccwpck_require__(891); const issues_processor_1 = __nccwpck_require__(3292); -function run() { +function _run() { return __awaiter(this, void 0, void 0, function* () { try { - const args = getAndValidateArgs(); + const args = _getAndValidateArgs(); const processor = new issues_processor_1.IssuesProcessor(args); yield processor.processIssues(); } @@ -938,7 +967,7 @@ function run() { } }); } -function getAndValidateArgs() { +function _getAndValidateArgs() { const args = { repoToken: core.getInput('repo-token'), staleIssueMessage: core.getInput('stale-issue-message'), @@ -970,7 +999,10 @@ function getAndValidateArgs() { : undefined, exemptMilestones: core.getInput('exempt-milestones'), exemptIssueMilestones: core.getInput('exempt-issue-milestones'), - exemptPrMilestones: core.getInput('exempt-pr-milestones') + exemptPrMilestones: core.getInput('exempt-pr-milestones'), + exemptAllMilestones: core.getInput('exempt-all-milestones') === 'true', + exemptAllIssueMilestones: _toOptionalBoolean('exempt-all-issue-milestones'), + exemptAllPrMilestones: _toOptionalBoolean('exempt-all-pr-milestones') }; for (const numberInput of [ 'days-before-stale', @@ -991,7 +1023,17 @@ function getAndValidateArgs() { } return args; } -run(); +function _toOptionalBoolean(argumentName) { + const argument = core.getInput(argumentName); + if (argument === 'true') { + return true; + } + else if (argument === 'false') { + return false; + } + return undefined; +} +_run(); /***/ }), diff --git a/package.json b/package.json index e1c5d140..d4982f11 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Marks old issues and PRs as stale", "main": "lib/main.js", "scripts": { - "build": "tsc", + "build": "tsc --project tsconfig.app.json", "format": "prettier --write --ignore-unknown **/*.{md,json,yml,ts}", "format-check": "prettier --check --ignore-unknown **/*.{md,json,yml,ts}", "lint": "eslint src/**/*.ts", diff --git a/src/classes/issue.spec.ts b/src/classes/issue.spec.ts index 949211d5..105c19af 100644 --- a/src/classes/issue.spec.ts +++ b/src/classes/issue.spec.ts @@ -39,7 +39,10 @@ describe('Issue', (): void => { stalePrMessage: '', startDate: undefined, stalePrLabel: 'dummy-stale-pr-label', - staleIssueLabel: 'dummy-stale-issue-label' + staleIssueLabel: 'dummy-stale-issue-label', + exemptAllMilestones: false, + exemptAllIssueMilestones: undefined, + exemptAllPrMilestones: undefined }; issueInterface = { title: 'dummy-title', diff --git a/src/classes/milestones.spec.ts b/src/classes/milestones.spec.ts index 4703a7f7..d010fb76 100644 --- a/src/classes/milestones.spec.ts +++ b/src/classes/milestones.spec.ts @@ -39,7 +39,10 @@ describe('Milestones', (): void => { startDate: undefined, exemptIssueMilestones: '', exemptPrMilestones: '', - exemptMilestones: '' + exemptMilestones: '', + exemptAllMilestones: false, + exemptAllIssueMilestones: undefined, + exemptAllPrMilestones: undefined }; issueInterface = { created_at: '', diff --git a/src/classes/milestones.ts b/src/classes/milestones.ts index b208c85f..eeb91393 100644 --- a/src/classes/milestones.ts +++ b/src/classes/milestones.ts @@ -19,6 +19,10 @@ export class Milestones { } shouldExemptMilestones(): boolean { + if (this._shouldExemptAllMilestones()) { + return true; + } + const exemptMilestones: string[] = this._getExemptMilestones(); return exemptMilestones.some((exemptMilestone: Readonly): boolean => @@ -56,4 +60,34 @@ export class Milestones { Milestones._cleanMilestone(this._issue.milestone.title) ); } + + private _shouldExemptAllMilestones(): boolean { + if (this._issue.milestone) { + return this._issue.isPullRequest + ? this._shouldExemptAllPullRequestMilestones() + : this._shouldExemptAllIssueMilestones(); + } + + return false; + } + + private _shouldExemptAllIssueMilestones(): boolean { + if (this._options.exemptAllIssueMilestones === true) { + return true; + } else if (this._options.exemptAllIssueMilestones === false) { + return false; + } + + return this._options.exemptAllMilestones; + } + + private _shouldExemptAllPullRequestMilestones(): boolean { + if (this._options.exemptAllPrMilestones === true) { + return true; + } else if (this._options.exemptAllPrMilestones === false) { + return false; + } + + return this._options.exemptAllMilestones; + } } diff --git a/src/interfaces/issues-processor-options.ts b/src/interfaces/issues-processor-options.ts index 11253c95..8a74cab0 100644 --- a/src/interfaces/issues-processor-options.ts +++ b/src/interfaces/issues-processor-options.ts @@ -30,4 +30,7 @@ export interface IIssuesProcessorOptions { exemptMilestones: string; exemptIssueMilestones: string; exemptPrMilestones: string; + exemptAllMilestones: boolean; + exemptAllIssueMilestones: boolean | undefined; + exemptAllPrMilestones: boolean | undefined; } diff --git a/src/main.ts b/src/main.ts index 130d1b00..7620c05f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,9 +3,9 @@ import {isValidDate} from './functions/dates/is-valid-date'; import {IssuesProcessor} from './classes/issues-processor'; import {IIssuesProcessorOptions} from './interfaces/issues-processor-options'; -async function run(): Promise { +async function _run(): Promise { try { - const args = getAndValidateArgs(); + const args = _getAndValidateArgs(); const processor: IssuesProcessor = new IssuesProcessor(args); await processor.processIssues(); @@ -15,7 +15,7 @@ async function run(): Promise { } } -function getAndValidateArgs(): IIssuesProcessorOptions { +function _getAndValidateArgs(): IIssuesProcessorOptions { const args: IIssuesProcessorOptions = { repoToken: core.getInput('repo-token'), staleIssueMessage: core.getInput('stale-issue-message'), @@ -56,7 +56,10 @@ function getAndValidateArgs(): IIssuesProcessorOptions { : undefined, exemptMilestones: core.getInput('exempt-milestones'), exemptIssueMilestones: core.getInput('exempt-issue-milestones'), - exemptPrMilestones: core.getInput('exempt-pr-milestones') + exemptPrMilestones: core.getInput('exempt-pr-milestones'), + exemptAllMilestones: core.getInput('exempt-all-milestones') === 'true', + exemptAllIssueMilestones: _toOptionalBoolean('exempt-all-issue-milestones'), + exemptAllPrMilestones: _toOptionalBoolean('exempt-all-pr-milestones') }; for (const numberInput of [ @@ -83,4 +86,18 @@ function getAndValidateArgs(): IIssuesProcessorOptions { return args; } -run(); +function _toOptionalBoolean( + argumentName: Readonly +): boolean | undefined { + const argument: string = core.getInput(argumentName); + + if (argument === 'true') { + return true; + } else if (argument === 'false') { + return false; + } + + return undefined; +} + +_run(); diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 00000000..2b5d80c1 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "**/*.spec.ts"], + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json index 4ba71e8d..ed2e7fe0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,11 +3,10 @@ "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, "outDir": "./lib" /* Redirect output structure to the directory. */, - "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, "strict": true /* Enable all strict type-checking options. */, "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ //"sourceMap": true }, - "exclude": ["node_modules", "**/*.test.ts"] + "include": ["src", "__tests__"] } diff --git a/tsconfig.spec.json b/tsconfig.spec.json new file mode 100644 index 00000000..14f9e85f --- /dev/null +++ b/tsconfig.spec.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src", "__tests__"], + "exclude": ["node_modules"] +}