Revert "Merge pull request #586 from C0ZEN/feature/split-pr-and-issue-options"

This reverts commit db699ab3b1, reversing
changes made to b83d488cb9.
This commit is contained in:
Luke Tomlinson
2021-10-20 09:25:24 -04:00
parent fc4a5ff942
commit 3a971aeb80
23 changed files with 12014 additions and 6533 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,218 +1,290 @@
import deburr from 'lodash.deburr';
import {Option} from '../enums/option';
import {wordsToList} from '../functions/words-to-list';
import {Assignee} from '../interfaces/assignee';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {LoggerService} from '../services/logger.service';
type CleanAssignee = string;
export class Assignees {
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);
}
private static _cleanAssignee(assignee: Readonly<string>): CleanAssignee {
return deburr(assignee.toLowerCase());
}
shouldExemptAssignees(): boolean {
if (!this._issue.hasAssignees) {
this._issueLogger.info('This $$type has no assignee');
this._logSkip();
return false;
}
if (this._shouldExemptAllAssignees()) {
this._issueLogger.info(
LoggerService.white('└──'),
'Skipping this $$type because it has an exempt assignee'
);
return true;
}
const exemptAssignees: string[] = this._getExemptAssignees();
if (exemptAssignees.length === 0) {
this._issueLogger.info(
LoggerService.white('├──'),
`No assignee option was specified to skip the stale process for this $$type`
);
this._logSkip();
return false;
}
this._issueLogger.info(
LoggerService.white('├──'),
`Found ${LoggerService.cyan(exemptAssignees.length)} assignee${
exemptAssignees.length > 1 ? 's' : ''
} that can exempt stale on this $$type`
);
const hasExemptAssignee: boolean = exemptAssignees.some(
(exemptAssignee: Readonly<string>): boolean =>
this._hasAssignee(exemptAssignee)
);
if (!hasExemptAssignee) {
this._issueLogger.info(
LoggerService.white('├──'),
'No assignee on this $$type can exempt the stale process'
);
this._logSkip();
} else {
this._issueLogger.info(
LoggerService.white('└──'),
'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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
);
return [];
}
const exemptAssignees: string[] = wordsToList(
this._options.exemptIssueAssignees
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueAssignees
)} is set. ${LoggerService.cyan(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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
);
return [];
}
const exemptAssignees: string[] = wordsToList(
this._options.exemptPrAssignees
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrAssignees
)} is set. ${LoggerService.cyan(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<Assignee>): boolean => {
const isSameAssignee: boolean =
cleanAssignee === Assignees._cleanAssignee(issueAssignee.login);
if (isSameAssignee) {
this._issueLogger.info(
LoggerService.white('├──'),
`@${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) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllIssueAssignees
)} is enabled. Any assignee on this $$type will skip the stale process`
);
return true;
}
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllIssueAssignees
)} is disabled. Only some specific assignees on this $$type will skip the stale process`
);
return false;
}
private _shouldExemptAllPullRequestAssignees(): boolean {
if (this._options.exemptAllPrAssignees) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllPrAssignees
)} is enabled. Any assignee on this $$type will skip the stale process`
);
return true;
}
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllPrAssignees
)} is disabled. Only some specific assignees on this $$type will skip the stale process`
);
return false;
}
private _logSkip(): void {
this._issueLogger.info(
LoggerService.white('└──'),
'Skip the assignees checks'
);
}
}
import deburr from 'lodash.deburr';
import {Option} from '../enums/option';
import {wordsToList} from '../functions/words-to-list';
import {Assignee} from '../interfaces/assignee';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {LoggerService} from '../services/logger.service';
type CleanAssignee = string;
export class Assignees {
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);
}
private static _cleanAssignee(assignee: Readonly<string>): CleanAssignee {
return deburr(assignee.toLowerCase());
}
shouldExemptAssignees(): boolean {
if (!this._issue.hasAssignees) {
this._issueLogger.info('This $$type has no assignee');
this._logSkip();
return false;
}
if (this._shouldExemptAllAssignees()) {
this._issueLogger.info(
LoggerService.white('└──'),
'Skipping this $$type because it has an exempt assignee'
);
return true;
}
const exemptAssignees: string[] = this._getExemptAssignees();
if (exemptAssignees.length === 0) {
this._issueLogger.info(
LoggerService.white('├──'),
`No assignee option was specified to skip the stale process for this $$type`
);
this._logSkip();
return false;
}
this._issueLogger.info(
LoggerService.white('├──'),
`Found ${LoggerService.cyan(exemptAssignees.length)} assignee${
exemptAssignees.length > 1 ? 's' : ''
} that can exempt stale on this $$type`
);
const hasExemptAssignee: boolean = exemptAssignees.some(
(exemptAssignee: Readonly<string>): boolean =>
this._hasAssignee(exemptAssignee)
);
if (!hasExemptAssignee) {
this._issueLogger.info(
LoggerService.white('├──'),
'No assignee on this $$type can exempt the stale process'
);
this._logSkip();
} else {
this._issueLogger.info(
LoggerService.white('└──'),
'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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
);
if (this._options.exemptAssignees === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAssignees
)} is set. ${LoggerService.cyan(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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueAssignees
)} is set. ${LoggerService.cyan(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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
);
if (this._options.exemptAssignees === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAssignees
)} is set. ${LoggerService.cyan(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(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrAssignees
)} is set. ${LoggerService.cyan(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<Assignee>): boolean => {
const isSameAssignee: boolean =
cleanAssignee === Assignees._cleanAssignee(issueAssignee.login);
if (isSameAssignee) {
this._issueLogger.info(
LoggerService.white('├──'),
`@${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 ${this._issueLogger.createOptionLink(
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 ${this._issueLogger.createOptionLink(
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 ${this._issueLogger.createOptionLink(
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 ${this._issueLogger.createOptionLink(
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 ${this._issueLogger.createOptionLink(
Option.ExemptAllAssignees
)} is enabled. Any assignee on this $$type will skip the stale process`
);
} else {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllAssignees
)} is disabled. Only some specific assignees on this $$type will skip the stale process`
);
}
}
private _logSkip(): void {
this._issueLogger.info(
LoggerService.white('└──'),
'Skip the assignees checks'
);
}
}

View File

@@ -1,163 +1,251 @@
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 {IgnoreUpdates} from './ignore-updates';
import {Issue} from './issue';
describe('IgnoreUpdates', (): void => {
let ignoreUpdates: IgnoreUpdates;
let optionsInterface: IIssuesProcessorOptions;
let issue: Issue;
let issueInterface: IIssue;
beforeEach((): void => {
optionsInterface = {
...DefaultProcessorOptions,
ignoreIssueUpdates: true
};
issueInterface = generateIIssue();
});
describe('shouldIgnoreUpdates()', (): void => {
describe('when the given issue is not a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = undefined;
});
describe('when the given options are configured to reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
describe('when the given options are configured to reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
});
describe('when the given issue is a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = {};
});
describe('when the given options are configured to reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
describe('when the given options are configured to reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
});
});
});
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 {IgnoreUpdates} from './ignore-updates';
import {Issue} from './issue';
describe('IgnoreUpdates', (): void => {
let ignoreUpdates: IgnoreUpdates;
let optionsInterface: IIssuesProcessorOptions;
let issue: Issue;
let issueInterface: IIssue;
beforeEach((): void => {
optionsInterface = {
...DefaultProcessorOptions,
ignoreIssueUpdates: true
};
issueInterface = generateIIssue();
});
describe('shouldIgnoreUpdates()', (): void => {
describe('when the given issue is not a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = undefined;
});
describe('when the given options are configured to reset the stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreUpdates = false;
});
describe('when the given options are not configured to reset the issue stale on updates', (): void => {
beforeEach((): void => {
delete optionsInterface.ignoreIssueUpdates;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
});
describe('when the given options are configured to reset the stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreUpdates = true;
});
describe('when the given options are not configured to reset the issue stale on updates', (): void => {
beforeEach((): void => {
delete optionsInterface.ignoreIssueUpdates;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
describe('when the given options are configured to reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the issue stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreIssueUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
});
});
describe('when the given issue is a pull request', (): void => {
beforeEach((): void => {
issueInterface.pull_request = {};
});
describe('when the given options are configured to reset the stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreUpdates = false;
});
describe('when the given options are not configured to reset the pull request stale on updates', (): void => {
beforeEach((): void => {
delete optionsInterface.ignorePrUpdates;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
});
describe('when the given options are configured to not reset the stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignoreUpdates = true;
});
describe('when the given options are not configured to reset the pull request stale on updates', (): void => {
beforeEach((): void => {
delete optionsInterface.ignorePrUpdates;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
describe('when the given options are configured to reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = false;
});
it('should return false', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(false);
});
});
describe('when the given options are configured to not reset the pull request stale on updates', (): void => {
beforeEach((): void => {
optionsInterface.ignorePrUpdates = true;
});
it('should return true', (): void => {
expect.assertions(1);
issue = new Issue(optionsInterface, issueInterface);
ignoreUpdates = new IgnoreUpdates(optionsInterface, issue);
const result = ignoreUpdates.shouldIgnoreUpdates();
expect(result).toStrictEqual(true);
});
});
});
});
});
});

View File

@@ -1,66 +1,90 @@
import {Option} from '../enums/option';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
export class IgnoreUpdates {
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);
}
shouldIgnoreUpdates(): boolean {
return this._shouldIgnoreUpdates();
}
private _shouldIgnoreUpdates(): boolean {
return this._issue.isPullRequest
? this._shouldIgnorePullRequestUpdates()
: this._shouldIgnoreIssueUpdates();
}
private _shouldIgnorePullRequestUpdates(): boolean {
if (this._options.ignorePrUpdates) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnorePrUpdates
)} is enabled. The stale counter will ignore any updates or comments on this $$type and will use the creation date as a reference ignoring any kind of update`
);
return true;
}
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnorePrUpdates
)} is disabled. The stale counter will take into account updates and comments on this $$type to avoid to stale when there is some update`
);
return false;
}
private _shouldIgnoreIssueUpdates(): boolean {
if (this._options.ignoreIssueUpdates) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnoreIssueUpdates
)} is enabled. The stale counter will ignore any updates or comments on this $$type and will use the creation date as a reference ignoring any kind of update`
);
return true;
}
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnoreIssueUpdates
)} is disabled. The stale counter will take into account updates and comments on this $$type to avoid to stale when there is some update`
);
return false;
}
}
import {Option} from '../enums/option';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
export class IgnoreUpdates {
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);
}
shouldIgnoreUpdates(): boolean {
return this._shouldIgnoreUpdates();
}
private _shouldIgnoreUpdates(): boolean {
return this._issue.isPullRequest
? this._shouldIgnorePullRequestUpdates()
: this._shouldIgnoreIssueUpdates();
}
private _shouldIgnorePullRequestUpdates(): boolean {
if (this._options.ignorePrUpdates === true) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnorePrUpdates
)} is enabled. The stale counter will ignore any updates or comments on this $$type and will use the creation date as a reference ignoring any kind of update`
);
return true;
} else if (this._options.ignorePrUpdates === false) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnorePrUpdates
)} is disabled. The stale counter will take into account updates and comments on this $$type to avoid to stale when there is some update`
);
return false;
}
this._logIgnoreUpdates();
return this._options.ignoreUpdates;
}
private _shouldIgnoreIssueUpdates(): boolean {
if (this._options.ignoreIssueUpdates === true) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnoreIssueUpdates
)} is enabled. The stale counter will ignore any updates or comments on this $$type and will use the creation date as a reference ignoring any kind of update`
);
return true;
} else if (this._options.ignoreIssueUpdates === false) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnoreIssueUpdates
)} is disabled. The stale counter will take into account updates and comments on this $$type to avoid to stale when there is some update`
);
return false;
}
this._logIgnoreUpdates();
return this._options.ignoreUpdates;
}
private _logIgnoreUpdates(): void {
if (this._options.ignoreUpdates) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnoreUpdates
)} is enabled. The stale counter will ignore any updates or comments on this $$type and will use the creation date as a reference ignoring any kind of update`
);
} else {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.IgnoreUpdates
)} is disabled. The stale counter will take into account updates and comments on this $$type to avoid to stale when there is some update`
);
}
}
}

