Compare commits

..

25 Commits

Author SHA1 Message Date
Luke Tomlinson
cc8ff56517 Revert debugging 2021-05-12 14:02:04 -04:00
Luke Tomlinson
ab559aee86 update 2021-05-12 13:56:50 -04:00
Luke Tomlinson
ffc3c749f4 Dist 2021-05-12 13:37:22 -04:00
Luke Tomlinson
93db9b6708 Update issues-processor.ts 2021-05-12 13:35:50 -04:00
dependabot[bot]
3b3c3f03cd build(deps-dev): bump typescript from 4.2.2 to 4.2.3 (#353)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-05 09:18:00 -05:00
dependabot[bot]
70f07a7b62 build(deps-dev): bump @typescript-eslint/parser from 4.15.2 to 4.16.1 (#344)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 4.15.2 to 4.16.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.16.1/packages/parser)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-05 09:13:02 -05:00
dependabot[bot]
6a2a52084e build(deps): bump @octokit/rest from 18.3.2 to 18.3.3 (#354)
Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.3.2 to 18.3.3.
- [Release notes](https://github.com/octokit/rest.js/releases)
- [Commits](https://github.com/octokit/rest.js/compare/v18.3.2...v18.3.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-05 09:12:55 -05:00
dependabot[bot]
bea117ba11 build(deps-dev): bump eslint-plugin-github from 4.1.1 to 4.1.2 (#356)
Bumps [eslint-plugin-github](https://github.com/github/eslint-plugin-github) from 4.1.1 to 4.1.2.
- [Release notes](https://github.com/github/eslint-plugin-github/releases)
- [Commits](https://github.com/github/eslint-plugin-github/compare/v4.1.1...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-05 09:12:45 -05:00
dependabot[bot]
c181784783 build(deps-dev): bump ts-jest from 26.5.2 to 26.5.3 (#355)
Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 26.5.2 to 26.5.3.
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v26.5.2...v26.5.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-05 09:12:38 -05:00
Geoffrey Testelin
93cc018477 test: add more coverage for the stale label behaviour (#352)
* docs(only-labels): enhance the docs and fix duplicate (#341)

* docs(only-labels): remove duplicated option and improve descriptions

a bad rebase happend

* docs(readme): use a multi-line array and remove the optional column

the option column was not helpful since each value is optional
the multi-line array will allow to have a better UI in small devices and basically in GitHub too due to the max-width

* style(readme): break line for the statistics

* docs(readme): add a better description for the ascending option

* docs(action): add missing punctuation

* build(deps-dev): bump @typescript-eslint/eslint-plugin (#342)

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.15.2 to 4.16.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.16.1/packages/eslint-plugin)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @octokit/rest from 18.3.0 to 18.3.2 (#350)

Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.3.0 to 18.3.2.
- [Release notes](https://github.com/octokit/rest.js/releases)
- [Commits](https://github.com/octokit/rest.js/compare/v18.3.0...v18.3.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* test: add more coverage to make sure to understand how the stale label works

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-05 09:12:18 -05:00
dependabot[bot]
b80d40901f build(deps): bump @octokit/rest from 18.3.0 to 18.3.2 (#350)
Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.3.0 to 18.3.2.
- [Release notes](https://github.com/octokit/rest.js/releases)
- [Commits](https://github.com/octokit/rest.js/compare/v18.3.0...v18.3.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 06:38:50 -05:00
dependabot[bot]
10e1968c4f build(deps-dev): bump @typescript-eslint/eslint-plugin (#342)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.15.2 to 4.16.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.16.1/packages/eslint-plugin)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 06:38:32 -05:00
Geoffrey Testelin
ba1c02f61a docs(only-labels): enhance the docs and fix duplicate (#341)
* docs(only-labels): remove duplicated option and improve descriptions

a bad rebase happend

* docs(readme): use a multi-line array and remove the optional column

the option column was not helpful since each value is optional
the multi-line array will allow to have a better UI in small devices and basically in GitHub too due to the max-width

* style(readme): break line for the statistics

* docs(readme): add a better description for the ascending option

* docs(action): add missing punctuation
2021-03-04 06:38:05 -05:00
Geoffrey Testelin
419a53bc05 feat(statistics): display some stats in the logs (#337)
* test: add more coverage

* docs: reorder and enhance typo

* docs(contributing): add more information about the npm scripts

* feat(statistics): add simple statistics

* feat(statistics): add more stats

* refactor(issues-processor): remove some options from the constructor

it should have been only useful for the tests

* feat(statistics): add stats for new stale or undo stale issues

* chore(rebase): handle rebase conflicts
2021-03-01 15:34:35 -05:00
Jose Veiga
63ae8ac024 Feat: add any-of-labels option (#319)
* feat: add any-of-labels option

* chore: run pack script

* fix: error in milestones spec

* chore: update readme

* chore: fix default value in action.yml

* chore: add some unit tests

* docs: update README.md

Co-authored-by: Geoffrey Testelin <geoffrey.testelin@gmail.com>

* refactor: add return type to lambda

Co-authored-by: Geoffrey Testelin <geoffrey.testelin@gmail.com>
2021-03-01 11:05:53 -05:00
dependabot[bot]
8f5f223d0c Bump typescript from 4.1.5 to 4.2.2 (#340)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.1.5 to 4.2.2.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.1.5...v4.2.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-01 11:04:26 -05:00
dependabot[bot]
aac59820db Bump @typescript-eslint/eslint-plugin from 4.15.1 to 4.15.2 (#331)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.15.1 to 4.15.2.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.15.2/packages/eslint-plugin)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-01 09:21:56 -05:00
dependabot[bot]
4109d00d07 Bump @types/node from 14.14.28 to 14.14.31 (#328)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.28 to 14.14.31.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-01 09:21:45 -05:00
dependabot[bot]
b3213c1ffa Bump eslint from 7.20.0 to 7.21.0 (#339)
Bumps [eslint](https://github.com/eslint/eslint) from 7.20.0 to 7.21.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.20.0...v7.21.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-01 09:21:33 -05:00
dependabot[bot]
12d218f917 Bump ts-jest from 26.5.1 to 26.5.2 (#332)
Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 26.5.1 to 26.5.2.
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v26.5.1...v26.5.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-28 19:11:57 -05:00
dependabot[bot]
e1732283c7 Bump @typescript-eslint/parser from 4.15.1 to 4.15.2 (#330)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 4.15.1 to 4.15.2.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.15.2/packages/parser)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-28 19:11:41 -05:00
dependabot[bot]
8439944051 Bump @octokit/rest from 18.1.1 to 18.3.0 (#338)
Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.1.1 to 18.3.0.
- [Release notes](https://github.com/octokit/rest.js/releases)
- [Commits](https://github.com/octokit/rest.js/compare/v18.1.1...v18.3.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-28 19:11:32 -05:00
Geoffrey Testelin
0e95ddbecb feat(only-labels): add 2 new options to distinguish issue and PR configs (#336)
* feat(assignees): add new option to avoid stale for assignees

closes #271

* test: add more coverage

* docs: fix readme format issue

* docs: reorder and enhance typo

* docs(contributing): add more information about the npm scripts

* feat(only-labels): add new options to customize it for issues and PR

closes #308
2021-02-28 19:08:33 -05:00
Geoffrey Testelin
836169b81a feat(close-label): automatically remove close-label when no longer closed nor locked (#334)
* feat(assignees): add new option to avoid stale for assignees

closes #271

* test: add more coverage

* docs: fix readme format issue

* docs: reorder and enhance typo

* docs(contributing): add more information about the npm scripts

* docs(readme): update the default values to reflect the real applied ones

* feat(close-label): automatically remove it when no longer closed nor locked

closes #278
2021-02-28 19:07:54 -05:00
Geoffrey Testelin
ec96ff65b0 feat(assignees): add 6 new options to avoid stale for assignees (#327)
* feat(assignees): add new option to avoid stale for assignees

closes #271

* test: add more coverage

* docs: fix readme format issue

* docs: reorder and enhance typo

* docs(contributing): add more information about the npm scripts
2021-02-28 06:15:08 -05:00
32 changed files with 5233 additions and 1362 deletions

View File

@@ -17,3 +17,29 @@ Run the tests :heavy_check_mark:
```bash
$ npm test
```
Run the tests and display only the first failing tests :heavy_check_mark:
```bash
$ npm test:only-errors
```
Run the tests with the watch mode :heavy_check_mark:
```bash
$ npm test:watch
```
Run the linter and fix (almost) every issue for you :heavy_check_mark:
```bash
$ npm lint:all:fix
```
### Before creating a PR
Build, lint, package and test everything.
```bash
$ npm all
```

157
README.md
View File

@@ -4,44 +4,56 @@ Warns and then closes issues and PRs that have had no activity for a specified a
### 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 |
| `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 |
Every argument is optional.
| Input | Description |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `repo-token` | PAT(Personal Access Token) for authorizing repository.<br>_Defaults to **${{ github.token }}**_. |
| `days-before-stale` | Idle number of days before marking an issue/PR as stale.<br>_Defaults to **60**_. |
| `days-before-issue-stale` | Idle number of days before marking an issue as stale.<br>_Override `days-before-stale`_. |
| `days-before-pr-stale` | Idle number of days before marking an PR as stale.<br>_Override `days-before-stale`_. |
| `days-before-close` | Idle number of days before closing an stale issue/PR.<br>_Defaults to **7**_. |
| `days-before-issue-close` | Idle number of days before closing an stale issue.<br>_Override `days-before-close`_. |
| `days-before-pr-close` | Idle number of days before closing an stale PR.<br>_Override `days-before-close`_. |
| `stale-issue-message` | Message to post on the stale issue. |
| `stale-pr-message` | Message to post on the stale PR. |
| `close-issue-message` | Message to post on the stale issue while closing it. |
| `close-pr-message` | Message to post on the stale PR while closing it. |
| `stale-issue-label` | Label to apply on the stale issue.<br>_Defaults to **Stale**_. |
| `close-issue-label` | Label to apply on closing issue (automatically removed if no longer closed nor locked). |
| `stale-pr-label` | Label to apply on the stale PR.<br>_Defaults to **Stale**_. |
| `close-pr-label` | Label to apply on the closing PR (automatically removed if no longer closed nor locked). |
| `exempt-issue-labels` | Labels on an issue exempted from being marked as stale. |
| `exempt-pr-labels` | Labels on the PR exempted from being marked as stale. |
| `only-labels` | Only issues and PRs with ALL these labels are checked. Separate multiple labels with commas (eg. "question,answered"). |
| `only-issue-labels` | Only issues with ALL these labels are checked. Separate multiple labels with commas (eg. "question,answered").<br>_Override `only-labels`_. |
| `only-pr-labels` | Only PRs with ALL these labels are checked. Separate multiple labels with commas (eg. "question,answered").<br>_Override `only-labels`_. |
| `any-of-labels` | Only issues and PRs with ANY of these labels are checked. Separate multiple labels with commas (eg. "incomplete,waiting-feedback"). |
| `operations-per-run` | Maximum number of operations per run (GitHub API CRUD related).<br>_Defaults to **30**_. |
| `remove-stale-when-updated` | Remove stale label from issue/PR on updates or comments.<br>_Defaults to **true**_. |
| `debug-only` | Dry-run on action.<br>_Defaults to **false**_. |
| `ascending` | Order to get issues/PR (true is ascending, false is descending).<br>_Defaults to **false**_. |
| `skip-stale-issue-message` | Skip adding stale message on stale issue.<br>_Defaults to **false**_. |
| `skip-stale-pr-message` | Skip adding stale message on stale PR.<br>_Defaults to **false**_. |
| `start-date` | The date used to skip the stale action on issue/PR created before it (ISO 8601 or RFC 2822). |
| `delete-branch` | Delete the git branch after closing a stale pull request.<br>_Defaults to **false**_. |
| `exempt-milestones` | Milestones on an issue or a PR exempted from being marked as stale. |
| `exempt-issue-milestones` | Milestones on an issue exempted from being marked as stale.<br>_Override `exempt-milestones`_. |
| `exempt-pr-milestones` | Milestones on the PR exempted from being marked as stale.<br>_Override `exempt-milestones`_. |
| `exempt-all-milestones` | Exempt all issues and PRs with milestones from being marked as stale.<br>_Priority over `exempt-milestones` rules_. |
| `exempt-all-issue-milestones` | Exempt all issues with milestones from being marked as stale.<br>_Override `exempt-all-milestones`_. |
| `exempt-all-pr-milestones` | Exempt all PRs with milestones from being marked as stale.<br>_Override `exempt-all-milestones`_. |
| `exempt-assignees` | Assignees on an issue or a PR exempted from being marked as stale. |
| `exempt-issue-assignees` | Assignees on an issue exempted from being marked as stale.<br>_Override `exempt-assignees`_. |
| `exempt-pr-assignees` | Assignees on the PR exempted from being marked as stale.<br>_Override `exempt-assignees`_. |
| `exempt-all-assignees` | Exempt all issues and PRs with assignees from being marked as stale.<br>_Priority over `exempt-assignees` rules_. |
| `exempt-all-issue-assignees` | Exempt all issues with assignees from being marked as stale.<br>_Override `exempt-all-assignees`_. |
| `exempt-all-pr-assignees` | Exempt all PRs with assignees from being marked as stale.<br>_Override `exempt-all-assignees`_. |
| `enable-statistics` | Display some statistics at the end of the logs regarding the stale workflow (only when the logs are enabled).<br>_Defaults to **true**_. |
### Usage
See [action.yml](./action.yml) For comprehensive list of options.
See also [action.yml](./action.yml) for a comprehensive list of all the options.
Basic:
@@ -203,12 +215,81 @@ jobs:
exempt-all-pr-milestones: true
```
Avoid stale for specific labels:
```yaml
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
any-of-labels: 'needs-more-info,needs-demo'
# You can opt for 'only-labels' instead if your usecase requires all labels
# to be present in the issue/PR
```
Avoid stale for specific assignees:
```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-issue-assignees: 'marco,polo'
exempt-pr-assignees: 'marco'
```
Avoid stale for all PR with assignees:
```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-assignees: true
```
### Debugging
**Logs:**
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.
There is a lot of logs so this can be very helpful!
**Statistics:**
If the logs are enabled, you can also enable the statistics log which will be visible at the end of the logs once all issues were processed.
This is very helpful to have a quick understanding of the whole stale workflow.
Set `enable-statistics` to `true` in your workflow configuration file.
**Dry-run:**
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.
**More operations:**
You can increase the maximum number of operations per run by passing `operations-per-run` to `1000` for example which will help you to handle more operations in a single stale workflow run.
If the `debug-only` option is enabled, this is very helpful because the workflow will (almost) never reach the GitHub API rate, and you will be able to deep-dive into the logs.
**Job frequency:**
You could change the cron job frequency in the stale workflow to run the stale workflow more often.
Usually this is not very helpful though.
### Contributing

View File

@@ -0,0 +1,107 @@
import {Issue} from '../src/classes/issue';
import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options';
import {IssuesProcessorMock} from './classes/issues-processor-mock';
import {DefaultProcessorOptions} from './constants/default-processor-options';
import {generateIssue} from './functions/generate-issue';
describe('any-of-labels option', () => {
test('should do nothing when not set', async () => {
const sut = new IssuesProcessorBuilder()
.emptyAnyOfLabels()
.issues([{labels: [{name: 'some-label'}]}])
.build();
await sut.processIssues();
expect(sut.staleIssues).toHaveLength(1);
});
test('should skip it when none of the issue labels match', async () => {
const sut = new IssuesProcessorBuilder()
.anyOfLabels('skip-this-issue,and-this-one')
.issues([{labels: [{name: 'some-label'}, {name: 'some-other-label'}]}])
.build();
await sut.processIssues();
expect(sut.staleIssues).toHaveLength(0);
});
test('should skip it when the issue has no labels', async () => {
const sut = new IssuesProcessorBuilder()
.anyOfLabels('skip-this-issue,and-this-one')
.issues([{labels: []}])
.build();
await sut.processIssues();
expect(sut.staleIssues).toHaveLength(0);
});
test('should process it when one of the issue labels match', async () => {
const sut = new IssuesProcessorBuilder()
.anyOfLabels('skip-this-issue,and-this-one')
.issues([{labels: [{name: 'some-label'}, {name: 'skip-this-issue'}]}])
.build();
await sut.processIssues();
expect(sut.staleIssues).toHaveLength(1);
});
test('should process it when all the issue labels match', async () => {
const sut = new IssuesProcessorBuilder()
.anyOfLabels('skip-this-issue,and-this-one')
.issues([{labels: [{name: 'and-this-one'}, {name: 'skip-this-issue'}]}])
.build();
await sut.processIssues();
expect(sut.staleIssues).toHaveLength(1);
});
});
class IssuesProcessorBuilder {
private _options: IIssuesProcessorOptions;
private _issues: Issue[];
constructor() {
this._options = {...DefaultProcessorOptions};
this._issues = [];
}
anyOfLabels(labels: string): IssuesProcessorBuilder {
this._options.anyOfLabels = labels;
return this;
}
emptyAnyOfLabels(): IssuesProcessorBuilder {
return this.anyOfLabels('');
}
issues(issues: Partial<Issue>[]): IssuesProcessorBuilder {
this._issues = issues.map(
(issue, index): Issue =>
generateIssue(
this._options,
index,
issue.title || 'Issue title',
issue.updated_at || '2000-01-01T00:00:00Z', // we only care about stale/expired issues here
issue.created_at || '2000-01-01T00:00:00Z',
issue.isPullRequest || false,
issue.labels ? issue.labels.map(label => label.name) : []
)
);
return this;
}
build(): IssuesProcessorMock {
return new IssuesProcessorMock(
this._options,
async () => 'abot',
async p => (p === 1 ? this._issues : []),
async () => [],
async () => new Date().toDateString()
);
}
}

413
__tests__/assignees.spec.ts Normal file
View File

@@ -0,0 +1,413 @@
import {Issue} from '../src/classes/issue';
import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options';
import {IssuesProcessorMock} from './classes/issues-processor-mock';
import {DefaultProcessorOptions} from './constants/default-processor-options';
import {generateIssue} from './functions/generate-issue';
interface ITestData {
id: number;
isPullRequest: boolean;
assignees: string[];
exemptAllAssignees: boolean;
exemptAllIssueAssignees: boolean | undefined;
exemptAllPrAssignees: boolean | undefined;
exemptAssignees: string;
exemptIssueAssignees: string;
exemptPrAssignees: string;
shouldStale: boolean;
description: string;
}
describe('assignees options', (): void => {
let opts: IIssuesProcessorOptions;
let testIssueList: Issue[];
let processor: IssuesProcessorMock;
const setTestIssueList = (
isPullRequest: boolean,
assignees: string[],
id: number
) => {
testIssueList = [
generateIssue(
opts,
id,
'My first issue',
'2020-01-01T17:00:00Z',
'2020-01-01T17:00:00Z',
isPullRequest,
undefined,
undefined,
undefined,
undefined,
assignees
)
];
};
const setProcessor = () => {
processor = new IssuesProcessorMock(
opts,
async () => 'abot',
async p => (p === 1 ? testIssueList : []),
async () => [],
async () => new Date().toDateString()
);
};
beforeEach((): void => {
opts = {...DefaultProcessorOptions};
});
describe.each`
id | isPullRequest | assignees | exemptAllAssignees | exemptAllIssueAssignees | exemptAllPrAssignees | exemptAssignees | exemptIssueAssignees | exemptPrAssignees | shouldStale | description
${100} | ${false} | ${[]} | ${false} | ${undefined} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee'}
${101} | ${false} | ${[]} | ${true} | ${undefined} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and only exemptAllAssignees is enabled'}
${102} | ${false} | ${[]} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and only exemptAllIssueAssignees is enabled'}
${103} | ${false} | ${[]} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and only exemptAllPrAssignees is enabled'}
${104} | ${false} | ${[]} | ${true} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is disabled'}
${105} | ${false} | ${[]} | ${true} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is enabled'}
${106} | ${false} | ${[]} | ${true} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is disabled'}
${107} | ${false} | ${[]} | ${true} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is enabled'}
${108} | ${false} | ${[]} | ${false} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is disabled'}
${109} | ${false} | ${[]} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue does not have an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is enabled'}
${200} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is disabled'}
${201} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is enabled'}
${202} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${''} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and only exemptAllAssignees is enabled'}
${203} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and only exemptAllIssueAssignees is enabled'}
${204} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and only exemptAllPrAssignees is enabled'}
${205} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is disabled'}
${206} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is enabled'}
${207} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is disabled'}
${208} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is enabled'}
${209} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is disabled'}
${210} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is enabled'}
${211} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is disabled'}
${212} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is enabled'}
${213} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is disabled'}
${300} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${301} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees has a different assignee'}
${302} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAssignees has a different assignee'}
${303} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees has a different assignee'}
${304} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled and exemptAssignees has a different assignee'}
${305} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees has a different assignee'}
${306} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees has a different assignee'}
${307} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${308} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees has a different assignee'}
${309} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees has a different assignee'}
${310} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees has a different assignee'}
${311} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${312} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees has a different assignee'}
${313} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${400} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${401} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${402} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAssignees has the same assignee'}
${403} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees has the same assignee'}
${404} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${405} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees has the same assignee'}
${406} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees has the same assignee'}
${407} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${408} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${409} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees has the same assignee'}
${410} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees has the same assignee'}
${411} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${412} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${413} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${500} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${501} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${502} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${503} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${504} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${505} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${506} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${507} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${508} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${509} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${510} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${511} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${512} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${513} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${600} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${601} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${602} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${603} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${604} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${605} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${606} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${607} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${608} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${609} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${610} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${611} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${612} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${613} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${700} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${701} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${702} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${703} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${704} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${705} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${706} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${707} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${708} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${709} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${710} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${711} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${712} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${713} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${800} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${801} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${802} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${803} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${804} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${805} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${806} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${807} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${808} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${809} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${810} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${811} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${812} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${813} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'assignee'} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${900} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${901} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${902} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${903} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${904} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${905} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${906} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${907} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${908} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${909} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${910} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${911} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${912} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${913} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'bad'} | ${''} | ${true} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${1000} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1001} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1002} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1003} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1004} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1005} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1006} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1007} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1008} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1009} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1010} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1011} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1012} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1013} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${1100} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1101} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1102} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1103} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1104} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1105} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1106} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1107} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1108} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1109} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1110} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1111} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1112} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1113} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${1200} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1201} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1202} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1203} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1204} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1205} | ${false} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1206} | ${false} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1207} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1208} | ${false} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1209} | ${false} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1210} | ${false} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1211} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1212} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1213} | ${false} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the issue has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${1300} | ${true} | ${[]} | ${false} | ${undefined} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee'}
${1301} | ${true} | ${[]} | ${true} | ${undefined} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and only exemptAllAssignees is enabled'}
${1302} | ${true} | ${[]} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and only exemptAllIssueAssignees is enabled'}
${1303} | ${true} | ${[]} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and only exemptAllPrAssignees is enabled'}
${1304} | ${true} | ${[]} | ${true} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is disabled'}
${1305} | ${true} | ${[]} | ${true} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is enabled'}
${1306} | ${true} | ${[]} | ${true} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is disabled'}
${1307} | ${true} | ${[]} | ${true} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is enabled'}
${1308} | ${true} | ${[]} | ${false} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is disabled'}
${1309} | ${true} | ${[]} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request does not have an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is enabled'}
${1400} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is disabled'}
${1401} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is enabled'}
${1402} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${''} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and only exemptAllAssignees is enabled'}
${1403} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and only exemptAllIssueAssignees is enabled'}
${1404} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and only exemptAllPrAssignees is enabled'}
${1405} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is disabled'}
${1406} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAllIssueAssignees is enabled'}
${1407} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is disabled'}
${1408} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAllPrAssignees is enabled'}
${1409} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is disabled'}
${1410} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled and exemptAllIssueAssignees is enabled'}
${1411} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is disabled'}
${1412} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${''} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is enabled'}
${1413} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${''} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled and exemptAllPrAssignees is disabled'}
${1500} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${1501} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees has a different assignee'}
${1502} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAssignees has a different assignee'}
${1503} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees has a different assignee'}
${1504} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled and exemptAssignees has a different assignee'}
${1505} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees has a different assignee'}
${1506} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees has a different assignee'}
${1507} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${1508} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees has a different assignee'}
${1509} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees has a different assignee'}
${1510} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees has a different assignee'}
${1511} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${1513} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has a different assignee'}
${1600} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${1601} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${1602} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAssignees has the same assignee'}
${1603} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees has the same assignee'}
${1604} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${1605} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees has the same assignee'}
${1606} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees has the same assignee'}
${1607} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${1608} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${1609} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees has the same assignee'}
${1610} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees has the same assignee'}
${1611} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${1612} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees has the same assignee'}
${1613} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees has the same assignee'}
${1701} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1702} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1703} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1704} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1705} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1706} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1707} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1708} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1709} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1710} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1711} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'bad'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptIssueAssignees has a different assignee'}
${1800} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1801} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1802} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1803} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1804} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1805} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${'assignee'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1806} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1807} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1808} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${'assignee'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1809} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1810} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${'assignee'} | ${''} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptIssueAssignees has the same assignee'}
${1900} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1901} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1902} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1903} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1904} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1905} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1906} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1907} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1908} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1909} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1910} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${1911} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled and exemptAssignees and exemptPrAssignees has a different assignee'}
${2000} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2001} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2002} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2003} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2004} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2005} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2006} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2007} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2008} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2009} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2010} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'bad'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has a different assignee and exemptPrAssignees has the same assignee'}
${2100} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2101} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2102} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2103} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2104} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2105} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2106} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2107} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2108} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2109} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2110} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'bad'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has a different assignee'}
${2200} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2201} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2202} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2203} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2204} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2205} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2206} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2207} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2208} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2209} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2210} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2311} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2312} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2313} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${'assignee'} | ${''} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptIssueAssignees has the same assignee'}
${2300} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2301} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2302} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2303} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2304} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2305} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2306} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2307} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2308} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2309} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2310} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'bad'} | ${true} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2311} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'bad'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has a different assignee'}
${2400} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2401} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2402} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2403} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2404} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2405} | ${true} | ${['assignee']} | ${true} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2406} | ${true} | ${['assignee']} | ${true} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2407} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2408} | ${true} | ${['assignee']} | ${true} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is enabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2409} | ${true} | ${['assignee']} | ${false} | ${false} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2410} | ${true} | ${['assignee']} | ${false} | ${true} | ${undefined} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllIssueAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2411} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2412} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${true} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is enabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
${2413} | ${true} | ${['assignee']} | ${false} | ${undefined} | ${false} | ${'assignee'} | ${''} | ${'assignee'} | ${false} | ${'when the pull request has an assignee and exemptAllAssignees is disabled, exemptAllPrAssignees is disabled, exemptAssignees has the same assignee and exemptPrAssignees has the same assignee'}
`(
'$description',
({
id,
isPullRequest,
assignees,
exemptAllAssignees,
exemptAllIssueAssignees,
exemptAllPrAssignees,
exemptAssignees,
exemptIssueAssignees,
exemptPrAssignees,
shouldStale
}: ITestData): void => {
beforeEach((): void => {
opts.exemptAllAssignees = exemptAllAssignees;
opts.exemptAllIssueAssignees = exemptAllIssueAssignees;
opts.exemptAllPrAssignees = exemptAllPrAssignees;
opts.exemptAssignees = exemptAssignees;
opts.exemptIssueAssignees = exemptIssueAssignees;
opts.exemptPrAssignees = exemptPrAssignees;
setTestIssueList(isPullRequest, assignees, id);
setProcessor();
});
test(`should${
shouldStale ? '' : ' not'
} be marked as stale`, async () => {
expect.assertions(3);
await processor.processIssues(1);
expect(processor.staleIssues).toHaveLength(shouldStale ? 1 : 0);
expect(processor.closedIssues).toHaveLength(0);
expect(processor.removedLabelIssues).toHaveLength(0);
});
}
);
});

View File

@@ -0,0 +1,38 @@
import {Issue} from '../../src/classes/issue';
import {IssuesProcessor} from '../../src/classes/issues-processor';
import {IComment} from '../../src/interfaces/comment';
import {IIssuesProcessorOptions} from '../../src/interfaces/issues-processor-options';
export class IssuesProcessorMock extends IssuesProcessor {
constructor(
options: IIssuesProcessorOptions,
getActor?: () => Promise<string>,
getIssues?: (page: number) => Promise<Issue[]>,
listIssueComments?: (
issueNumber: number,
sinceDate: string
) => Promise<IComment[]>,
getLabelCreationDate?: (
issue: Issue,
label: string
) => Promise<string | undefined>
) {
super(options);
if (getActor) {
this.getActor = getActor;
}
if (getIssues) {
this.getIssues = getIssues;
}
if (listIssueComments) {
this.listIssueComments = listIssueComments;
}
if (getLabelCreationDate) {
this.getLabelCreationDate = getLabelCreationDate;
}
}
}

View File

@@ -19,6 +19,9 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
closePrLabel: '',
exemptPrLabels: '',
onlyLabels: '',
onlyIssueLabels: '',
onlyPrLabels: '',
anyOfLabels: '',
operationsPerRun: 100,
debugOnly: true,
removeStaleWhenUpdated: false,
@@ -32,5 +35,12 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
exemptPrMilestones: '',
exemptAllMilestones: false,
exemptAllIssueMilestones: undefined,
exemptAllPrMilestones: undefined
exemptAllPrMilestones: undefined,
exemptAssignees: '',
exemptIssueAssignees: '',
exemptPrAssignees: '',
exemptAllAssignees: false,
exemptAllIssueAssignees: undefined,
exemptAllPrAssignees: undefined,
enableStatistics: false
});

View File

@@ -0,0 +1,19 @@
import {IIssue} from '../../src/interfaces/issue';
export function generateIIssue(
partialIssue?: Readonly<Partial<IIssue>>
): IIssue {
return {
milestone: undefined,
assignees: [],
labels: [],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
number: Math.round(Math.random() * 5000),
pull_request: null,
title: 'dummy-title',
locked: false,
state: 'dummy-state',
...partialIssue
};
}

View File

@@ -1,4 +1,5 @@
import {Issue} from '../../src/classes/issue';
import {IAssignee} from '../../src/interfaces/assignee';
import {IIssuesProcessorOptions} from '../../src/interfaces/issues-processor-options';
import {IsoDateString} from '../../src/types/iso-date-string';
@@ -12,7 +13,8 @@ export function generateIssue(
labels: string[] = [],
isClosed = false,
isLocked = false,
milestone: string | undefined = undefined
milestone: string | undefined = undefined,
assignees: string[] = []
): Issue {
return new Issue(options, {
number: id,
@@ -29,6 +31,13 @@ export function generateIssue(
? {
title: milestone
}
: undefined
: undefined,
assignees: assignees.map(
(assignee: Readonly<string>): IAssignee => {
return {
login: assignee
};
}
)
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
import {Issue} from '../src/classes/issue';
import {IssuesProcessor} from '../src/classes/issues-processor';
import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options';
import {IssuesProcessorMock} from './classes/issues-processor-mock';
import {DefaultProcessorOptions} from './constants/default-processor-options';
import {generateIssue} from './functions/generate-issue';
@@ -9,13 +9,12 @@ interface ITestData {
milestone: string;
name: string;
shouldStale: boolean;
exemptAllMilestones: boolean;
}
describe('milestones options', (): void => {
let opts: IIssuesProcessorOptions;
let testIssueList: Issue[];
let processor: IssuesProcessor;
let processor: IssuesProcessorMock;
const setTestIssueList = (
isPullRequest: boolean,
@@ -38,7 +37,7 @@ describe('milestones options', (): void => {
};
const setProcessor = () => {
processor = new IssuesProcessor(
processor = new IssuesProcessorMock(
opts,
async () => 'abot',
async p => (p === 1 ? testIssueList : []),

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ inputs:
description: 'The label to apply when an issue is closed.'
required: false
exempt-issue-labels:
description: 'The labels that mean an issue is exempt from being marked stale. Separate multiple labels with commas (eg. "label1,label2")'
description: 'The labels that mean an issue is exempt from being marked stale. Separate multiple labels with commas (eg. "label1,label2").'
default: ''
required: false
stale-pr-label:
@@ -57,11 +57,11 @@ 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 as 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 pull request is exempt from being marked as 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:
@@ -85,7 +85,19 @@ inputs:
default: ''
required: false
only-labels:
description: 'Only issues or pull requests with all of these labels are checked if stale. Defaults to `[]` (disabled) and can be a comma-separated list of labels.'
description: 'Only issues or pull requests with all of these labels are checked if stale. Defaults to `` (disabled) and can be a comma-separated list of labels.'
default: ''
required: false
any-of-labels:
description: 'Only issues or pull requests with at least one of these labels are checked if stale. Defaults to `` (disabled) and can be a comma-separated list of labels.'
default: ''
required: false
only-issue-labels:
description: 'Only issues with all of these labels are checked if stale. Defaults to `[]` (disabled) and can be a comma-separated list of labels. Override "only-labels" option regarding only the issues.'
default: ''
required: false
only-pr-labels:
description: 'Only pull requests with all of these labels are checked if stale. Defaults to `[]` (disabled) and can be a comma-separated list of labels. Override "only-labels" option regarding only the pull requests.'
default: ''
required: false
operations-per-run:
@@ -101,7 +113,7 @@ inputs:
default: 'false'
required: false
ascending:
description: 'The order to get issues or pull requests. Defaults to false, which is descending'
description: 'The order to get issues or pull requests. Defaults to false, which is descending.'
default: 'false'
required: false
skip-stale-pr-message:
@@ -120,6 +132,34 @@ inputs:
description: 'The date used to skip the stale action on issue/pull request created before it (ISO 8601 or RFC 2822).'
default: ''
required: false
exempt-assignees:
description: 'The assignees which exempt an issue or a pull request from being marked as stale. Separate multiple assignees with commas (eg. "user1,user2").'
default: ''
required: false
exempt-issue-assignees:
description: 'The assignees which exempt an issue from being marked as stale. Separate multiple assignees with commas (eg. "user1,user2"). Override "exempt-assignees" option regarding only the issues.'
default: ''
required: false
exempt-pr-assignees:
description: 'The assignees which exempt a pull request from being marked as stale. Separate multiple assignees with commas (eg. "user1,user2"). Override "exempt-assignees" option regarding only the pull requests.'
default: ''
required: false
exempt-all-assignees:
description: 'Exempt all issues and pull requests with assignees from being marked as stale. Default to false.'
default: 'false'
required: false
exempt-all-issue-assignees:
description: 'Exempt all issues with assignees from being marked as stale. Override "exempt-all-assignees" option regarding only the issues.'
default: ''
required: false
exempt-all-pr-assignees:
description: 'Exempt all pull requests with assignees from being marked as stale. Override "exempt-all-assignees" option regarding only the pull requests.'
default: ''
required: false
enable-statistics:
description: 'Display some statistics at the end regarding the stale workflow (only when the logs are enabled).'
default: 'true'
required: false
runs:
using: 'node12'
main: 'dist/index.js'

965
dist/index.js vendored

File diff suppressed because it is too large Load Diff

573
package-lock.json generated
View File

@@ -418,9 +418,9 @@
}
},
"@eslint/eslintrc": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
"integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
"integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
@@ -430,7 +430,6 @@
"ignore": "^4.0.6",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
"lodash": "^4.17.20",
"minimatch": "^3.0.4",
"strip-json-comments": "^3.1.1"
},
@@ -474,12 +473,6 @@
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"dev": true
}
}
},
@@ -1568,9 +1561,9 @@
}
},
"@octokit/openapi-types": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-4.0.3.tgz",
"integrity": "sha512-CXCe1Zzc/WhjpuAEgoUktAinZJ02l6W8q1hDkwBtaonEtO6cjo/3Pyb2J1t5y2q/SvjESDJ77xZ9UVHqQVvihw=="
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-5.3.0.tgz",
"integrity": "sha512-5q2qBz4iZ0xS/DEJ0ROusFbN4cVlbJE9GvOByen+mv7artuGXfVhONqcuRd7jYN2glTmCnzcZw+X6LrjRVqs0A=="
},
"@octokit/plugin-paginate-rest": {
"version": "2.2.4",
@@ -1620,14 +1613,14 @@
}
},
"@octokit/rest": {
"version": "18.1.1",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.1.1.tgz",
"integrity": "sha512-ZcCHMyfGT1qtJD72usigAfUQ6jU89ZUPFb2AOubR6WZ7/RRFVZUENVm1I2yvJBUicqTujezPW9cY1+o3Mb4rNA==",
"version": "18.3.3",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.3.3.tgz",
"integrity": "sha512-OxElwBanZn1AShCaIrRTLM9PwhGE5/busMke/go30OWAQ+eJMD7Us/67mtapE77EYY4FM2tvb4Eg25rZaA/NPA==",
"requires": {
"@octokit/core": "^3.2.3",
"@octokit/plugin-paginate-rest": "^2.6.2",
"@octokit/plugin-request-log": "^1.0.2",
"@octokit/plugin-rest-endpoint-methods": "4.10.3"
"@octokit/plugin-rest-endpoint-methods": "4.13.3"
},
"dependencies": {
"@octokit/auth-token": {
@@ -1662,19 +1655,19 @@
}
},
"@octokit/plugin-paginate-rest": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.9.1.tgz",
"integrity": "sha512-8wnuWGjwDIEobbBet2xAjZwgiMVTgIer5wBsnGXzV3lJ4yqphLU2FEMpkhSrDx7y+WkZDfZ+V+1cFMZ1mAaFag==",
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.11.0.tgz",
"integrity": "sha512-7L9xQank2G3r1dGqrVPo1z62V5utbykOUzlmNHPz87Pww/JpZQ9KyG5CHtUzgmB4n5iDRKYNK/86A8D98HP0yA==",
"requires": {
"@octokit/types": "^6.8.0"
"@octokit/types": "^6.11.0"
}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "4.10.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.10.3.tgz",
"integrity": "sha512-CsNQeVY34Vs9iea2Z9/TCPlebxv6KpjO9f1BUPz+14qundTSYT9kgf8j5wA1k37VstfBQ4xnuURYdnbGzJBJXw==",
"version": "4.13.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.3.tgz",
"integrity": "sha512-nMGS2osFcWXRfHkDR0d+lB1zpMPTZJ0NjysPUfs7BT5/juNG/Q0+5UB6nC1f62jPzun154qekzwOb7Q5oahCXQ==",
"requires": {
"@octokit/types": "^6.8.3",
"@octokit/types": "^6.12.0",
"deprecation": "^2.3.1"
}
},
@@ -1694,12 +1687,11 @@
}
},
"@octokit/types": {
"version": "6.8.4",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.8.4.tgz",
"integrity": "sha512-iKAMx//mBk74NwXdeKg8kdYO5zb1n6Ypk5uxwM96U35rJQv4Y8lMQxfzhN8QyzQHaZkxQsl28bn+MPEhiqXb7w==",
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.12.0.tgz",
"integrity": "sha512-KwOf16soD7aDEEi/PgNeJlHzjZPfrmmNy+7WezSdrpnqZ7YImBJcNnX9+5RUHt1MnA4h8oISRHTqaZDGsX9DRQ==",
"requires": {
"@octokit/openapi-types": "^4.0.3",
"@types/node": ">= 8"
"@octokit/openapi-types": "^5.3.0"
}
},
"is-plain-object": {
@@ -1847,9 +1839,9 @@
}
},
"@types/node": {
"version": "14.14.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.28.tgz",
"integrity": "sha512-lg55ArB+ZiHHbBBttLpzD07akz0QPrZgUODNakeC09i62dnrywr9mFErHuaPlB6I7z+sEbK+IYmplahvplCj2g=="
"version": "14.14.31",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz",
"integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g=="
},
"@types/normalize-package-data": {
"version": "2.4.0",
@@ -1891,13 +1883,13 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.1.tgz",
"integrity": "sha512-yW2epMYZSpNJXZy22Biu+fLdTG8Mn6b22kR3TqblVk50HGNV8Zya15WAXuQCr8tKw4Qf1BL4QtI6kv6PCkLoJw==",
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.16.1.tgz",
"integrity": "sha512-SK777klBdlkUZpZLC1mPvyOWk9yAFCWmug13eAjVQ4/Q1LATE/NbcQL1xDHkptQkZOLnPmLUA1Y54m8dqYwnoQ==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "4.15.1",
"@typescript-eslint/scope-manager": "4.15.1",
"@typescript-eslint/experimental-utils": "4.16.1",
"@typescript-eslint/scope-manager": "4.16.1",
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.15",
@@ -1907,43 +1899,65 @@
},
"dependencies": {
"@typescript-eslint/experimental-utils": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.1.tgz",
"integrity": "sha512-9LQRmOzBRI1iOdJorr4jEnQhadxK4c9R2aEAsm7WE/7dq8wkKD1suaV0S/JucTL8QlYUPU1y2yjqg+aGC0IQBQ==",
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.16.1.tgz",
"integrity": "sha512-0Hm3LSlMYFK17jO4iY3un1Ve9x1zLNn4EM50Lia+0EV99NdbK+cn0er7HC7IvBA23mBg3P+8dUkMXy4leL33UQ==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
"@typescript-eslint/scope-manager": "4.15.1",
"@typescript-eslint/types": "4.15.1",
"@typescript-eslint/typescript-estree": "4.15.1",
"@typescript-eslint/scope-manager": "4.16.1",
"@typescript-eslint/types": "4.16.1",
"@typescript-eslint/typescript-estree": "4.16.1",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
}
},
"@typescript-eslint/scope-manager": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.1.tgz",
"integrity": "sha512-ibQrTFcAm7yG4C1iwpIYK7vDnFg+fKaZVfvyOm3sNsGAerKfwPVFtYft5EbjzByDJ4dj1WD8/34REJfw/9wdVA==",
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz",
"integrity": "sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.15.1",
"@typescript-eslint/visitor-keys": "4.15.1"
"@typescript-eslint/types": "4.16.1",
"@typescript-eslint/visitor-keys": "4.16.1"
}
},
"@typescript-eslint/types": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.16.1.tgz",
"integrity": "sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.1.tgz",
"integrity": "sha512-z8MN3CicTEumrWAEB2e2CcoZa3KP9+SMYLIA2aM49XW3cWIaiVSOAGq30ffR5XHxRirqE90fgLw3e6WmNx5uNw==",
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz",
"integrity": "sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.15.1",
"@typescript-eslint/visitor-keys": "4.15.1",
"@typescript-eslint/types": "4.16.1",
"@typescript-eslint/visitor-keys": "4.16.1",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz",
"integrity": "sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.16.1",
"eslint-visitor-keys": "^2.0.0"
}
},
"eslint-visitor-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
"integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
"dev": true
}
}
},
@@ -1962,41 +1976,63 @@
}
},
"@typescript-eslint/parser": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.1.tgz",
"integrity": "sha512-V8eXYxNJ9QmXi5ETDguB7O9diAXlIyS+e3xzLoP/oVE4WCAjssxLIa0mqCLsCGXulYJUfT+GV70Jv1vHsdKwtA==",
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.16.1.tgz",
"integrity": "sha512-/c0LEZcDL5y8RyI1zLcmZMvJrsR6SM1uetskFkoh3dvqDKVXPsXI+wFB/CbVw7WkEyyTKobC1mUNp/5y6gRvXg==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "4.15.1",
"@typescript-eslint/types": "4.15.1",
"@typescript-eslint/typescript-estree": "4.15.1",
"@typescript-eslint/scope-manager": "4.16.1",
"@typescript-eslint/types": "4.16.1",
"@typescript-eslint/typescript-estree": "4.16.1",
"debug": "^4.1.1"
},
"dependencies": {
"@typescript-eslint/scope-manager": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.1.tgz",
"integrity": "sha512-ibQrTFcAm7yG4C1iwpIYK7vDnFg+fKaZVfvyOm3sNsGAerKfwPVFtYft5EbjzByDJ4dj1WD8/34REJfw/9wdVA==",
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz",
"integrity": "sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.15.1",
"@typescript-eslint/visitor-keys": "4.15.1"
"@typescript-eslint/types": "4.16.1",
"@typescript-eslint/visitor-keys": "4.16.1"
}
},
"@typescript-eslint/types": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.16.1.tgz",
"integrity": "sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.1.tgz",
"integrity": "sha512-z8MN3CicTEumrWAEB2e2CcoZa3KP9+SMYLIA2aM49XW3cWIaiVSOAGq30ffR5XHxRirqE90fgLw3e6WmNx5uNw==",
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz",
"integrity": "sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.15.1",
"@typescript-eslint/visitor-keys": "4.15.1",
"@typescript-eslint/types": "4.16.1",
"@typescript-eslint/visitor-keys": "4.16.1",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz",
"integrity": "sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.16.1",
"eslint-visitor-keys": "^2.0.0"
}
},
"eslint-visitor-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
"integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
"dev": true
}
}
},
@@ -2174,13 +2210,15 @@
"dev": true
},
"array-includes": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz",
"integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
"integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
"dev": true,
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0",
"es-abstract": "^1.18.0-next.2",
"get-intrinsic": "^1.1.1",
"is-string": "^1.0.5"
}
},
@@ -2197,13 +2235,14 @@
"dev": true
},
"array.prototype.flat": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz",
"integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz",
"integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==",
"dev": true,
"requires": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.1"
"es-abstract": "^1.18.0-next.1"
}
},
"asn1": {
@@ -2566,6 +2605,16 @@
}
}
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -3022,22 +3071,27 @@
}
},
"es-abstract": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
"integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
"dev": true,
"requires": {
"call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"get-intrinsic": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"has-symbols": "^1.0.2",
"is-callable": "^1.2.3",
"is-negative-zero": "^2.0.1",
"is-regex": "^1.1.2",
"is-string": "^1.0.5",
"object-inspect": "^1.9.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
"object.assign": "^4.1.2",
"string.prototype.trimend": "^1.0.4",
"string.prototype.trimstart": "^1.0.4",
"unbox-primitive": "^1.0.0"
}
},
"es-to-primitive": {
@@ -3080,13 +3134,13 @@
}
},
"eslint": {
"version": "7.20.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz",
"integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==",
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz",
"integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==",
"dev": true,
"requires": {
"@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.3.0",
"@eslint/eslintrc": "^0.4.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -3099,7 +3153,7 @@
"espree": "^7.3.1",
"esquery": "^1.4.0",
"esutils": "^2.0.2",
"file-entry-cache": "^6.0.0",
"file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
"globals": "^12.1.0",
@@ -3140,9 +3194,9 @@
"dev": true
},
"@babel/highlight": {
"version": "7.12.13",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
"version": "7.13.8",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz",
"integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.12.11",
@@ -3314,9 +3368,9 @@
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"optionator": {
@@ -3381,13 +3435,10 @@
}
},
"eslint-config-prettier": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz",
"integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==",
"dev": true,
"requires": {
"get-stdin": "^6.0.0"
}
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz",
"integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==",
"dev": true
},
"eslint-import-resolver-node": {
"version": "0.3.4",
@@ -3462,14 +3513,14 @@
}
},
"eslint-plugin-github": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.1.1.tgz",
"integrity": "sha512-MzCh4P4zVvR/13AHtumzZ3znq0cbUE7lXehyBEpFURD/EHdx/+7qW+0c+ySTrteImpX9LGLJFTYNtu10BifkbQ==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.1.2.tgz",
"integrity": "sha512-ng738ugjNNF0BY4HQ9qo51xxQZZYtdYC//dhis+j8FL9BEsQ6x5BPmMbaKNP7PZ9wBUBTA7U8p4xFxUJlMi/PA==",
"dev": true,
"requires": {
"@typescript-eslint/eslint-plugin": ">=2.25.0",
"@typescript-eslint/parser": ">=2.25.0",
"eslint-config-prettier": ">=6.10.1",
"eslint-config-prettier": ">=8.0.0",
"eslint-plugin-eslint-comments": ">=3.0.1",
"eslint-plugin-import": ">=2.20.1",
"eslint-plugin-prettier": ">=3.1.2",
@@ -3479,9 +3530,9 @@
}
},
"eslint-plugin-import": {
"version": "2.22.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz",
"integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==",
"version": "2.22.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz",
"integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==",
"dev": true,
"requires": {
"array-includes": "^3.1.1",
@@ -3489,7 +3540,7 @@
"contains-path": "^0.1.0",
"debug": "^2.6.9",
"doctrine": "1.5.0",
"eslint-import-resolver-node": "^0.3.3",
"eslint-import-resolver-node": "^0.3.4",
"eslint-module-utils": "^2.6.0",
"has": "^1.0.3",
"minimatch": "^3.0.4",
@@ -3518,6 +3569,15 @@
"isarray": "^1.0.0"
}
},
"is-core-module": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
"integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -3535,11 +3595,12 @@
}
},
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
"dev": true,
"requires": {
"is-core-module": "^2.2.0",
"path-parse": "^1.0.6"
}
}
@@ -3555,9 +3616,9 @@
}
},
"eslint-plugin-prettier": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz",
"integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz",
"integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==",
"dev": true,
"requires": {
"prettier-linter-helpers": "^1.0.0"
@@ -3989,9 +4050,9 @@
}
},
"file-entry-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz",
"integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true,
"requires": {
"flat-cache": "^3.0.4"
@@ -4114,18 +4175,23 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"get-intrinsic": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
}
},
"get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
"dev": true
},
"get-stdin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
"integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
"dev": true
},
"get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
@@ -4208,9 +4274,9 @@
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
"dev": true
},
"growly": {
@@ -4245,6 +4311,12 @@
"function-bind": "^1.1.1"
}
},
"has-bigints": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
"integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
"dev": true
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -4252,9 +4324,9 @@
"dev": true
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
"dev": true
},
"has-value": {
@@ -4484,6 +4556,21 @@
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"is-bigint": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz",
"integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==",
"dev": true
},
"is-boolean-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz",
"integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==",
"dev": true,
"requires": {
"call-bind": "^1.0.0"
}
},
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
@@ -4491,9 +4578,9 @@
"dev": true
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
"integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==",
"dev": true
},
"is-ci": {
@@ -4599,6 +4686,12 @@
"is-extglob": "^2.1.1"
}
},
"is-negative-zero": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
"integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
"dev": true
},
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
@@ -4619,6 +4712,12 @@
}
}
},
"is-number-object": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz",
"integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==",
"dev": true
},
"is-plain-object": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz",
@@ -4631,12 +4730,13 @@
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
"integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
"dev": true,
"requires": {
"has": "^1.0.3"
"call-bind": "^1.0.2",
"has-symbols": "^1.0.1"
}
},
"is-stream": {
@@ -7140,6 +7240,67 @@
}
}
},
"jest-silent-reporter": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/jest-silent-reporter/-/jest-silent-reporter-0.4.0.tgz",
"integrity": "sha512-X9pLv87dOba/Ou6E3MrT0HmszG56oZSykgyhIlcL9SErjikPObprxAz58831g4Ngl8TKwpU73pAfkPpjYaMSxg==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
"jest-util": "^26.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"jest-snapshot": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz",
@@ -8000,9 +8161,9 @@
}
},
"object-inspect": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
"integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
"integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==",
"dev": true
},
"object-keys": {
@@ -8029,15 +8190,15 @@
}
},
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
"integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"has-symbols": "^1.0.1",
"object-keys": "^1.1.1"
}
},
"object.pick": {
@@ -8058,14 +8219,14 @@
}
},
"object.values": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz",
"integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz",
"integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==",
"dev": true,
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.1",
"function-bind": "^1.1.1",
"es-abstract": "^1.18.0-next.2",
"has": "^1.0.3"
}
},
@@ -9132,45 +9293,23 @@
}
},
"string.prototype.trimend": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
"integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
"integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"string.prototype.trimleft": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
"integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5",
"string.prototype.trimstart": "^1.0.0"
}
},
"string.prototype.trimright": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
"integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5",
"string.prototype.trimend": "^1.0.0"
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
}
},
"string.prototype.trimstart": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
"integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
"integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
}
},
"strip-ansi": {
@@ -9267,9 +9406,9 @@
},
"dependencies": {
"ajv": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.0.tgz",
"integrity": "sha512-svS9uILze/cXbH0z2myCK2Brqprx/+JJYK5pHicT/GQiBfzzhUVAIT6MwqJg8y4xV/zoGsUeuPuwtoiKSGE15g==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz",
"integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@@ -9285,9 +9424,9 @@
"dev": true
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}
}
@@ -9399,12 +9538,11 @@
}
},
"ts-jest": {
"version": "26.5.1",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.1.tgz",
"integrity": "sha512-G7Rmo3OJMvlqE79amJX8VJKDiRcd7/r61wh9fnvvG8cAjhA9edklGw/dCxRSQmfZ/z8NDums5srSVgwZos1qfg==",
"version": "26.5.3",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.3.tgz",
"integrity": "sha512-nBiiFGNvtujdLryU7MiMQh1iPmnZ/QvOskBbD2kURiI1MwqvxlxNnaAB/z9TbslMqCsSbu5BXvSSQPc5tvHGeA==",
"dev": true,
"requires": {
"@types/jest": "26.x",
"bs-logger": "0.x",
"buffer-from": "1.x",
"fast-json-stable-stringify": "2.x",
@@ -9418,9 +9556,9 @@
},
"dependencies": {
"yargs-parser": {
"version": "20.2.5",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz",
"integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==",
"version": "20.2.6",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.6.tgz",
"integrity": "sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA==",
"dev": true
}
}
@@ -9514,11 +9652,23 @@
}
},
"typescript": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
"dev": true
},
"unbox-primitive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz",
"integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"has-bigints": "^1.0.0",
"has-symbols": "^1.0.0",
"which-boxed-primitive": "^1.0.1"
}
},
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@@ -9723,6 +9873,19 @@
"isexe": "^2.0.0"
}
},
"which-boxed-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
"dev": true,
"requires": {
"is-bigint": "^1.0.1",
"is-boolean-object": "^1.1.0",
"is-number-object": "^1.0.4",
"is-string": "^1.0.5",
"is-symbol": "^1.0.3"
}
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",

