Issue 596/include only assigned (#817)

* Add new 'include-only-assigned' option

If set, only issues containing assignees will be processed

* Test new flag

* Update code comment

* Update src/classes/issues-processor.ts

Co-authored-by: Francesco Renzi <rentziass@github.com>

* Update index.js with typo fix

Co-authored-by: Francesco Renzi <rentziass@github.com>
This commit is contained in:
JoannaaKL 2022-09-12 13:20:57 +02:00 committed by GitHub
parent 33e37032bb
commit 3e4418e47e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 95 additions and 4 deletions

View File

@ -51,5 +51,6 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
ignoreIssueUpdates: undefined, ignoreIssueUpdates: undefined,
ignorePrUpdates: undefined, ignorePrUpdates: undefined,
exemptDraftPr: false, exemptDraftPr: false,
closeIssueReason: '' closeIssueReason: '',
includeOnlyAssigned: false
}); });

View File

@ -2352,3 +2352,69 @@ test('processing a pull request to be stale with the "stalePrMessage" option set
expect(processor.closedIssues).toHaveLength(0); expect(processor.closedIssues).toHaveLength(0);
expect(processor.statistics?.addedPullRequestsCommentsCount).toStrictEqual(0); expect(processor.statistics?.addedPullRequestsCommentsCount).toStrictEqual(0);
}); });
test('processing an issue with the "includeOnlyAssigned" option and nonempty assignee list will stale the issue', async () => {
const issueDate = new Date();
issueDate.setDate(issueDate.getDate() - 2);
const opts: IIssuesProcessorOptions = {
...DefaultProcessorOptions,
staleIssueLabel: 'This issue is stale',
includeOnlyAssigned: true
};
const TestIssueList: Issue[] = [
generateIssue(
opts,
1,
'An issue with no label',
issueDate.toDateString(),
issueDate.toDateString(),
false,
[],
false,
false,
undefined,
['assignee1']
)
];
const processor = new IssuesProcessorMock(
opts,
async p => (p === 1 ? TestIssueList : []),
async () => [],
async () => new Date().toDateString()
);
// process our fake issue list
await processor.processIssues(1);
expect(processor.staleIssues).toHaveLength(1);
expect(processor.closedIssues).toHaveLength(0);
});
test('processing an issue with the "includeOnlyAssigned" option set and no assignees will not stale the issue', async () => {
const issueDate = new Date();
issueDate.setDate(issueDate.getDate() - 2);
const opts: IIssuesProcessorOptions = {
...DefaultProcessorOptions,
staleIssueLabel: 'This issue is stale',
includeOnlyAssigned: true
};
const TestIssueList: Issue[] = [
generateIssue(opts, 1, 'An issue with no label', issueDate.toDateString())
];
const processor = new IssuesProcessorMock(
opts,
async p => (p === 1 ? TestIssueList : []),
async () => [],
async () => new Date().toDateString()
);
// process our fake issue list
await processor.processIssues(1);
expect(processor.staleIssues).toHaveLength(0);
expect(processor.closedIssues).toHaveLength(0);
});

11
dist/index.js vendored
View File