View File

@@ -17,40 +17,50 @@ describe('Issue', (): void => {
closeIssueMessage: '',
closePrLabel: '',
closePrMessage: '',
daysBeforeClose: 0,
daysBeforeIssueClose: 0,
daysBeforeIssueStale: 0,
daysBeforePrClose: 0,
daysBeforePrStale: 0,
daysBeforeStale: 0,
debugOnly: false,
deleteBranch: false,
exemptIssueLabels: '',
exemptPrLabels: '',
onlyLabels: '',
onlyIssueLabels: '',
onlyPrLabels: '',
anyOfLabels: '',
anyOfIssueLabels: '',
anyOfPrLabels: '',
operationsPerRun: 0,
removeIssueStaleWhenUpdated: false,
removePrStaleWhenUpdated: false,
removeStaleWhenUpdated: false,
removeIssueStaleWhenUpdated: undefined,
removePrStaleWhenUpdated: undefined,
repoToken: '',
staleIssueMessage: '',
stalePrMessage: '',
startDate: undefined,
stalePrLabel: 'dummy-stale-pr-label',
staleIssueLabel: 'dummy-stale-issue-label',
exemptMilestones: '',
exemptIssueMilestones: '',
exemptPrMilestones: '',
exemptAllIssueMilestones: false,
exemptAllPrMilestones: false,
exemptAllMilestones: false,
exemptAllIssueMilestones: undefined,
exemptAllPrMilestones: undefined,
exemptAssignees: '',
exemptIssueAssignees: '',
exemptPrAssignees: '',
exemptAllIssueAssignees: false,
exemptAllPrAssignees: false,
exemptAllAssignees: false,
exemptAllIssueAssignees: undefined,
exemptAllPrAssignees: undefined,
enableStatistics: false,
labelsToRemoveWhenUnstale: '',
labelsToAddWhenUnstale: '',
ignoreIssueUpdates: false,
ignorePrUpdates: false,
ignoreUpdates: false,
ignoreIssueUpdates: undefined,
ignorePrUpdates: undefined,
exemptDraftPr: false
};
issueInterface = {

View File

@@ -3,28 +3,29 @@ import {context, getOctokit} from '@actions/github';
import {GitHub} from '@actions/github/lib/utils';
import {GetResponseTypeFromEndpointMethod} from '@octokit/types';
import {Option} from '../enums/option';
import {cleanLabel} from '../functions/clean-label';
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 {isBoolean} from '../functions/is-boolean';
import {isLabeled} from '../functions/is-labeled';
import {cleanLabel} from '../functions/clean-label';
import {shouldMarkWhenStale} from '../functions/should-mark-when-stale';
import {wordsToList} from '../functions/words-to-list';
import {IComment} from '../interfaces/comment';
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 {LoggerService} from '../services/logger.service';
import {Assignees} from './assignees';
import {ExemptDraftPullRequest} from './exempt-draft-pull-request';
import {IgnoreUpdates} from './ignore-updates';
import {ExemptDraftPullRequest} from './exempt-draft-pull-request';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {Logger} from './loggers/logger';
import {Milestones} from './milestones';
import {StaleOperations} from './stale-operations';
import {Statistics} from './statistics';
import {LoggerService} from '../services/logger.service';
import {IIssue} from '../interfaces/issue';
/***
* Handle processing of issues for staleness/closure.
@@ -206,8 +207,8 @@ export class IssuesProcessor {
? this.options.stalePrMessage.length === 0
: this.options.staleIssueMessage.length === 0;
const daysBeforeStale: number = issue.isPullRequest
? this.options.daysBeforePrStale
: this.options.daysBeforeIssueStale;
? this._getDaysBeforePrStale()
: this._getDaysBeforeIssueStale();
if (issue.state === 'closed') {
issueLogger.info(`Skipping this $$type because it is closed`);
@@ -226,7 +227,7 @@ export class IssuesProcessor {
if (onlyLabels.length > 0) {
issueLogger.info(
`The option ${issueLogger.createOptionLink(
issue.isPullRequest ? Option.OnlyPrLabels : Option.OnlyIssueLabels
Option.OnlyLabels
)} was specified to only process issues and pull requests with all those labels (${LoggerService.cyan(
onlyLabels.length
)})`
@@ -259,7 +260,7 @@ export class IssuesProcessor {
} else {
issueLogger.info(
`The option ${issueLogger.createOptionLink(
issue.isPullRequest ? Option.OnlyPrLabels : Option.OnlyIssueLabels
Option.OnlyLabels
)} was not specified`
);
issueLogger.info(
@@ -344,7 +345,7 @@ export class IssuesProcessor {
if (anyOfLabels.length > 0) {
issueLogger.info(
`The option ${issueLogger.createOptionLink(
issue.isPullRequest ? Option.AnyOfPrLabels : Option.AnyOfIssueLabels
Option.AnyOfLabels
)} was specified to only process the issues and pull requests with one of those labels (${LoggerService.cyan(
anyOfLabels.length
)})`
@@ -376,7 +377,7 @@ export class IssuesProcessor {
} else {
issueLogger.info(
`The option ${issueLogger.createOptionLink(
issue.isPullRequest ? Option.AnyOfPrLabels : Option.AnyOfIssueLabels
Option.AnyOfLabels
)} was not specified`
);
issueLogger.info(
@@ -460,7 +461,7 @@ export class IssuesProcessor {
if (shouldMarkAsStale) {
issueLogger.info(
`This $$type should be marked as stale based on the option ${issueLogger.createOptionLink(
IssuesProcessor._getDaysBeforeStaleUsedOptionName(issue)
this._getDaysBeforeStaleUsedOptionName(issue)
)} (${LoggerService.cyan(daysBeforeStale)})`
);
await this._markStale(issue, staleMessage, staleLabel, skipMessage);
@@ -469,7 +470,7 @@ export class IssuesProcessor {
} else {
issueLogger.info(
`This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(
IssuesProcessor._getDaysBeforeStaleUsedOptionName(issue)
this._getDaysBeforeStaleUsedOptionName(issue)
)} (${LoggerService.cyan(daysBeforeStale)})`
);
}
@@ -639,8 +640,8 @@ export class IssuesProcessor {
);
const daysBeforeClose: number = issue.isPullRequest
? this.options.daysBeforePrClose
: this.options.daysBeforeIssueClose;
? this._getDaysBeforePrClose()
: this._getDaysBeforeIssueClose();
issueLogger.info(
`Days before $$type close: ${LoggerService.cyan(daysBeforeClose)}`
@@ -659,7 +660,7 @@ export class IssuesProcessor {
issueLogger.info(
`The option ${issueLogger.createOptionLink(
IssuesProcessor._getRemoveStaleWhenUpdatedUsedOptionName(issue)
this._getRemoveStaleWhenUpdatedUsedOptionName(issue)
)} is: ${LoggerService.cyan(shouldRemoveStaleWhenUpdated)}`
);
@@ -956,26 +957,72 @@ export class IssuesProcessor {
}
}
private _getDaysBeforeIssueStale(): number {
return isNaN(this.options.daysBeforeIssueStale)
? this.options.daysBeforeStale
: this.options.daysBeforeIssueStale;
}
private _getDaysBeforePrStale(): number {
return isNaN(this.options.daysBeforePrStale)
? this.options.daysBeforeStale
: this.options.daysBeforePrStale;
}
private _getDaysBeforeIssueClose(): number {
return isNaN(this.options.daysBeforeIssueClose)
? this.options.daysBeforeClose
: this.options.daysBeforeIssueClose;
}
private _getDaysBeforePrClose(): number {
return isNaN(this.options.daysBeforePrClose)
? this.options.daysBeforeClose
: this.options.daysBeforePrClose;
}
private _getOnlyLabels(issue: Issue): string {
if (issue.isPullRequest) {
return this.options.onlyPrLabels;
if (this.options.onlyPrLabels !== '') {
return this.options.onlyPrLabels;
}
} else {
if (this.options.onlyIssueLabels !== '') {
return this.options.onlyIssueLabels;
}
}
return this.options.onlyIssueLabels;
return this.options.onlyLabels;
}
private _getAnyOfLabels(issue: Issue): string {
if (issue.isPullRequest) {
return this.options.anyOfPrLabels;
if (this.options.anyOfPrLabels !== '') {
return this.options.anyOfPrLabels;
}
} else {
if (this.options.anyOfIssueLabels !== '') {
return this.options.anyOfIssueLabels;
}
}
return this.options.anyOfIssueLabels;
return this.options.anyOfLabels;
}
private _shouldRemoveStaleWhenUpdated(issue: Issue): boolean {
return issue.isPullRequest
? this.options.removePrStaleWhenUpdated
: this.options.removeIssueStaleWhenUpdated;
if (issue.isPullRequest) {
if (isBoolean(this.options.removePrStaleWhenUpdated)) {
return this.options.removePrStaleWhenUpdated;
}
return this.options.removeStaleWhenUpdated;
}
if (isBoolean(this.options.removeIssueStaleWhenUpdated)) {
return this.options.removeIssueStaleWhenUpdated;
}
return this.options.removeStaleWhenUpdated;
}
private async _removeLabelsWhenUnstale(
@@ -1094,24 +1141,56 @@ export class IssuesProcessor {
}
}
private static _getDaysBeforeStaleUsedOptionName(
issue: Readonly<Issue>
): Option.DaysBeforeIssueStale | Option.DaysBeforePrStale {
return issue.isPullRequest
? Option.DaysBeforePrStale
: Option.DaysBeforeIssueStale;
}
private static _getRemoveStaleWhenUpdatedUsedOptionName(
issue: Readonly<Issue>
): Option.RemovePrStaleWhenUpdated | Option.RemoveIssueStaleWhenUpdated {
return issue.isPullRequest
? Option.RemovePrStaleWhenUpdated
: Option.RemoveIssueStaleWhenUpdated;
}
private _consumeIssueOperation(issue: Readonly<Issue>): void {
this.operations.consumeOperation();
issue.operations.consumeOperation();
}
private _getDaysBeforeStaleUsedOptionName(
issue: Readonly<Issue>
):
| Option.DaysBeforeStale
| Option.DaysBeforeIssueStale
| Option.DaysBeforePrStale {
return issue.isPullRequest
? this._getDaysBeforePrStaleUsedOptionName()
: this._getDaysBeforeIssueStaleUsedOptionName();
}
private _getDaysBeforeIssueStaleUsedOptionName():
| Option.DaysBeforeStale
| Option.DaysBeforeIssueStale {
return isNaN(this.options.daysBeforeIssueStale)
? Option.DaysBeforeStale
: Option.DaysBeforeIssueStale;
}
private _getDaysBeforePrStaleUsedOptionName():
| Option.DaysBeforeStale
| Option.DaysBeforePrStale {
return isNaN(this.options.daysBeforePrStale)
? Option.DaysBeforeStale
: Option.DaysBeforePrStale;
}
private _getRemoveStaleWhenUpdatedUsedOptionName(
issue: Readonly<Issue>
):
| Option.RemovePrStaleWhenUpdated
| Option.RemoveStaleWhenUpdated
| Option.RemoveIssueStaleWhenUpdated {
if (issue.isPullRequest) {
if (isBoolean(this.options.removePrStaleWhenUpdated)) {
return Option.RemovePrStaleWhenUpdated;
}
return Option.RemoveStaleWhenUpdated;
}
if (isBoolean(this.options.removeIssueStaleWhenUpdated)) {
return Option.RemoveIssueStaleWhenUpdated;
}
return Option.RemoveStaleWhenUpdated;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,225 +1,297 @@
import deburr from 'lodash.deburr';
import {Option} from '../enums/option';
import {wordsToList} from '../functions/words-to-list';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {LoggerService} from '../services/logger.service';
type CleanMilestone = string;
export class Milestones {
private static _cleanMilestone(milestone: Readonly<string>): CleanMilestone {
return deburr(milestone.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);
}
shouldExemptMilestones(): boolean {
if (!this._issue.milestone) {
this._issueLogger.info('This $$type has no milestone');
this._logSkip();
return false;
}
if (this._shouldExemptAllMilestones()) {
this._issueLogger.info(
LoggerService.white('└──'),
'Skipping this $$type because it has a milestone'
);
return true;
}
const exemptMilestones: string[] = this._getExemptMilestones();
if (exemptMilestones.length === 0) {
this._issueLogger.info(
LoggerService.white('├──'),
`No milestone option was specified to skip the stale process for this $$type`
);
this._logSkip();
return false;
}
this._issueLogger.info(
LoggerService.white('├──'),
`Found ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length > 1 ? 's' : ''
} that can exempt stale on this $$type`
);
const hasExemptMilestone: boolean = exemptMilestones.some(
(exemptMilestone: Readonly<string>): boolean =>
this._hasMilestone(exemptMilestone)
);
if (!hasExemptMilestone) {
this._issueLogger.info(
LoggerService.white('├──'),
'No milestone on this $$type can exempt the stale process'
);
this._logSkip();
} else {
this._issueLogger.info(
LoggerService.white('└──'),
'Skipping this $$type because it has an exempt milestone'
);
}
return hasExemptMilestone;
}
private _getExemptMilestones(): string[] {
return this._issue.isPullRequest
? this._getExemptPullRequestMilestones()
: this._getExemptIssueMilestones();
}
private _getExemptIssueMilestones(): string[] {
if (this._options.exemptIssueMilestones === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
);
return [];
}
const exemptMilestones: string[] = wordsToList(
this._options.exemptIssueMilestones
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueMilestones
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptMilestones;
}
private _getExemptPullRequestMilestones(): string[] {
if (this._options.exemptPrMilestones === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
);
return [];
}
const exemptMilestones: string[] = wordsToList(
this._options.exemptPrMilestones
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrMilestones
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptMilestones;
}
private _hasMilestone(milestone: Readonly<string>): boolean {
if (!this._issue.milestone) {
return false;
}
const cleanMilestone: CleanMilestone =
Milestones._cleanMilestone(milestone);
const isSameMilestone: boolean =
cleanMilestone ===
Milestones._cleanMilestone(this._issue.milestone.title);
if (isSameMilestone) {
this._issueLogger.info(
LoggerService.white('├──'),
`The milestone "${LoggerService.cyan(
milestone
)}" is set on this $$type and is an exempt milestone`
);
}
return isSameMilestone;
}
private _shouldExemptAllMilestones(): boolean {
if (this._issue.milestone) {
return this._issue.isPullRequest
? this._shouldExemptAllPullRequestMilestones()
: this._shouldExemptAllIssueMilestones();
}
return false;
}
private _shouldExemptAllIssueMilestones(): boolean {
if (this._options.exemptAllIssueMilestones) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllIssueMilestones
)} is enabled. Any milestone on this $$type will skip the stale process`
);
return true;
}
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllIssueMilestones
)} is disabled. Only some specific milestones on this $$type will skip the stale process`
);
return false;
}
private _shouldExemptAllPullRequestMilestones(): boolean {
if (this._options.exemptAllPrMilestones) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllPrMilestones
)} is enabled. Any milestone on this $$type will skip the stale process`
);
return true;
}
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllPrMilestones
)} is disabled. Only some specific milestones on this $$type will skip the stale process`
);
return false;
}
private _logSkip(): void {
this._issueLogger.info(
LoggerService.white('└──'),
'Skip the milestones checks'
);
}
}
import deburr from 'lodash.deburr';
import {Option} from '../enums/option';
import {wordsToList} from '../functions/words-to-list';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {LoggerService} from '../services/logger.service';
type CleanMilestone = string;
export class Milestones {
private static _cleanMilestone(milestone: Readonly<string>): CleanMilestone {
return deburr(milestone.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);
}
shouldExemptMilestones(): boolean {
if (!this._issue.milestone) {
this._issueLogger.info('This $$type has no milestone');
this._logSkip();
return false;
}
if (this._shouldExemptAllMilestones()) {
this._issueLogger.info(
LoggerService.white('└──'),
'Skipping this $$type because it has a milestone'
);
return true;
}
const exemptMilestones: string[] = this._getExemptMilestones();
if (exemptMilestones.length === 0) {
this._issueLogger.info(
LoggerService.white('├──'),
`No milestone option was specified to skip the stale process for this $$type`
);
this._logSkip();
return false;
}
this._issueLogger.info(
LoggerService.white('├──'),
`Found ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length > 1 ? 's' : ''
} that can exempt stale on this $$type`
);
const hasExemptMilestone: boolean = exemptMilestones.some(
(exemptMilestone: Readonly<string>): boolean =>
this._hasMilestone(exemptMilestone)
);
if (!hasExemptMilestone) {
this._issueLogger.info(
LoggerService.white('├──'),
'No milestone on this $$type can exempt the stale process'
);
this._logSkip();
} else {
this._issueLogger.info(
LoggerService.white('└──'),
'Skipping this $$type because it has an exempt milestone'
);
}
return hasExemptMilestone;
}
private _getExemptMilestones(): string[] {
return this._issue.isPullRequest
? this._getExemptPullRequestMilestones()
: this._getExemptIssueMilestones();
}
private _getExemptIssueMilestones(): string[] {
if (this._options.exemptIssueMilestones === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
);
if (this._options.exemptMilestones === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
);
return [];
}
const exemptMilestones: string[] = wordsToList(
this._options.exemptMilestones
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptMilestones;
}
const exemptMilestones: string[] = wordsToList(
this._options.exemptIssueMilestones
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueMilestones
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptMilestones;
}
private _getExemptPullRequestMilestones(): string[] {
if (this._options.exemptPrMilestones === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
);
if (this._options.exemptMilestones === '') {
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
);
return [];
}
const exemptMilestones: string[] = wordsToList(
this._options.exemptMilestones
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptMilestones;
}
const exemptMilestones: string[] = wordsToList(
this._options.exemptPrMilestones
);
this._issueLogger.info(
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrMilestones
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
return exemptMilestones;
}
private _hasMilestone(milestone: Readonly<string>): boolean {
if (!this._issue.milestone) {
return false;
}
const cleanMilestone: CleanMilestone =
Milestones._cleanMilestone(milestone);
const isSameMilestone: boolean =
cleanMilestone ===
Milestones._cleanMilestone(this._issue.milestone.title);
if (isSameMilestone) {
this._issueLogger.info(
LoggerService.white('├──'),
`The milestone "${LoggerService.cyan(
milestone
)}" is set on this $$type and is an exempt milestone`
);
}
return isSameMilestone;
}
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) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllIssueMilestones
)} is enabled. Any milestone on this $$type will skip the stale process`
);
return true;
} else if (this._options.exemptAllIssueMilestones === false) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllIssueMilestones
)} is disabled. Only some specific milestones on this $$type will skip the stale process`
);
return false;
}
this._logExemptAllMilestonesOption();
return this._options.exemptAllMilestones;
}
private _shouldExemptAllPullRequestMilestones(): boolean {
if (this._options.exemptAllPrMilestones === true) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllPrMilestones
)} is enabled. Any milestone on this $$type will skip the stale process`
);
return true;
} else if (this._options.exemptAllPrMilestones === false) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllPrMilestones
)} is disabled. Only some specific milestones on this $$type will skip the stale process`
);
return false;
}
this._logExemptAllMilestonesOption();
return this._options.exemptAllMilestones;
}
private _logExemptAllMilestonesOption(): void {
if (this._options.exemptAllMilestones) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllMilestones
)} is enabled. Any milestone on this $$type will skip the stale process`
);
} else {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAllMilestones
)} is disabled. Only some specific milestones on this $$type will skip the stale process`
);
}
}
private _logSkip(): void {
this._issueLogger.info(
LoggerService.white('└──'),
'Skip the milestones checks'
);
}
}

View File

@@ -4,8 +4,10 @@ export enum Option {
StalePrMessage = 'stale-pr-message',
CloseIssueMessage = 'close-issue-message',
ClosePrMessage = 'close-pr-message',
DaysBeforeStale = 'days-before-stale',
DaysBeforeIssueStale = 'days-before-issue-stale',
DaysBeforePrStale = 'days-before-pr-stale',
DaysBeforeClose = 'days-before-close',
DaysBeforeIssueClose = 'days-before-issue-close',
DaysBeforePrClose = 'days-before-pr-close',
StaleIssueLabel = 'stale-issue-label',
@@ -14,28 +16,34 @@ export enum Option {
StalePrLabel = 'stale-pr-label',
ClosePrLabel = 'close-pr-label',
ExemptPrLabels = 'exempt-pr-labels',
OnlyLabels = 'only-labels',
OnlyIssueLabels = 'only-issue-labels',
OnlyPrLabels = 'only-pr-labels',
AnyOfIssueLabels = 'any-of-issue-labels',
AnyOfPrLabels = 'any-of-pr-labels',
AnyOfLabels = 'any-of-labels',
OperationsPerRun = 'operations-per-run',
RemoveStaleWhenUpdated = 'remove-stale-when-updated',
RemoveIssueStaleWhenUpdated = 'remove-issue-stale-when-updated',
RemovePrStaleWhenUpdated = 'remove-pr-stale-when-updated',
DebugOnly = 'debug-only',
Ascending = 'ascending',
DeleteBranch = 'delete-branch',
StartDate = 'start-date',
ExemptMilestones = 'exempt-milestones',
ExemptIssueMilestones = 'exempt-issue-milestones',
ExemptPrMilestones = 'exempt-pr-milestones',
ExemptAllMilestones = 'exempt-all-milestones',
ExemptAllIssueMilestones = 'exempt-all-issue-milestones',
ExemptAllPrMilestones = 'exempt-all-pr-milestones',
ExemptAssignees = 'exempt-assignees',
ExemptIssueAssignees = 'exempt-issue-assignees',
ExemptPrAssignees = 'exempt-pr-assignees',
ExemptAllAssignees = 'exempt-all-assignees',
ExemptAllIssueAssignees = 'exempt-all-issue-assignees',
ExemptAllPrAssignees = 'exempt-all-pr-assignees',
EnableStatistics = 'enable-statistics',
LabelsToRemoveWhenUnstale = 'labels-to-remove-when-unstale',
LabelsToAddWhenUnstale = 'labels-to-add-when-unstale',
IgnoreUpdates = 'ignore-updates',
IgnoreIssueUpdates = 'ignore-issue-updates',
IgnorePrUpdates = 'ignore-pr-updates',
ExemptDraftPr = 'exempt-draft-pr'

View File

@@ -6,39 +6,49 @@ export interface IIssuesProcessorOptions {
stalePrMessage: string;
closeIssueMessage: string;
closePrMessage: string;
daysBeforeIssueStale: number;
daysBeforePrStale: number;
daysBeforeIssueClose: number;
daysBeforePrClose: number;
daysBeforeStale: number;
daysBeforeIssueStale: number; // Could be NaN
daysBeforePrStale: number; // Could be NaN
daysBeforeClose: number;
daysBeforeIssueClose: number; // Could be NaN
daysBeforePrClose: number; // Could be NaN
staleIssueLabel: string;
closeIssueLabel: string;
exemptIssueLabels: string;
stalePrLabel: string;
closePrLabel: string;
exemptPrLabels: string;
onlyLabels: string;
onlyIssueLabels: string;
onlyPrLabels: string;
anyOfLabels: string;
anyOfIssueLabels: string;
anyOfPrLabels: string;
operationsPerRun: number;
removeIssueStaleWhenUpdated: boolean;
removePrStaleWhenUpdated: boolean;
removeStaleWhenUpdated: boolean;
removeIssueStaleWhenUpdated: boolean | undefined;
removePrStaleWhenUpdated: boolean | undefined;
debugOnly: boolean;
ascending: boolean;
deleteBranch: boolean;
startDate: IsoOrRfcDateString | undefined; // Should be ISO 8601 or RFC 2822
exemptMilestones: string;
exemptIssueMilestones: string;
exemptPrMilestones: string;
exemptAllIssueMilestones: boolean;
exemptAllPrMilestones: boolean;
exemptAllMilestones: boolean;
exemptAllIssueMilestones: boolean | undefined;
exemptAllPrMilestones: boolean | undefined;
exemptAssignees: string;
exemptIssueAssignees: string;
exemptPrAssignees: string;
exemptAllIssueAssignees: boolean;
exemptAllPrAssignees: boolean;
exemptAllAssignees: boolean;
exemptAllIssueAssignees: boolean | undefined;
exemptAllPrAssignees: boolean | undefined;
enableStatistics: boolean;
labelsToRemoveWhenUnstale: string;
labelsToAddWhenUnstale: string;
ignoreIssueUpdates: boolean;
ignorePrUpdates: boolean;
ignoreUpdates: boolean;
ignoreIssueUpdates: boolean | undefined;
ignorePrUpdates: boolean | undefined;
exemptDraftPr: boolean;
}

View File

@@ -28,36 +28,39 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
stalePrMessage: core.getInput('stale-pr-message'),
closeIssueMessage: core.getInput('close-issue-message'),
closePrMessage: core.getInput('close-pr-message'),
daysBeforeIssueStale: parseInt(
core.getInput('days-before-issue-stale', {required: true})
daysBeforeStale: parseInt(
core.getInput('days-before-stale', {required: true})
),
daysBeforePrStale: parseInt(
core.getInput('days-before-pr-stale', {required: true})
),
daysBeforeIssueClose: parseInt(
core.getInput('days-before-issue-close', {required: true})
),
daysBeforePrClose: parseInt(
core.getInput('days-before-pr-close', {required: true})
daysBeforeIssueStale: parseInt(core.getInput('days-before-issue-stale')),
daysBeforePrStale: parseInt(core.getInput('days-before-pr-stale')),
daysBeforeClose: parseInt(
core.getInput('days-before-close', {required: true})
),
daysBeforeIssueClose: parseInt(core.getInput('days-before-issue-close')),
daysBeforePrClose: parseInt(core.getInput('days-before-pr-close')),
staleIssueLabel: core.getInput('stale-issue-label', {required: true}),
closeIssueLabel: core.getInput('close-issue-label'),
exemptIssueLabels: core.getInput('exempt-issue-labels'),
stalePrLabel: core.getInput('stale-pr-label', {required: true}),
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'),
anyOfIssueLabels: core.getInput('any-of-issue-labels'),
anyOfPrLabels: core.getInput('any-of-pr-labels'),
operationsPerRun: parseInt(
core.getInput('operations-per-run', {required: true})
),
removeIssueStaleWhenUpdated: !(
core.getInput('remove-issue-stale-when-updated') === 'false'
removeStaleWhenUpdated: !(
core.getInput('remove-stale-when-updated') === 'false'
),
removePrStaleWhenUpdated: !(
core.getInput('remove-pr-stale-when-updated') === 'false'
removeIssueStaleWhenUpdated: _toOptionalBoolean(
'remove-issue-stale-when-updated'
),
removePrStaleWhenUpdated: _toOptionalBoolean(
'remove-pr-stale-when-updated'
),
debugOnly: core.getInput('debug-only') === 'true',
ascending: core.getInput('ascending') === 'true',
@@ -66,29 +69,30 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
core.getInput('start-date') !== ''
? core.getInput('start-date')
: undefined,
exemptMilestones: core.getInput('exempt-milestones'),
exemptIssueMilestones: core.getInput('exempt-issue-milestones'),
exemptPrMilestones: core.getInput('exempt-pr-milestones'),
exemptAllIssueMilestones:
core.getInput('exempt-all-issue-milestones') === 'true',
exemptAllPrMilestones: core.getInput('exempt-all-pr-milestones') === 'true',
exemptAllMilestones: core.getInput('exempt-all-milestones') === 'true',
exemptAllIssueMilestones: _toOptionalBoolean('exempt-all-issue-milestones'),
exemptAllPrMilestones: _toOptionalBoolean('exempt-all-pr-milestones'),
exemptAssignees: core.getInput('exempt-assignees'),
exemptIssueAssignees: core.getInput('exempt-issue-assignees'),
exemptPrAssignees: core.getInput('exempt-pr-assignees'),
exemptAllIssueAssignees:
core.getInput('exempt-all-issue-assignees') === 'true',
exemptAllPrAssignees: core.getInput('exempt-all-pr-assignees') === 'true',
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',
labelsToRemoveWhenUnstale: core.getInput('labels-to-remove-when-unstale'),
labelsToAddWhenUnstale: core.getInput('labels-to-add-when-unstale'),
ignoreIssueUpdates: core.getInput('ignore-issue-updates') === 'true',
ignorePrUpdates: core.getInput('ignore-pr-updates') === 'true',
ignoreUpdates: core.getInput('ignore-updates') === 'true',
ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'),
ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'),
exemptDraftPr: core.getInput('exempt-draft-pr') === 'true'
};
for (const numberInput of [
'days-before-issue-stale',
'days-before-pr-stale',
'days-before-issue-close',
'days-before-pr-close',
'days-before-stale',
'days-before-close',
'operations-per-run'
]) {
if (isNaN(parseInt(core.getInput(numberInput)))) {
@@ -120,4 +124,29 @@ async function processOutput(
core.setOutput('closed-issues-prs', JSON.stringify(closedIssues));
}
/**
* @description
* From an argument name, get the value as an optional boolean
* This is very useful for all the arguments that override others
* It will allow us to easily use the original one when the return value is `undefined`
* Which is different from `true` or `false` that consider the argument as set
*
* @param {Readonly<string>} argumentName The name of the argument to check
*
* @returns {boolean | undefined} The value matching the given argument name
*/
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;
}
void _run();