View File

@@ -14,6 +14,8 @@
"lint:all:fix": "npm run format && npm run lint:fix",
"pack": "ncc build",
"test": "jest",
"test:only-errors": "jest --reporters jest-silent-reporter --silent",
"test:watch": "jest --watch --notify --expandf",
"all": "npm run build && npm run format && npm run lint && npm run pack && npm test"
},
"repository": {
@@ -30,26 +32,27 @@
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/github": "^4.0.0",
"@octokit/rest": "^18.1.1",
"@octokit/rest": "^18.3.3",
"lodash.deburr": "^4.1.0",
"semver": "^7.3.4"
},
"devDependencies": {
"@types/jest": "^26.0.20",
"@types/lodash.deburr": "^4.1.6",
"@types/node": "^14.14.28",
"@types/node": "^14.14.31",
"@types/semver": "^7.3.4",
"@typescript-eslint/eslint-plugin": "^4.15.1",
"@typescript-eslint/parser": "^4.15.1",
"@typescript-eslint/eslint-plugin": "^4.16.1",
"@typescript-eslint/parser": "^4.16.1",
"@vercel/ncc": "^0.27.0",
"eslint": "^7.20.0",
"eslint-plugin-github": "^4.0.1",
"eslint": "^7.21.0",
"eslint-plugin-github": "^4.1.2",
"eslint-plugin-jest": "^24.1.5",
"jest": "^26.6.3",
"jest-circus": "^26.6.3",
"jest-silent-reporter": "^0.4.0",
"js-yaml": "^4.0.0",
"prettier": "^2.2.1",
"ts-jest": "^26.5.1",
"typescript": "^4.1.5"
"ts-jest": "^26.5.3",
"typescript": "^4.2.3"
}
}