@ -476,6 +476,11 @@ class IssuesProcessor {
IssuesProcessor._endIssueProcessing(issue); IssuesProcessor._endIssueProcessing(issue);
return; // Don't process locked issues return; // Don't process locked issues
} }
if (this._isIncludeOnlyAssigned(issue)) {
issueLogger.info(`Skipping this $$type because its assignees list is empty`);
IssuesProcessor._endIssueProcessing(issue);
return; // If the issue has an 'include-only-assigned' option set, process only issues with nonempty assignees list
}
const onlyLabels = words_to_list_1.wordsToList(this._getOnlyLabels(issue)); const onlyLabels = words_to_list_1.wordsToList(this._getOnlyLabels(issue));
if (onlyLabels.length > 0) { if (onlyLabels.length > 0) {
issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.OnlyLabels)} was specified to only process issues and pull requests with all those labels (${logger_service_1.LoggerService.cyan(onlyLabels.length)})`); issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.OnlyLabels)} was specified to only process issues and pull requests with all those labels (${logger_service_1.LoggerService.cyan(onlyLabels.length)})`);
@ -988,6 +993,9 @@ class IssuesProcessor {
} }
return this.options.onlyLabels; return this.options.onlyLabels;
} }
_isIncludeOnlyAssigned(issue) {
return this.options.includeOnlyAssigned && !issue.hasAssignees;
}
_getAnyOfLabels(issue) { _getAnyOfLabels(issue) {
if (issue.isPullRequest) { if (issue.isPullRequest) {
if (this.options.anyOfPrLabels !== '') { if (this.options.anyOfPrLabels !== '') {
@ -2207,7 +2215,8 @@ function _getAndValidateArgs() {
ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'), ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'),
ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'), ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'),
exemptDraftPr: core.getInput('exempt-draft-pr') === 'true', exemptDraftPr: core.getInput('exempt-draft-pr') === 'true',
closeIssueReason: core.getInput('close-issue-reason') closeIssueReason: core.getInput('close-issue-reason'),
includeOnlyAssigned: core.getInput('include-only-assigned') === 'true'
}; };
for (const numberInput of [ for (const numberInput of [
'days-before-stale', 'days-before-stale',

View File

@ -62,7 +62,8 @@ describe('Issue', (): void => {
ignoreIssueUpdates: undefined, ignoreIssueUpdates: undefined,
ignorePrUpdates: undefined, ignorePrUpdates: undefined,
exemptDraftPr: false, exemptDraftPr: false,
closeIssueReason: '' closeIssueReason: '',
includeOnlyAssigned: false
}; };
issueInterface = { issueInterface = {
title: 'dummy-title', title: 'dummy-title',

View File

@ -221,6 +221,14 @@ export class IssuesProcessor {
return; // Don't process locked issues return; // Don't process locked issues
} }
if (this._isIncludeOnlyAssigned(issue)) {
issueLogger.info(
`Skipping this $$type because its assignees list is empty`
);
IssuesProcessor._endIssueProcessing(issue);
return; // If the issue has an 'include-only-assigned' option set, process only issues with nonempty assignees list
}
const onlyLabels: string[] = wordsToList(this._getOnlyLabels(issue)); const onlyLabels: string[] = wordsToList(this._getOnlyLabels(issue));
if (onlyLabels.length > 0) { if (onlyLabels.length > 0) {
@ -1012,6 +1020,10 @@ export class IssuesProcessor {
return this.options.onlyLabels; return this.options.onlyLabels;
} }
private _isIncludeOnlyAssigned(issue: Issue): boolean {
return this.options.includeOnlyAssigned && !issue.hasAssignees;
}
private _getAnyOfLabels(issue: Issue): string { private _getAnyOfLabels(issue: Issue): string {
if (issue.isPullRequest) { if (issue.isPullRequest) {
if (this.options.anyOfPrLabels !== '') { if (this.options.anyOfPrLabels !== '') {

View File

@ -52,4 +52,5 @@ export interface IIssuesProcessorOptions {
ignorePrUpdates: boolean | undefined; ignorePrUpdates: boolean | undefined;
exemptDraftPr: boolean; exemptDraftPr: boolean;
closeIssueReason: string; closeIssueReason: string;
includeOnlyAssigned: boolean;
} }

View File

@ -88,7 +88,8 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'), ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'),
ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'), ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'),
exemptDraftPr: core.getInput('exempt-draft-pr') === 'true', exemptDraftPr: core.getInput('exempt-draft-pr') === 'true',
closeIssueReason: core.getInput('close-issue-reason') closeIssueReason: core.getInput('close-issue-reason'),
includeOnlyAssigned: core.getInput('include-only-assigned') === 'true'
}; };
for (const numberInput of [ for (const numberInput of [