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