View File

@@ -0,0 +1,594 @@
import {DefaultProcessorOptions} from '../../__tests__/constants/default-processor-options';
import {generateIIssue} from '../../__tests__/functions/generate-iissue';
import {IIssue} from '../interfaces/issue';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {Assignees} from './assignees';
describe('Assignees', (): void => {
let assignees: Assignees;
let optionsInterface: IIssuesProcessorOptions;
let issue: Issue;
let issueInterface: IIssue;
beforeEach((): void => {
optionsInterface = {...DefaultProcessorOptions};
issueInterface = generateIIssue();
});
describe('shouldExemptAssignees()', (): void => {
describe('when the given issue is not a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = undefined;
});
describe('when the given options are not configured to exempt an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptAssignees = '';
});
describe('when the given options are not configured to exempt an issue with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptIssueAssignees = '';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
});
describe('when the given options are configured to exempt an issue with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptIssueAssignees =
'dummy-exempt-issue-assignee';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee different than the exempt issue assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt issue assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-issue-assignee'
}
];
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(true);
});
});
});
});
describe('when the given options are configured to exempt an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptAssignees = 'dummy-exempt-assignee';
});
describe('when the given options are not configured to exempt an issue with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptIssueAssignees = '';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee different than the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-assignee'
}
];
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(true);
});
});
});
describe('when the given options are configured to exempt an issue with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptIssueAssignees =
'dummy-exempt-issue-assignee';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee different than the exempt issue assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt issue assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-issue-assignee'
}
];
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(true);
});
});
describe('when the given issue does have an assignee different than the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-assignee'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
});
});
});
describe('when the given issue is a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = {};
});
describe('when the given options are not configured to exempt an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptAssignees = '';
});
describe('when the given options are not configured to exempt a pull request with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptPrAssignees = '';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
});
describe('when the given options are configured to exempt a pull request with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptPrAssignees = 'dummy-exempt-pr-assignee';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee different than the exempt pull request assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt pull request assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-pr-assignee'
}
];
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(true);
});
});
});
});
describe('when the given options are configured to exempt an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptAssignees = 'dummy-exempt-assignee';
});
describe('when the given options are not configured to exempt a pull request with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptPrAssignees = '';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee different than the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-assignee'
}
];
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(true);
});
});
});
describe('when the given options are configured to exempt a pull request with an assignee', (): void => {
beforeEach((): void => {
optionsInterface.exemptPrAssignees = 'dummy-exempt-pr-assignee';
});
describe('when the given issue does not have an assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee different than the exempt pull request assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt pull request assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-pr-assignee'
}
];
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(true);
});
});
describe('when the given issue does have an assignee different than the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
describe('when the given issue does have an assignee equaling the exempt assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-exempt-assignee'
}
];
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
assignees = new Assignees(optionsInterface, issue);
const result = assignees.shouldExemptAssignees();
expect(result).toStrictEqual(false);
});
});
});
});
});
});
});

