mirror of
https://gitea.com/actions/stale.git
synced 2026-09-16 17:44:24 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3020607302 | |||
| f01e4de246 |
@@ -110,6 +110,7 @@ Every argument is optional.
|
||||
| [ignore-pr-updates](#ignore-pr-updates) | Override [ignore-updates](#ignore-updates) for PRs only | |
|
||||
| [include-only-assigned](#include-only-assigned) | Process only assigned issues | `false` |
|
||||
| [sort-by](#sort-by) | What to sort issues and PRs by | `created` |
|
||||
| [exempt-issue-types](#exempt-issue-types) | Issue types on issues exempted from stale/closed. | |
|
||||
| [only-issue-types](#only-issue-types) | Only issues with a matching type are processed as stale/closed. | |
|
||||
|
||||
### List of output options
|
||||
@@ -567,6 +568,17 @@ Useful to sort the issues and PRs by the specified field. It accepts `created`,
|
||||
|
||||
Default value: `created`
|
||||
|
||||
#### exempt-issue-types
|
||||
|
||||
A comma separated list of issue types that can be assigned to issues to exclude them from being marked as stale
|
||||
(e.g: `Bug,Feature`)
|
||||
|
||||
If unset (or an empty string), this option will not alter the stale workflow.
|
||||
|
||||
If a type is listed in both `exempt-issue-types` and `only-issue-types`, `exempt-issue-types` takes precedence.
|
||||
|
||||
Default value: unset
|
||||
|
||||
#### only-issue-types
|
||||
|
||||
A comma separated list of allowed issue types. Only issues with a matching type will be processed (e.g.: `bug,question`).
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
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';
|
||||
import {alwaysFalseStateMock} from './classes/state-mock';
|
||||
|
||||
describe('exempt-issue-types option', () => {
|
||||
test('should skip issues with an exempt type', async () => {
|
||||
const opts: IIssuesProcessorOptions = {
|
||||
...DefaultProcessorOptions,
|
||||
exemptIssueTypes: 'question,discussion'
|
||||
};
|
||||
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A bug',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
[],
|
||||
'bug'
|
||||
),
|
||||
generateIssue(
|
||||
opts,
|
||||
2,
|
||||
'A question',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
[],
|
||||
'question'
|
||||
),
|
||||
generateIssue(
|
||||
opts,
|
||||
3,
|
||||
'A discussion',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
[],
|
||||
'discussion'
|
||||
)
|
||||
];
|
||||
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
await processor.processIssues(1);
|
||||
|
||||
// The exempt types should not be processed/marked stale
|
||||
expect(processor.staleIssues.map(i => i.title)).toEqual(['A bug']);
|
||||
});
|
||||
|
||||
test('should process all issues if exemptIssueTypes is unset', async () => {
|
||||
const opts: IIssuesProcessorOptions = {
|
||||
...DefaultProcessorOptions,
|
||||
exemptIssueTypes: ''
|
||||
};
|
||||
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A bug',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
[],
|
||||
'bug'
|
||||
),
|
||||
generateIssue(
|
||||
opts,
|
||||
2,
|
||||
'A feature',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
[],
|
||||
'feature'
|
||||
)
|
||||
];
|
||||
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
await processor.processIssues(1);
|
||||
expect(processor.staleIssues.map(i => i.title)).toEqual([
|
||||
'A bug',
|
||||
'A feature'
|
||||
]);
|
||||
});
|
||||
|
||||
test('should take precedence over onlyIssueTypes', async () => {
|
||||
const opts: IIssuesProcessorOptions = {
|
||||
...DefaultProcessorOptions,
|
||||
exemptIssueTypes: 'bug',
|
||||
onlyIssueTypes: 'bug'
|
||||
};
|
||||
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A bug',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
[],
|
||||
'bug'
|
||||
)
|
||||
];
|
||||
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
await processor.processIssues(1);
|
||||
expect(processor.staleIssues).toEqual([]);
|
||||
});
|
||||
|
||||
test('should ignore exemptIssueTypes filter when item is a pull request', async () => {
|
||||
const opts: IIssuesProcessorOptions = {
|
||||
...DefaultProcessorOptions,
|
||||
exemptIssueTypes: 'bug'
|
||||
};
|
||||
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A pull request',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
true,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
[],
|
||||
'bug'
|
||||
)
|
||||
];
|
||||
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
await processor.processIssues(1);
|
||||
expect(processor.staleIssues.map(i => i.title)).toEqual(['A pull request']);
|
||||
});
|
||||
});
|
||||
@@ -208,6 +208,10 @@ inputs:
|
||||
description: 'Only the issues or the pull requests with an assignee will be marked as stale automatically.'
|
||||
default: 'false'
|
||||
required: false
|
||||
exempt-issue-types:
|
||||
description: 'Issues with a matching type are exempt from being processed as stale/closed. Defaults to `[]` (disabled) and can be a comma-separated list of issue types.'
|
||||
default: ''
|
||||
required: false
|
||||
only-issue-types:
|
||||
description: 'Only issues with a matching type are processed as stale/closed. Defaults to `[]` (disabled) and can be a comma-separated list of issue types.'
|
||||
default: ''
|
||||
|
||||
Vendored
+16
-1
@@ -49743,6 +49743,7 @@ var Option;
|
||||
Option["IgnorePrUpdates"] = "ignore-pr-updates";
|
||||
Option["ExemptDraftPr"] = "exempt-draft-pr";
|
||||
Option["CloseIssueReason"] = "close-issue-reason";
|
||||
Option["ExemptIssueTypes"] = "exempt-issue-types";
|
||||
Option["OnlyIssueTypes"] = "only-issue-types";
|
||||
})(Option || (Option = {}));
|
||||
|
||||
@@ -51978,6 +51979,19 @@ class IssuesProcessor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// exemptIssueTypes wins if both it and onlyIssueTypes are specified
|
||||
if (this.options.exemptIssueTypes && !issue.isPullRequest) {
|
||||
const exemptTypes = this.options.exemptIssueTypes
|
||||
.split(',')
|
||||
.map(t => t.trim().toLowerCase())
|
||||
.filter(Boolean);
|
||||
const issueType = (issue.issue_type || '').toLowerCase();
|
||||
if (exemptTypes.includes(issueType)) {
|
||||
issueLogger.info(`Skipping this $$type because its type ('${issue.issue_type}') is in exemptIssueTypes (${exemptTypes.join(', ')})`);
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const onlyLabels = wordsToList(this._getOnlyLabels(issue));
|
||||
if (onlyLabels.length > 0) {
|
||||
issueLogger.info(`The option ${issueLogger.createOptionLink(Option.OnlyLabels)} was specified to only process issues and pull requests with all those labels (${LoggerService.cyan(onlyLabels.length)})`);
|
||||
@@ -106904,7 +106918,8 @@ function _getAndValidateArgs() {
|
||||
exemptDraftPr: getInput('exempt-draft-pr') === 'true',
|
||||
closeIssueReason: getInput('close-issue-reason'),
|
||||
includeOnlyAssigned: getInput('include-only-assigned') === 'true',
|
||||
onlyIssueTypes: getInput('only-issue-types')
|
||||
onlyIssueTypes: getInput('only-issue-types'),
|
||||
exemptIssueTypes: getInput('exempt-issue-types')
|
||||
};
|
||||
for (const numberInput of ['days-before-stale']) {
|
||||
if (isNaN(parseFloat(getInput(numberInput)))) {
|
||||
|
||||
Generated
+3
-3
@@ -3679,9 +3679,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.41",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.41.tgz",
|
||||
"integrity": "sha512-WwS7MHhqGHHlaVsqRZnhvCEMS0owDX+SxRlve7JkuH7My1Ara3ZriTmCQupPfYjxMZ8I/tgxtJYr2t7taHaH4A==",
|
||||
"version": "2.11.22",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.22.tgz",
|
||||
"integrity": "sha512-pWc4w51fBFd7mav43/zKRC+RI6f4yfzQoVlfvE8dECePyfkn1bzLp01Fj0QACcyCZyFhiEMyD2qScfKRWgWibA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
||||
@@ -268,6 +268,24 @@ export class IssuesProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
// exemptIssueTypes wins if both it and onlyIssueTypes are specified
|
||||
if (this.options.exemptIssueTypes && !issue.isPullRequest) {
|
||||
const exemptTypes = this.options.exemptIssueTypes
|
||||
.split(',')
|
||||
.map(t => t.trim().toLowerCase())
|
||||
.filter(Boolean);
|
||||
const issueType = (issue.issue_type || '').toLowerCase();
|
||||
if (exemptTypes.includes(issueType)) {
|
||||
issueLogger.info(
|
||||
`Skipping this $$type because its type ('${
|
||||
issue.issue_type
|
||||
}') is in exemptIssueTypes (${exemptTypes.join(', ')})`
|
||||
);
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const onlyLabels: string[] = wordsToList(this._getOnlyLabels(issue));
|
||||
|
||||
if (onlyLabels.length > 0) {
|
||||
|
||||
@@ -50,5 +50,6 @@ export enum Option {
|
||||
IgnorePrUpdates = 'ignore-pr-updates',
|
||||
ExemptDraftPr = 'exempt-draft-pr',
|
||||
CloseIssueReason = 'close-issue-reason',
|
||||
ExemptIssueTypes = 'exempt-issue-types',
|
||||
OnlyIssueTypes = 'only-issue-types'
|
||||
}
|
||||
|
||||
@@ -55,5 +55,6 @@ export interface IIssuesProcessorOptions {
|
||||
exemptDraftPr: boolean;
|
||||
closeIssueReason: string;
|
||||
includeOnlyAssigned: boolean;
|
||||
exemptIssueTypes?: string;
|
||||
onlyIssueTypes?: string;
|
||||
}
|
||||
|
||||
+2
-1
@@ -125,7 +125,8 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
|
||||
exemptDraftPr: core.getInput('exempt-draft-pr') === 'true',
|
||||
closeIssueReason: core.getInput('close-issue-reason'),
|
||||
includeOnlyAssigned: core.getInput('include-only-assigned') === 'true',
|
||||
onlyIssueTypes: core.getInput('only-issue-types')
|
||||
onlyIssueTypes: core.getInput('only-issue-types'),
|
||||
exemptIssueTypes: core.getInput('exempt-issue-types')
|
||||
};
|
||||
|
||||
for (const numberInput of ['days-before-stale']) {
|
||||
|
||||
Reference in New Issue
Block a user