251
src/classes/assignees.ts Normal file
View File

@@ -0,0 +1,251 @@
import deburr from 'lodash.deburr';
import {wordsToList} from '../functions/words-to-list';
import {IAssignee} from '../interfaces/assignee';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
type CleanAssignee = string;
export class Assignees {
private static _cleanAssignee(assignee: Readonly<string>): CleanAssignee {
return deburr(assignee.toLowerCase());
}
private readonly _options: IIssuesProcessorOptions;
private readonly _issue: Issue;
private readonly _issueLogger: IssueLogger;
constructor(options: Readonly<IIssuesProcessorOptions>, issue: Issue) {
this._options = options;
this._issue = issue;
this._issueLogger = new IssueLogger(issue);
}
shouldExemptAssignees(): boolean {
if (!this._issue.hasAssignees) {
this._issueLogger.info('This $$type has no assignee');
this._logSkip();
return false;
}
if (this._shouldExemptAllAssignees()) {
this._issueLogger.info(
'Skipping $$type because it has an exempt assignee'
);
return true;
}
const exemptAssignees: string[] = this._getExemptAssignees();
if (exemptAssignees.length === 0) {
this._issueLogger.info(
`No option was specified to skip the stale process for this $$type`
);
this._logSkip();
return false;
}
this._issueLogger.info(
`Found ${exemptAssignees.length} assignee${
exemptAssignees.length > 1 ? 's' : ''
} on this $$type`
);
const hasExemptAssignee: boolean = exemptAssignees.some(
(exemptAssignee: Readonly<string>): boolean =>
this._hasAssignee(exemptAssignee)
);
if (!hasExemptAssignee) {
this._issueLogger.info(
'No assignee on this $$type can exempt the stale process'
);
this._logSkip();
} else {
this._issueLogger.info(
'Skipping this $$type because it has an exempt assignee'
);
}
return hasExemptAssignee;
}
private _getExemptAssignees(): string[] {
return this._issue.isPullRequest
? this._getExemptPullRequestAssignees()
: this._getExemptIssueAssignees();
}
private _getExemptIssueAssignees(): string[] {
if (this._options.exemptIssueAssignees === '') {
this._issueLogger.info(
'The option "exemptIssueAssignees" is disabled. No specific assignee can skip the stale process for this $$type'
);
if (this._options.exemptAssignees === '') {
this._issueLogger.info(
'The option "exemptAssignees" is disabled. No specific assignee can skip the stale process for this $$type'
);
return [];
}
const exemptAssignees: string[] = wordsToList(
this._options.exemptAssignees
);
this._issueLogger.info(
`The option "exemptAssignees" is set. ${
exemptAssignees.length
} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptAssignees;
}
const exemptAssignees: string[] = wordsToList(
this._options.exemptIssueAssignees
);
this._issueLogger.info(
`The option "exemptIssueAssignees" is set. ${
exemptAssignees.length
} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptAssignees;
}
private _getExemptPullRequestAssignees(): string[] {
if (this._options.exemptPrAssignees === '') {
this._issueLogger.info(
'The option "exemptPrAssignees" is disabled. No specific assignee can skip the stale process for this $$type'
);
if (this._options.exemptAssignees === '') {
this._issueLogger.info(
'The option "exemptAssignees" is disabled. No specific assignee can skip the stale process for this $$type'
);
return [];
}
const exemptAssignees: string[] = wordsToList(
this._options.exemptAssignees
);
this._issueLogger.info(
`The option "exemptAssignees" is set. ${
exemptAssignees.length
} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptAssignees;
}
const exemptAssignees: string[] = wordsToList(
this._options.exemptPrAssignees
);
this._issueLogger.info(
`The option "exemptPrAssignees" is set. ${
exemptAssignees.length
} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptAssignees;
}
private _hasAssignee(assignee: Readonly<string>): boolean {
const cleanAssignee: CleanAssignee = Assignees._cleanAssignee(assignee);
return this._issue.assignees.some(
(issueAssignee: Readonly<IAssignee>): boolean => {
const isSameAssignee: boolean =
cleanAssignee === Assignees._cleanAssignee(issueAssignee.login);
if (isSameAssignee) {
this._issueLogger.info(
`@${issueAssignee.login} is assigned on this $$type and is an exempt assignee`
);
}
return isSameAssignee;
}
);
}
private _shouldExemptAllAssignees(): boolean {
return this._issue.isPullRequest
? this._shouldExemptAllPullRequestAssignees()
: this._shouldExemptAllIssueAssignees();
}
private _shouldExemptAllIssueAssignees(): boolean {
if (this._options.exemptAllIssueAssignees === true) {
this._issueLogger.info(
'The option "exemptAllIssueAssignees" is enabled. Any assignee on this $$type will skip the stale process'
);
return true;
} else if (this._options.exemptAllIssueAssignees === false) {
this._issueLogger.info(
'The option "exemptAllIssueAssignees" is disabled. Only some specific assignees on this $$type will skip the stale process'
);
return false;
}
this._logExemptAllAssigneesOption();
return this._options.exemptAllAssignees;
}
private _shouldExemptAllPullRequestAssignees(): boolean {
if (this._options.exemptAllPrAssignees === true) {
this._issueLogger.info(
'The option "exemptAllPrAssignees" is enabled. Any assignee on this $$type will skip the stale process'
);
return true;
} else if (this._options.exemptAllPrAssignees === false) {
this._issueLogger.info(
'The option "exemptAllPrAssignees" is disabled. Only some specific assignees on this $$type will skip the stale process'
);
return false;
}
this._logExemptAllAssigneesOption();
return this._options.exemptAllAssignees;
}
private _logExemptAllAssigneesOption(): void {
if (this._options.exemptAllAssignees) {
this._issueLogger.info(
'The option "exemptAllAssignees" is enabled. Any assignee on this $$type will skip the stale process'
);
} else {
this._issueLogger.info(
'The option "exemptAllAssignees" is disabled. Only some specific assignees on this $$type will skip the stale process'
);
}
}
private _logSkip(): void {
this._issueLogger.info('Skip the assignees checks');
}
}

View File

@@ -1,3 +1,4 @@
import {IAssignee} from '../interfaces/assignee';
import {IIssue} from '../interfaces/issue';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {ILabel} from '../interfaces/label';
@@ -25,11 +26,11 @@ describe('Issue', (): void => {
debugOnly: false,
deleteBranch: false,
exemptIssueLabels: '',
exemptIssueMilestones: '',
exemptMilestones: '',
exemptPrLabels: '',
exemptPrMilestones: '',
onlyLabels: '',
onlyIssueLabels: '',
onlyPrLabels: '',
anyOfLabels: '',
operationsPerRun: 0,
removeStaleWhenUpdated: false,
repoToken: '',
@@ -40,9 +41,19 @@ describe('Issue', (): void => {
startDate: undefined,
stalePrLabel: 'dummy-stale-pr-label',
staleIssueLabel: 'dummy-stale-issue-label',
exemptMilestones: '',
exemptIssueMilestones: '',
exemptPrMilestones: '',
exemptAllMilestones: false,
exemptAllIssueMilestones: undefined,
exemptAllPrMilestones: undefined
exemptAllPrMilestones: undefined,
exemptAssignees: '',
exemptIssueAssignees: '',
exemptPrAssignees: '',
exemptAllAssignees: false,
exemptAllIssueAssignees: undefined,
exemptAllPrAssignees: undefined,
enableStatistics: false
};
issueInterface = {
title: 'dummy-title',
@@ -59,7 +70,12 @@ describe('Issue', (): void => {
locked: false,
milestone: {
title: 'dummy-milestone'
}
},
assignees: [
{
login: 'dummy-login'
}
]
};
issue = new Issue(optionsInterface, issueInterface);
});
@@ -125,56 +141,14 @@ describe('Issue', (): void => {
} as IMilestone);
});
describe('when the given issue pull_request is not set', (): void => {
beforeEach((): void => {
issueInterface.pull_request = undefined;
issue = new Issue(optionsInterface, issueInterface);
});
it('should set the assignees with the given issue assignees', (): void => {
expect.assertions(1);
it('should set the isPullRequest to false', (): void => {
expect.assertions(1);
expect(issue.isPullRequest).toStrictEqual(false);
});
});
describe('when the given issue pull_request is set', (): void => {
beforeEach((): void => {
issueInterface.pull_request = {};
issue = new Issue(optionsInterface, issueInterface);
});
it('should set the isPullRequest to true', (): void => {
expect.assertions(1);
expect(issue.isPullRequest).toStrictEqual(true);
});
});
describe('when the given issue is not a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = undefined;
issue = new Issue(optionsInterface, issueInterface);
});
it('should set the staleLabel with the given option staleIssueLabel', (): void => {
expect.assertions(1);
expect(issue.staleLabel).toStrictEqual('dummy-stale-issue-label');
});
});
describe('when the given issue is a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = {};
issue = new Issue(optionsInterface, issueInterface);
});
it('should set the staleLabel with the given option stalePrLabel', (): void => {
expect.assertions(1);
expect(issue.staleLabel).toStrictEqual('dummy-stale-pr-label');
});
expect(issue.assignees).toStrictEqual([
{
login: 'dummy-login'
} as IAssignee
]);
});
describe('when the given issue does not contains the stale label', (): void => {
@@ -209,4 +183,104 @@ describe('Issue', (): void => {
});
});
});
describe('get isPullRequest', (): void => {
describe('when the issue pull_request is not set', (): void => {
beforeEach((): void => {
issueInterface.pull_request = undefined;
issue = new Issue(optionsInterface, issueInterface);
});
it('should return false', (): void => {
expect.assertions(1);
const result = issue.isPullRequest;
expect(result).toStrictEqual(false);
});
});
describe('when the issue pull_request is set', (): void => {
beforeEach((): void => {
issueInterface.pull_request = {};
issue = new Issue(optionsInterface, issueInterface);
});
it('should return true', (): void => {
expect.assertions(1);
const result = issue.isPullRequest;
expect(result).toStrictEqual(true);
});
});
});
describe('get staleLabel', (): void => {
describe('when the issue is not a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = undefined;
issue = new Issue(optionsInterface, issueInterface);
});
it('should return the issue stale label', (): void => {
expect.assertions(1);
const result = issue.staleLabel;
expect(result).toStrictEqual('dummy-stale-issue-label');
});
});
describe('when the given issue is a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = {};
issue = new Issue(optionsInterface, issueInterface);
});
it('should return the pull request stale label', (): void => {
expect.assertions(1);
const result = issue.staleLabel;
expect(result).toStrictEqual('dummy-stale-pr-label');
});
});
});
describe('get hasAssignees', (): void => {
describe('when the issue has no assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [];
issue = new Issue(optionsInterface, issueInterface);
});
it('should return false', (): void => {
expect.assertions(1);
const result = issue.hasAssignees;
expect(result).toStrictEqual(false);
});
});
describe('when the issue has at least one assignee', (): void => {
beforeEach((): void => {
issueInterface.assignees = [
{
login: 'dummy-login'
}
];
issue = new Issue(optionsInterface, issueInterface);
});
it('should return true', (): void => {
expect.assertions(1);
const result = issue.hasAssignees;
expect(result).toStrictEqual(true);
});
});
});
});

View File

@@ -1,5 +1,6 @@
import {isLabeled} from '../functions/is-labeled';
import {isPullRequest} from '../functions/is-pull-request';
import {IAssignee} from '../interfaces/assignee';
import {IIssue} from '../interfaces/issue';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {ILabel} from '../interfaces/label';
@@ -14,11 +15,10 @@ export class Issue implements IIssue {
updated_at: IsoDateString;
readonly labels: ILabel[];
readonly pull_request: Object | null | undefined;
readonly state: string;
readonly state: string | 'closed' | 'open';
readonly locked: boolean;
readonly milestone: IMilestone | undefined;
readonly isPullRequest: boolean;
readonly staleLabel: string;
readonly assignees: IAssignee[];
isStale: boolean;
constructor(
@@ -35,12 +35,23 @@ export class Issue implements IIssue {
this.state = issue.state;
this.locked = issue.locked;
this.milestone = issue.milestone;
this.assignees = issue.assignees;
this.isPullRequest = isPullRequest(this);
this.staleLabel = this._getStaleLabel();
this.isStale = isLabeled(this, this.staleLabel);
}
get isPullRequest(): boolean {
return isPullRequest(this);
}
get staleLabel(): string {
return this._getStaleLabel();
}
get hasAssignees(): boolean {
return this.assignees.length > 0;
}
private _getStaleLabel(): string {
return this.isPullRequest
? this._options.stalePrLabel

View File

@@ -1,11 +1,10 @@
import {context, getOctokit} from '@actions/github';
import {GitHub} from '@actions/github/lib/utils';
import {GetResponseTypeFromEndpointMethod} from '@octokit/types';
import {IssueType} from '../enums/issue-type';
import { coerce } from 'semver';
import {getHumanizedDate} from '../functions/dates/get-humanized-date';
import {isDateMoreRecentThan} from '../functions/dates/is-date-more-recent-than';
import {isValidDate} from '../functions/dates/is-valid-date';
import {getIssueType} from '../functions/get-issue-type';
import {isLabeled} from '../functions/is-labeled';
import {isPullRequest} from '../functions/is-pull-request';
import {shouldMarkWhenStale} from '../functions/should-mark-when-stale';
@@ -15,10 +14,12 @@ import {IIssue} from '../interfaces/issue';
import {IIssueEvent} from '../interfaces/issue-event';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {IPullRequest} from '../interfaces/pull-request';
import {Assignees} from './assignees';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {Logger} from './loggers/logger';
import {Milestones} from './milestones';
import {Statistics} from './statistics';
/***
* Handle processing of issues for staleness/closure.
@@ -33,6 +34,7 @@ export class IssuesProcessor {
}
private readonly _logger: Logger = new Logger();
private readonly _statistics: Statistics | undefined;
private _operationsLeft = 0;
readonly client: InstanceType<typeof GitHub>;
readonly options: IIssuesProcessorOptions;
@@ -41,65 +43,40 @@ export class IssuesProcessor {
readonly deletedBranchIssues: Issue[] = [];
readonly removedLabelIssues: Issue[] = [];
constructor(
options: IIssuesProcessorOptions,
getActor?: () => Promise<string>,
getIssues?: (page: number) => Promise<Issue[]>,
listIssueComments?: (
issueNumber: number,
sinceDate: string
) => Promise<IComment[]>,
getLabelCreationDate?: (
issue: Issue,
label: string
) => Promise<string | undefined>
) {
constructor(options: IIssuesProcessorOptions) {
this.options = options;
this._operationsLeft = options.operationsPerRun;
this.client = getOctokit(options.repoToken);
if (getActor) {
this._getActor = getActor;
}
if (getIssues) {
this._getIssues = getIssues;
}
if (listIssueComments) {
this._listIssueComments = listIssueComments;
}
if (getLabelCreationDate) {
this._getLabelCreationDate = getLabelCreationDate;
}
this._operationsLeft = this.options.operationsPerRun;
this.client = getOctokit(this.options.repoToken);
if (this.options.debugOnly) {
this._logger.warning(
'Executing in debug mode. Debug output will be written but no issues will be processed.'
);
}
if (this.options.enableStatistics) {
this._statistics = new Statistics(this.options);
}
}
async processIssues(page = 1): Promise<number> {
// get the next batch of issues
const issues: Issue[] = await this._getIssues(page);
this._operationsLeft -= 1;
const actor: string = await this._getActor();
const issues: Issue[] = await this.getIssues(page);
const actor: string = await this.getActor();
if (issues.length <= 0) {
this._logger.info('---');
this._statistics?.setOperationsLeft(this._operationsLeft).logStats();
this._logger.info('No more issues found to process. Exiting.');
return this._operationsLeft;
}
for (const issue of issues.values()) {
const issueLogger: IssueLogger = new IssueLogger(issue);
this._statistics?.incrementProcessedIssuesCount();
issueLogger.info(
`Found issue: issue #${issue.number} last updated ${issue.updated_at} (is pr? ${issue.isPullRequest})`
);
issueLogger.info(`Found this $$type last updated ${issue.updated_at}`);
// calculate string based messages for this issue
const staleMessage: string = issue.isPullRequest
@@ -117,34 +94,60 @@ export class IssuesProcessor {
const skipMessage = issue.isPullRequest
? this.options.skipStalePrMessage
: this.options.skipStaleIssueMessage;
const issueType: IssueType = getIssueType(issue.isPullRequest);
const daysBeforeStale: number = issue.isPullRequest
? this._getDaysBeforePrStale()
: this._getDaysBeforeIssueStale();
const onlyLabels: string[] = wordsToList(this._getOnlyLabels(issue));
if (issue.isPullRequest) {
issueLogger.info(`Days before pull request stale: ${daysBeforeStale}`);
if (onlyLabels.length > 0) {
issueLogger.info(
`The option "onlyLabels" was specified to only processed the issues and pull requests with all those labels (${onlyLabels.length})`
);
const hasAllWhitelistedLabels: boolean = onlyLabels.every(
(label: Readonly<string>): boolean => {
return isLabeled(issue, label);
}
);
if (!hasAllWhitelistedLabels) {
issueLogger.info(
`Skipping this $$type because it doesn't have all the required labels`
);
continue; // Don't process issues without all of the required labels
} else {
issueLogger.info(
`All the required labels are present on this $$type. Continuing the process`
);
}
} else {
issueLogger.info(`Days before issue stale: ${daysBeforeStale}`);
issueLogger.info(
`The option "onlyLabels" was not specified. Continuing the process for this $$type`
);
}
issueLogger.info(`Days before $$type stale: ${daysBeforeStale}`);
const shouldMarkAsStale: boolean = shouldMarkWhenStale(daysBeforeStale);
if (!staleMessage && shouldMarkAsStale) {
issueLogger.info(`Skipping ${issueType} due to empty stale message`);
issueLogger.info(`Skipping $$type due to empty stale message`);
continue;
}
if (issue.state === 'closed') {
issueLogger.info(`Skipping ${issueType} because it is closed`);
issueLogger.info(`Skipping $$type because it is closed`);
continue; // don't process closed issues
}
if (issue.locked) {
issueLogger.info(`Skipping ${issueType} because it is locked`);
issueLogger.info(`Skipping $$type because it is locked`);
continue; // don't process locked issues
}
// Try to remove the close label when not close/locked issue or PR
await this._removeCloseLabel(issue, closeLabel);
if (this.options.startDate) {
const startDate: Date = new Date(this.options.startDate);
const createdAt: Date = new Date(issue.created_at);
@@ -164,14 +167,14 @@ export class IssuesProcessor {
}
issueLogger.info(
`Issue created the ${getHumanizedDate(createdAt)} (${
`$$type created the ${getHumanizedDate(createdAt)} (${
issue.created_at
})`
);
if (!isDateMoreRecentThan(createdAt, startDate)) {
issueLogger.info(
`Skipping ${issueType} because it was created before the specified start date`
`Skipping $$type because it was created before the specified start date`
);
continue; // don't process issues which were created before the start date
@@ -179,9 +182,9 @@ export class IssuesProcessor {
}
if (issue.isStale) {
issueLogger.info(`This issue has a stale label`);
issueLogger.info(`This $$type has a stale label`);
} else {
issueLogger.info(`This issue hasn't a stale label`);
issueLogger.info(`This $$type hasn't a stale label`);
}
const exemptLabels: string[] = wordsToList(
@@ -200,21 +203,38 @@ export class IssuesProcessor {
await this._removeStaleLabel(issue, staleLabel);
}
issueLogger.info(
`Skipping ${issueType} because it has an exempt label`
);
issueLogger.info(`Skipping $$type because it has an exempt label`);
continue; // don't process exempt issues
}
const anyOfLabels: string[] = wordsToList(this.options.anyOfLabels);
if (
anyOfLabels.length &&
!anyOfLabels.some((label: Readonly<string>): boolean =>
isLabeled(issue, label)
)
) {
issueLogger.info(
`Skipping $$type because it does not have any of the required labels`
);
continue; // don't process issues without any of the required labels
}
const milestones: Milestones = new Milestones(this.options, issue);
if (milestones.shouldExemptMilestones()) {
issueLogger.info(
`Skipping ${issueType} because it has an exempt milestone`
`Skipping $$type because it has an exempted milestone`
);
continue; // don't process exempt milestones
}
const assignees: Assignees = new Assignees(this.options, issue);
if (assignees.shouldExemptAssignees()) {
continue; // don't process exempt assignees
}
// should this issue be marked stale?
const shouldBeStale = !IssuesProcessor._updatedSince(
issue.updated_at,
@@ -224,7 +244,7 @@ export class IssuesProcessor {
// determine if this issue needs to be marked stale first
if (!issue.isStale && shouldBeStale && shouldMarkAsStale) {
issueLogger.info(
`Marking ${issueType} stale because it was last updated on ${issue.updated_at} and it does not have a stale label`
`Marking $$type stale because it was last updated on ${issue.updated_at} and it does not have a stale label`
);
await this._markStale(issue, staleMessage, staleLabel, skipMessage);
issue.isStale = true; // this issue is now considered stale
@@ -236,10 +256,9 @@ export class IssuesProcessor {
// process the issue if it was marked stale
if (issue.isStale) {
issueLogger.info(`Found a stale ${issueType}`);
issueLogger.info(`Found a stale $$type`);
await this._processStaleIssue(
issue,
issueType,
staleLabel,
actor,
closeMessage,
@@ -259,118 +278,15 @@ export class IssuesProcessor {
return this.processIssues(page + 1);
}
// handle all of the stale issue logic when we find a stale issue
private async _processStaleIssue(
issue: Issue,
issueType: IssueType,
staleLabel: string,
actor: string,
closeMessage?: string,
closeLabel?: string
) {
const issueLogger: IssueLogger = new IssueLogger(issue);
const markedStaleOn: string =
(await this._getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
issueLogger.info(
`Issue #${issue.number} marked stale on: ${markedStaleOn}`
);
const issueHasComments: boolean = await this._hasCommentsSince(
issue,
markedStaleOn,
actor
);
issueLogger.info(
`Issue #${issue.number} has been commented on: ${issueHasComments}`
);
const isPr: boolean = isPullRequest(issue);
const daysBeforeClose: number = isPr
? this._getDaysBeforePrClose()
: this._getDaysBeforeIssueClose();
if (isPr) {
issueLogger.info(`Days before pull request close: ${daysBeforeClose}`);
} else {
issueLogger.info(`Days before issue close: ${daysBeforeClose}`);
}
const issueHasUpdate: boolean = IssuesProcessor._updatedSince(
issue.updated_at,
daysBeforeClose
);
issueLogger.info(
`Issue #${issue.number} has been updated: ${issueHasUpdate}`
);
// should we un-stale this issue?
if (this.options.removeStaleWhenUpdated && issueHasComments) {
await this._removeStaleLabel(issue, staleLabel);
}
// now start closing logic
if (daysBeforeClose < 0) {
return; // nothing to do because we aren't closing stale issues
}
if (!issueHasComments && !issueHasUpdate) {
issueLogger.info(
`Closing ${issueType} because it was last updated on ${issue.updated_at}`
);
await this._closeIssue(issue, closeMessage, closeLabel);
if (this.options.deleteBranch && issue.pull_request) {
issueLogger.info(
`Deleting branch for #${issue.number} as delete-branch option was specified`
);
await this._deleteBranch(issue);
this.deletedBranchIssues.push(issue);
}
} else {
issueLogger.info(
`Stale ${issueType} is not old enough to close yet (hasComments? ${issueHasComments}, hasUpdate? ${issueHasUpdate})`
);
}
}
// checks to see if a given issue is still stale (has had activity on it)
private async _hasCommentsSince(
issue: Issue,
sinceDate: string,
actor: string
): Promise<boolean> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(
`Checking for comments on issue #${issue.number} since ${sinceDate}`
);
if (!sinceDate) {
return true;
}
// find any comments since the date
const comments = await this._listIssueComments(issue.number, sinceDate);
const filteredComments = comments.filter(
comment => comment.user.type === 'User' && comment.user.login !== actor
);
issueLogger.info(
`Comments not made by actor or another bot: ${filteredComments.length}`
);
// if there are any user comments returned
return filteredComments.length > 0;
}
// grab comments for an issue since a given date
private async _listIssueComments(
async listIssueComments(
issueNumber: number,
sinceDate: string
): Promise<IComment[]> {
// find any comments since date on the given issue
try {
this._operationsLeft -= 1;
this._statistics?.incrementFetchedIssuesCommentsCount();
const comments = await this.client.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -385,11 +301,15 @@ export class IssuesProcessor {
}
// get the actor from the GitHub token or context
private async _getActor(): Promise<string> {
async getActor(): Promise<string> {
let actor;
try {
this._operationsLeft -= 1;
actor = await this.client.users.getAuthenticated();
this._logger.info('Actor is from client')
} catch (error) {
this._logger.info('Actor is from context')
return context.actor;
}
@@ -397,18 +317,19 @@ export class IssuesProcessor {
}
// grab issues from github in batches of 100
private async _getIssues(page: number): Promise<Issue[]> {
async getIssues(page: number): Promise<Issue[]> {
// generate type for response
const endpoint = this.client.issues.listForRepo;
type OctoKitIssueList = GetResponseTypeFromEndpointMethod<typeof endpoint>;
try {
this._operationsLeft -= 1;
this._statistics?.incrementFetchedIssuesCount();
const issueResult: OctoKitIssueList = await this.client.issues.listForRepo(
{
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: this.options.onlyLabels,
per_page: 100,
direction: this.options.ascending ? 'asc' : 'desc',
page
@@ -424,212 +345,18 @@ export class IssuesProcessor {
}
}
// Mark an issue as stale with a comment and a label
private async _markStale(
issue: Issue,
staleMessage: string,
staleLabel: string,
skipMessage: boolean
): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Marking issue #${issue.number} as stale`);
this.staleIssues.push(issue);
this._operationsLeft -= 2;
// if the issue is being marked stale, the updated date should be changed to right now
// so that close calculations work correctly
const newUpdatedAtDate: Date = new Date();
issue.updated_at = newUpdatedAtDate.toString();
if (this.options.debugOnly) {
return;
}
if (!skipMessage) {
try {
await this.client.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: staleMessage
});
} catch (error) {
issueLogger.error(`Error creating a comment: ${error.message}`);
}
}
try {
await this.client.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [staleLabel]
});
} catch (error) {
issueLogger.error(`Error adding a label: ${error.message}`);
}
}
// Close an issue based on staleness
private async _closeIssue(
issue: Issue,
closeMessage?: string,
closeLabel?: string
): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Closing issue #${issue.number} for being stale`);
this.closedIssues.push(issue);
this._operationsLeft -= 1;
if (this.options.debugOnly) {
return;
}
if (closeMessage) {
try {
await this.client.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: closeMessage
});
} catch (error) {
issueLogger.error(`Error creating a comment: ${error.message}`);
}
}
if (closeLabel) {
try {
await this.client.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [closeLabel]
});
} catch (error) {
issueLogger.error(`Error adding a label: ${error.message}`);
}
}
try {
await this.client.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed'
});
} catch (error) {
issueLogger.error(`Error updating an issue: ${error.message}`);
}
}
private async _getPullRequest(
issue: Issue
): Promise<IPullRequest | undefined> {
const issueLogger: IssueLogger = new IssueLogger(issue);
this._operationsLeft -= 1;
try {
const pullRequest = await this.client.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: issue.number
});
return pullRequest.data;
} catch (error) {
issueLogger.error(
`Error getting pull request ${issue.number}: ${error.message}`
);
}
}
// Delete the branch on closed pull request
private async _deleteBranch(issue: Issue): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(
`Delete branch from closed issue #${issue.number} - ${issue.title}`
);
if (this.options.debugOnly) {
return;
}
const pullRequest = await this._getPullRequest(issue);
if (!pullRequest) {
issueLogger.info(
`Not deleting branch as pull request not found for issue ${issue.number}`
);
return;
}
const branch = pullRequest.head.ref;
issueLogger.info(
`Deleting branch ${branch} from closed issue #${issue.number}`
);
this._operationsLeft -= 1;
try {
await this.client.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `heads/${branch}`
});
} catch (error) {
issueLogger.error(
`Error deleting branch ${branch} from issue #${issue.number}: ${error.message}`
);
}
}
// Remove a label from an issue
private async _removeLabel(issue: Issue, label: string): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Removing label "${label}" from issue #${issue.number}`);
this.removedLabelIssues.push(issue);
this._operationsLeft -= 1;
// @todo remove the debug only to be able to test the code below
if (this.options.debugOnly) {
return;
}
try {
await this.client.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
name: label
});
} catch (error) {
issueLogger.error(`Error removing a label: ${error.message}`);
}
}
// returns the creation date of a given label on an issue (or nothing if no label existed)
///see https://developer.github.com/v3/activity/events/
private async _getLabelCreationDate(
async getLabelCreationDate(
issue: Issue,
label: string
): Promise<string | undefined> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Checking for label on issue #${issue.number}`);
issueLogger.info(`Checking for label on $$type`);
this._operationsLeft -= 1;
this._statistics?.incrementFetchedIssuesEventsCount();
const options = this.client.issues.listEvents.endpoint.merge({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -652,6 +379,296 @@ export class IssuesProcessor {
return staleLabeledEvent.created_at;
}
// handle all of the stale issue logic when we find a stale issue
private async _processStaleIssue(
issue: Issue,
staleLabel: string,
actor: string,
closeMessage?: string,
closeLabel?: string
) {
const issueLogger: IssueLogger = new IssueLogger(issue);
const markedStaleOn: string =
(await this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
issueLogger.info(`$$type marked stale on: ${markedStaleOn}`);
const issueHasComments: boolean = await this._hasCommentsSince(
issue,
markedStaleOn,
actor
);
issueLogger.info(`$$type has been commented on: ${issueHasComments}`);
const isPr: boolean = isPullRequest(issue);
const daysBeforeClose: number = isPr
? this._getDaysBeforePrClose()
: this._getDaysBeforeIssueClose();
issueLogger.info(`Days before $$type close: ${daysBeforeClose}`);
const issueHasUpdate: boolean = IssuesProcessor._updatedSince(
issue.updated_at,
daysBeforeClose
);
issueLogger.info(`$$type has been updated: ${issueHasUpdate}`);
// should we un-stale this issue?
if (this.options.removeStaleWhenUpdated && issueHasComments) {
await this._removeStaleLabel(issue, staleLabel);
}
// now start closing logic
if (daysBeforeClose < 0) {
return; // nothing to do because we aren't closing stale issues
}
if (!issueHasComments && !issueHasUpdate) {
issueLogger.info(
`Closing $$type because it was last updated on ${issue.updated_at}`
);
await this._closeIssue(issue, closeMessage, closeLabel);
if (this.options.deleteBranch && issue.pull_request) {
issueLogger.info(
`Deleting branch for as delete-branch option was specified`
);
await this._deleteBranch(issue);
this.deletedBranchIssues.push(issue);
}
} else {
issueLogger.info(
`Stale $$type is not old enough to close yet (hasComments? ${issueHasComments}, hasUpdate? ${issueHasUpdate})`
);
}
}
// checks to see if a given issue is still stale (has had activity on it)
private async _hasCommentsSince(
issue: Issue,
sinceDate: string,
actor: string
): Promise<boolean> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Checking for comments on $$type since ${sinceDate}`);
if (!sinceDate) {
return true;
}
// find any comments since the date
const comments = await this.listIssueComments(issue.number, sinceDate);
issueLogger.info('Not filtering for debug purposes')
const filteredComments = comments.filter(
comment => comment.user.type === 'User' && comment.user.login !== actor
);
issueLogger.info(
`Comments not made by actor or another bot: ${filteredComments.length}`
);
// if there are any user comments returned
return filteredComments.length > 0;
}
// Mark an issue as stale with a comment and a label
private async _markStale(
issue: Issue,
staleMessage: string,
staleLabel: string,
skipMessage: boolean
): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Marking $$type as stale`);
this.staleIssues.push(issue);
// if the issue is being marked stale, the updated date should be changed to right now
// so that close calculations work correctly
const newUpdatedAtDate: Date = new Date();
issue.updated_at = newUpdatedAtDate.toString();
if (this.options.debugOnly) {
return;
}
if (!skipMessage) {
try {
this._operationsLeft -= 1;
this._statistics?.incrementAddedComment();
await this.client.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: staleMessage
});
} catch (error) {
issueLogger.error(`Error creating a comment: ${error.message}`);
}
}
try {
this._operationsLeft -= 1;
this._statistics?.incrementAddedLabel();
this._statistics?.incrementStaleIssuesCount();
await this.client.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [staleLabel]
});
} catch (error) {
issueLogger.error(`Error adding a label: ${error.message}`);
}
}
// Close an issue based on staleness
private async _closeIssue(
issue: Issue,
closeMessage?: string,
closeLabel?: string
): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Closing $$type for being stale`);
this.closedIssues.push(issue);
if (this.options.debugOnly) {
return;
}
if (closeMessage) {
try {
this._operationsLeft -= 1;
this._statistics?.incrementAddedComment();
await this.client.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: closeMessage
});
} catch (error) {
issueLogger.error(`Error creating a comment: ${error.message}`);
}
}
if (closeLabel) {
try {
this._operationsLeft -= 1;
this._statistics?.incrementAddedLabel();
await this.client.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [closeLabel]
});
} catch (error) {
issueLogger.error(`Error adding a label: ${error.message}`);
}
}
try {
this._operationsLeft -= 1;
this._statistics?.incrementClosedIssuesCount();
await this.client.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed'
});
} catch (error) {
issueLogger.error(`Error updating this $$type: ${error.message}`);
}
}
private async _getPullRequest(
issue: Issue
): Promise<IPullRequest | undefined | void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
if (this.options.debugOnly) {
return;
}
try {
this._operationsLeft -= 1;
this._statistics?.incrementFetchedPullRequestsCount();
const pullRequest = await this.client.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: issue.number
});
return pullRequest.data;
} catch (error) {
issueLogger.error(`Error getting this $$type: ${error.message}`);
}
}
// Delete the branch on closed pull request
private async _deleteBranch(issue: Issue): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Delete branch from closed $$type - ${issue.title}`);
const pullRequest = await this._getPullRequest(issue);
if (!pullRequest) {
issueLogger.info(
`Not deleting branch as pull request not found for this $$type`
);
return;
}
if (this.options.debugOnly) {
return;
}
const branch = pullRequest.head.ref;
issueLogger.info(`Deleting branch ${branch} from closed $$type`);
try {
this._operationsLeft -= 1;
this._statistics?.incrementDeletedBranchesCount();
await this.client.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `heads/${branch}`
});
} catch (error) {
issueLogger.error(
`Error deleting branch ${branch} from $$type: ${error.message}`
);
}
}
// Remove a label from an issue
private async _removeLabel(issue: Issue, label: string): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Removing label "${label}" from $$type`);
this.removedLabelIssues.push(issue);
// @todo remove the debug only to be able to test the code below
if (this.options.debugOnly) {
return;
}
try {
this._operationsLeft -= 1;
this._statistics?.incrementDeletedLabelsCount();
await this.client.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
name: label
});
} catch (error) {
issueLogger.error(`Error removing a label: ${error.message}`);
}
}
private _getDaysBeforeIssueStale(): number {
return isNaN(this.options.daysBeforeIssueStale)
? this.options.daysBeforeStale
@@ -676,6 +693,20 @@ export class IssuesProcessor {
: this.options.daysBeforePrClose;
}
private _getOnlyLabels(issue: Issue): string {
if (issue.isPullRequest) {
if (this.options.onlyPrLabels !== '') {
return this.options.onlyPrLabels;
}
} else {
if (this.options.onlyIssueLabels !== '') {
return this.options.onlyIssueLabels;
}
}
return this.options.onlyLabels;
}
private async _removeStaleLabel(
issue: Issue,
staleLabel: Readonly<string>
@@ -683,9 +714,36 @@ export class IssuesProcessor {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(
`Issue #${issue.number} is no longer stale. Removing stale label.`
`The $$type is no longer stale. Removing the stale label...`
);
return this._removeLabel(issue, staleLabel);
await this._removeLabel(issue, staleLabel);
this._statistics?.incrementUndoStaleIssuesCount();
}
private async _removeCloseLabel(
issue: Issue,
closeLabel: Readonly<string | undefined>
): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(
`The $$type is not closed nor locked. Trying to remove the close label...`
);
if (!closeLabel) {
issueLogger.info(`There is no close label on this $$type. Skip`);
return Promise.resolve();
}
if (isLabeled(issue, closeLabel)) {
issueLogger.info(
`The $$type has a close label "${closeLabel}". Removing the close label...`
);
await this._removeLabel(issue, closeLabel);
this._statistics?.incrementDeletedCloseLabelsCount();
}
}
}

View File

@@ -1,3 +1,5 @@
import {DefaultProcessorOptions} from '../../../__tests__/constants/default-processor-options';
import {generateIIssue} from '../../../__tests__/functions/generate-iissue';
import {Issue} from '../issue';
import {IssueLogger} from './issue-logger';
import * as core from '@actions/core';
@@ -5,21 +7,20 @@ import * as core from '@actions/core';
describe('IssueLogger', (): void => {
let issue: Issue;
let issueLogger: IssueLogger;
let message: string;
beforeEach((): void => {
issue = {
number: 8
} as Issue;
issueLogger = new IssueLogger(issue);
});
let coreWarningSpy: jest.SpyInstance;
describe('warning()', (): void => {
let message: string;
let coreWarningSpy: jest.SpyInstance;
beforeEach((): void => {
message = 'dummy-message';
issue = new Issue(
DefaultProcessorOptions,
generateIIssue({
number: 8
})
);
issueLogger = new IssueLogger(issue);
coreWarningSpy = jest.spyOn(core, 'warning').mockImplementation();
});
@@ -35,12 +36,17 @@ describe('IssueLogger', (): void => {
});
describe('info()', (): void => {
let message: string;
let coreInfoSpy: jest.SpyInstance;
beforeEach((): void => {
message = 'dummy-message';
issue = new Issue(
DefaultProcessorOptions,
generateIIssue({
number: 8
})
);
issueLogger = new IssueLogger(issue);
coreInfoSpy = jest.spyOn(core, 'info').mockImplementation();
});
@@ -56,12 +62,17 @@ describe('IssueLogger', (): void => {
});
describe('error()', (): void => {
let message: string;
let coreErrorSpy: jest.SpyInstance;
beforeEach((): void => {
message = 'dummy-message';
issue = new Issue(
DefaultProcessorOptions,
generateIIssue({
number: 8
})
);
issueLogger = new IssueLogger(issue);
coreErrorSpy = jest.spyOn(core, 'error').mockImplementation();
});
@@ -75,4 +86,82 @@ describe('IssueLogger', (): void => {
expect(coreErrorSpy).toHaveBeenCalledWith('[#8] dummy-message');
});
});
it('should prefix the message with the issue number', (): void => {
expect.assertions(2);
message = 'dummy-message';
issue = new Issue(
DefaultProcessorOptions,
generateIIssue({
number: 123
})
);
issueLogger = new IssueLogger(issue);
coreWarningSpy = jest.spyOn(core, 'warning').mockImplementation();
issueLogger.warning(message);
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith('[#123] dummy-message');
});
it.each`
pull_request | replacement
${{key: 'value'}} | ${'pull request'}
${{}} | ${'pull request'}
${null} | ${'issue'}
${undefined} | ${'issue'}
`(
'should replace the special tokens "$$type" with the corresponding type',
({pull_request, replacement}): void => {
expect.assertions(2);
message = 'The $$type will stale! $$type will soon be closed!';
issue = new Issue(
DefaultProcessorOptions,
generateIIssue({
number: 8,
pull_request
})
);
issueLogger = new IssueLogger(issue);
coreWarningSpy = jest.spyOn(core, 'warning').mockImplementation();
issueLogger.warning(message);
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith(
`[#8] The ${replacement} will stale! ${replacement} will soon be closed!`
);
}
);
it.each`
pull_request | replacement
${{key: 'value'}} | ${'Pull request'}
${{}} | ${'Pull request'}
${null} | ${'Issue'}
${undefined} | ${'Issue'}
`(
'should replace the special token "$$type" with the corresponding type with first letter as uppercase',
({pull_request, replacement}): void => {
expect.assertions(2);
message = '$$type will stale';
issue = new Issue(
DefaultProcessorOptions,
generateIIssue({
number: 8,
pull_request
})
);
issueLogger = new IssueLogger(issue);
coreWarningSpy = jest.spyOn(core, 'warning').mockImplementation();
issueLogger.warning(message);
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith(
`[#8] ${replacement} will stale`
);
}
);
});

View File

@@ -2,6 +2,19 @@ import * as core from '@actions/core';
import {Issue} from '../issue';
import {Logger} from './logger';
/**
* @description
* Each log will prefix the message with the issue number
*
* @example
* warning('No stale') => "[#123] No stale"
*
* Each log method can have special tokens:
* - $$type => will replace this by either "pull request" or "issue" depending of the type of issue
*
* @example
* warning('The $$type will stale') => "The pull request will stale"
*/
export class IssueLogger implements Logger {
private readonly _issue: Issue;
@@ -10,15 +23,31 @@ export class IssueLogger implements Logger {
}
warning(message: Readonly<string>): void {
core.warning(this._prefixWithIssueNumber(message));
core.warning(this._format(message));
}
info(message: Readonly<string>): void {
core.info(this._prefixWithIssueNumber(message));
core.info(this._format(message));
}
error(message: Readonly<string>): void {
core.error(this._prefixWithIssueNumber(message));
core.error(this._format(message));
}
private _replaceTokens(message: Readonly<string>): string {
return this._replaceTypeToken(message);
}
private _replaceTypeToken(message: Readonly<string>): string {
return message
.replace(
/^\$\$type/,
this._issue.isPullRequest ? 'Pull request' : 'Issue'
)
.replace(
/\$\$type/g,
this._issue.isPullRequest ? 'pull request' : 'issue'
);
}
private _prefixWithIssueNumber(message: Readonly<string>): string {
@@ -28,4 +57,8 @@ export class IssueLogger implements Logger {
private _getIssueNumber(): number {
return this._issue.number;
}
private _format(message: Readonly<string>): string {
return this._prefixWithIssueNumber(this._replaceTokens(message));
}
}

View File

@@ -1,3 +1,5 @@
import {DefaultProcessorOptions} from '../../__tests__/constants/default-processor-options';
import {generateIIssue} from '../../__tests__/functions/generate-iissue';
import {IIssue} from '../interfaces/issue';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
@@ -10,51 +12,8 @@ describe('Milestones', (): void => {
let issueInterface: IIssue;
beforeEach((): void => {
optionsInterface = {
ascending: false,
closeIssueLabel: '',
closeIssueMessage: '',
closePrLabel: '',
closePrMessage: '',
daysBeforeClose: 0,
daysBeforeIssueClose: 0,
daysBeforeIssueStale: 0,
daysBeforePrClose: 0,
daysBeforePrStale: 0,
daysBeforeStale: 0,
debugOnly: false,
deleteBranch: false,
exemptIssueLabels: '',
exemptPrLabels: '',
onlyLabels: '',
operationsPerRun: 0,
removeStaleWhenUpdated: false,
repoToken: '',
skipStaleIssueMessage: false,
skipStalePrMessage: false,
staleIssueLabel: '',
staleIssueMessage: '',
stalePrLabel: '',
stalePrMessage: '',
startDate: undefined,
exemptIssueMilestones: '',
exemptPrMilestones: '',
exemptMilestones: '',
exemptAllMilestones: false,
exemptAllIssueMilestones: undefined,
exemptAllPrMilestones: undefined
};
issueInterface = {
created_at: '',
locked: false,
milestone: undefined,
number: 0,
pull_request: undefined,
state: '',
title: '',
updated_at: '',
labels: []
};
optionsInterface = {...DefaultProcessorOptions};
issueInterface = generateIIssue();
});
describe('shouldExemptMilestones()', (): void => {

View File

@@ -6,8 +6,8 @@ import {Issue} from './issue';
type CleanMilestone = string;
export class Milestones {
private static _cleanMilestone(label: Readonly<string>): CleanMilestone {
return deburr(label.toLowerCase());
private static _cleanMilestone(milestone: Readonly<string>): CleanMilestone {
return deburr(milestone.toLowerCase());
}
private readonly _options: IIssuesProcessorOptions;

200
src/classes/statistics.ts Normal file
View File

@@ -0,0 +1,200 @@
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Logger} from './loggers/logger';
export class Statistics {
private readonly _logger: Logger = new Logger();
private readonly _options: IIssuesProcessorOptions;
private _processedIssuesCount = 0;
private _staleIssuesCount = 0;
private _undoStaleIssuesCount = 0;
private _operationsCount = 0;
private _closedIssuesCount = 0;
private _deletedLabelsCount = 0;
private _deletedCloseLabelsCount = 0;
private _deletedBranchesCount = 0;
private _addedLabelsCount = 0;
private _addedCommentsCount = 0;
private _fetchedIssuesCount = 0;
private _fetchedIssuesEventsCount = 0;
private _fetchedIssuesCommentsCount = 0;
private _fetchedPullRequestsCount = 0;
constructor(options: IIssuesProcessorOptions) {
this._options = options;
}
incrementProcessedIssuesCount(increment: Readonly<number> = 1): Statistics {
this._processedIssuesCount += increment;
return this;
}
incrementStaleIssuesCount(increment: Readonly<number> = 1): Statistics {
this._staleIssuesCount += increment;
return this;
}
incrementUndoStaleIssuesCount(increment: Readonly<number> = 1): Statistics {
this._undoStaleIssuesCount += increment;
return this;
}
setOperationsLeft(operationsLeft: Readonly<number>): Statistics {
this._operationsCount = this._options.operationsPerRun - operationsLeft;
return this;
}
incrementClosedIssuesCount(increment: Readonly<number> = 1): Statistics {
this._closedIssuesCount += increment;
return this;
}
incrementDeletedLabelsCount(increment: Readonly<number> = 1): Statistics {
this._deletedLabelsCount += increment;
return this;
}
incrementDeletedCloseLabelsCount(
increment: Readonly<number> = 1
): Statistics {
this._deletedCloseLabelsCount += increment;
return this;
}
incrementDeletedBranchesCount(increment: Readonly<number> = 1): Statistics {
this._deletedBranchesCount += increment;
return this;
}
incrementAddedLabel(increment: Readonly<number> = 1): Statistics {
this._addedLabelsCount += increment;
return this;
}
incrementAddedComment(increment: Readonly<number> = 1): Statistics {
this._addedCommentsCount += increment;
return this;
}
incrementFetchedIssuesCount(increment: Readonly<number> = 1): Statistics {
this._fetchedIssuesCount += increment;
return this;
}
incrementFetchedIssuesEventsCount(
increment: Readonly<number> = 1
): Statistics {
this._fetchedIssuesEventsCount += increment;
return this;
}
incrementFetchedIssuesCommentsCount(
increment: Readonly<number> = 1
): Statistics {
this._fetchedIssuesCommentsCount += increment;
return this;
}
incrementFetchedPullRequestsCount(
increment: Readonly<number> = 1
): Statistics {
this._fetchedPullRequestsCount += increment;
return this;
}
logStats(): Statistics {
this._logger.info('Statistics');
this._logProcessedIssuesCount();
this._logStaleIssuesCount();
this._logUndoStaleIssuesCount();
this._logOperationsCount();
this._logClosedIssuesCount();
this._logDeletedLabelsCount();
this._logDeletedCloseLabelsCount();
this._logDeletedBranchesCount();
this._logAddedLabelsCount();
this._logAddedCommentsCount();
this._logFetchedIssuesCount();
this._logFetchedIssuesEventsCount();
this._logFetchedIssuesCommentsCount();
this._logFetchedPullRequestsCount();
this._logger.info('---');
return this;
}
private _logProcessedIssuesCount(): void {
this._logCount('Processed issues/PRs', this._processedIssuesCount);
}
private _logStaleIssuesCount(): void {
this._logCount('New stale issues/PRs', this._staleIssuesCount);
}
private _logUndoStaleIssuesCount(): void {
this._logCount('No longer stale issues/PRs', this._undoStaleIssuesCount);
}
private _logOperationsCount(): void {
this._logCount('Operations performed', this._operationsCount);
}
private _logClosedIssuesCount(): void {
this._logCount('Closed issues', this._closedIssuesCount);
}
private _logDeletedLabelsCount(): void {
this._logCount('Deleted labels', this._deletedLabelsCount);
}
private _logDeletedCloseLabelsCount(): void {
this._logCount('Deleted close labels', this._deletedCloseLabelsCount);
}
private _logDeletedBranchesCount(): void {
this._logCount('Deleted branches', this._deletedBranchesCount);
}
private _logAddedLabelsCount(): void {
this._logCount('Added labels', this._addedLabelsCount);
}
private _logAddedCommentsCount(): void {
this._logCount('Added comments', this._addedCommentsCount);
}
private _logFetchedIssuesCount(): void {
this._logCount('Fetched issues', this._fetchedIssuesCount);
}
private _logFetchedIssuesEventsCount(): void {
this._logCount('Fetched issues events', this._fetchedIssuesEventsCount);
}
private _logFetchedIssuesCommentsCount(): void {
this._logCount('Fetched issues comments', this._fetchedIssuesCommentsCount);
}
private _logFetchedPullRequestsCount(): void {
this._logCount('Fetched pull requests', this._fetchedPullRequestsCount);
}
private _logCount(name: Readonly<string>, count: Readonly<number>): void {
if (count > 0) {
this._logger.info(`${name}: ${count}`);
}
}
}

View File

@@ -1,33 +0,0 @@
import {getIssueType} from './get-issue-type';
describe('getIssueType()', (): void => {
let isPullRequest: boolean;
describe('when the issue is a not pull request', (): void => {
beforeEach((): void => {
isPullRequest = false;
});
it('should return that the issue is really an issue', (): void => {
expect.assertions(1);
const result = getIssueType(isPullRequest);
expect(result).toStrictEqual('issue');
});
});
describe('when the issue is a pull request', (): void => {
beforeEach((): void => {
isPullRequest = true;
});
it('should return that the issue is a pull request', (): void => {
expect.assertions(1);
const result = getIssueType(isPullRequest);
expect(result).toStrictEqual('pr');
});
});
});

View File

@@ -1,5 +0,0 @@
import {IssueType} from '../enums/issue-type';
export function getIssueType(isPullRequest: Readonly<boolean>): IssueType {
return isPullRequest ? IssueType.PullRequest : IssueType.Issue;
}

View File

@@ -0,0 +1,3 @@
export interface IAssignee {
login: string;
}

View File

@@ -1,4 +1,5 @@
import {IsoDateString} from '../types/iso-date-string';
import {IAssignee} from './assignee';
import {ILabel} from './label';
import {IMilestone} from './milestone';
@@ -12,4 +13,5 @@ export interface IIssue {
state: string;
locked: boolean;
milestone: IMilestone | undefined;
assignees: IAssignee[];
}

View File

@@ -19,6 +19,9 @@ export interface IIssuesProcessorOptions {
closePrLabel: string;
exemptPrLabels: string;
onlyLabels: string;
onlyIssueLabels: string;
onlyPrLabels: string;
anyOfLabels: string;
operationsPerRun: number;
removeStaleWhenUpdated: boolean;
debugOnly: boolean;
@@ -33,4 +36,11 @@ export interface IIssuesProcessorOptions {
exemptAllMilestones: boolean;
exemptAllIssueMilestones: boolean | undefined;
exemptAllPrMilestones: boolean | undefined;
exemptAssignees: string;
exemptIssueAssignees: string;
exemptPrAssignees: string;
exemptAllAssignees: boolean;
exemptAllIssueAssignees: boolean | undefined;
exemptAllPrAssignees: boolean | undefined;
enableStatistics: boolean;
}

View File

@@ -1,4 +1,4 @@
export interface IUser {
type: string;
type: string | 'User';
login: string;
}

View File

@@ -39,6 +39,9 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
closePrLabel: core.getInput('close-pr-label'),
exemptPrLabels: core.getInput('exempt-pr-labels'),
onlyLabels: core.getInput('only-labels'),
onlyIssueLabels: core.getInput('only-issue-labels'),
onlyPrLabels: core.getInput('only-pr-labels'),
anyOfLabels: core.getInput('any-of-labels'),
operationsPerRun: parseInt(
core.getInput('operations-per-run', {required: true})
),
@@ -59,7 +62,14 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
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')
exemptAllPrMilestones: _toOptionalBoolean('exempt-all-pr-milestones'),
exemptAssignees: core.getInput('exempt-assignees'),
exemptIssueAssignees: core.getInput('exempt-issue-assignees'),
exemptPrAssignees: core.getInput('exempt-pr-assignees'),
exemptAllAssignees: core.getInput('exempt-all-assignees') === 'true',
exemptAllIssueAssignees: _toOptionalBoolean('exempt-all-issue-assignees'),
exemptAllPrAssignees: _toOptionalBoolean('exempt-all-pr-assignees'),
enableStatistics: core.getInput('enable-statistics') === 'true'
};
for (const numberInput of [
@@ -100,4 +110,4 @@ function _toOptionalBoolean(
return undefined;
}
_run();
void _run();