diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d69fb66..481abe22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +# [7.0.0] + +:warning: Breaking change :warning: + +* Allow daysBeforeStale options to be float by @irega in https://github.com/actions/stale/pull/841 +* Use cache in check-dist.yml by @jongwooo in https://github.com/actions/stale/pull/876 +* fix print outputs step in existing workflows by @irega in https://github.com/actions/stale/pull/859 +* Update issue and PR templates, add/delete workflow files by @IvanZosimov in https://github.com/actions/stale/pull/880 +* Update how stale handles exempt items by @johnsudol in https://github.com/actions/stale/pull/874 + # [6.0.1] Update @actions/core to v1.10.0 ([#839](https://github.com/actions/stale/pull/839)) diff --git a/README.md b/README.md index b35614e4..41de7f22 100644 --- a/README.md +++ b/README.md @@ -246,8 +246,8 @@ Required Permission: `pull-requests: write` #### exempt-issue-labels -The label(s) that can exempt to automatically mark as stale the issues. -It can be a comma separated list of labels (e.g: `question,bug`). +Comma separated list of labels that can be assigned to issues to exclude them from being marked as stale +(e.g: `question,bug`) If unset (or an empty string), this option will not alter the stale workflow. @@ -255,8 +255,8 @@ Default value: unset #### exempt-pr-labels -The label(s) that can exempt to automatically mark as stale the pull requests. -It can be a comma separated list of labels (e.g: `need-help,WIP`). +Comma separated list of labels that can be assigned to pull requests to exclude them from being marked as stale +(e.g: `need-help,WIP`) If unset (or an empty string), this option will not alter the stale workflow. diff --git a/__tests__/main.spec.ts b/__tests__/main.spec.ts index 21882547..6f752864 100644 --- a/__tests__/main.spec.ts +++ b/__tests__/main.spec.ts @@ -1094,44 +1094,6 @@ test('exempt pr labels will not be marked stale', async () => { expect(processor.staleIssues).toHaveLength(2); // PR should get processed even though it has an exempt **issue** label }); -test('exempt issue labels will not be marked stale and will remove the existing stale label', async () => { - expect.assertions(3); - const opts = {...DefaultProcessorOptions}; - opts.exemptIssueLabels = 'Exempt'; - const TestIssueList: Issue[] = [ - generateIssue( - opts, - 1, - 'My first issue', - '2020-01-01T17:00:00Z', - '2020-01-01T17:00:00Z', - false, - ['Exempt', 'Stale'] - ) - ]; - const processor = new IssuesProcessorMock( - opts, - async p => (p === 1 ? TestIssueList : []), - async () => [ - { - user: { - login: 'notme', - type: 'User' - }, - body: 'Body' - } - ], // return a fake comment to indicate there was an update - async () => 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(1); -}); - test('stale issues should not be closed if days is set to -1', async () => { const opts = {...DefaultProcessorOptions}; opts.daysBeforeClose = -1; diff --git a/dist/index.js b/dist/index.js index eb56dc8a..3c11fcc9 100644 --- a/dist/index.js +++ b/dist/index.js @@ -5,140 +5,140 @@ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Assignees = void 0; -const lodash_deburr_1 = __importDefault(__nccwpck_require__(1601)); -const option_1 = __nccwpck_require__(5931); -const words_to_list_1 = __nccwpck_require__(1883); -const issue_logger_1 = __nccwpck_require__(2984); -const logger_service_1 = __nccwpck_require__(1973); -class Assignees { - constructor(options, issue) { - this._options = options; - this._issue = issue; - this._issueLogger = new issue_logger_1.IssueLogger(issue); - } - static _cleanAssignee(assignee) { - return lodash_deburr_1.default(assignee.toLowerCase()); - } - shouldExemptAssignees() { - if (!this._issue.hasAssignees) { - this._issueLogger.info('This $$type has no assignee'); - this._logSkip(); - return false; - } - if (this._shouldExemptAllAssignees()) { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has an exempt assignee'); - return true; - } - const exemptAssignees = this._getExemptAssignees(); - if (exemptAssignees.length === 0) { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `No assignee option was specified to skip the stale process for this $$type`); - this._logSkip(); - return false; - } - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `Found ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length > 1 ? 's' : ''} that can exempt stale on this $$type`); - const hasExemptAssignee = exemptAssignees.some((exemptAssignee) => this._hasAssignee(exemptAssignee)); - if (!hasExemptAssignee) { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), 'No assignee on this $$type can exempt the stale process'); - this._logSkip(); - } - else { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has an exempt assignee'); - } - return hasExemptAssignee; - } - _getExemptAssignees() { - return this._issue.isPullRequest - ? this._getExemptPullRequestAssignees() - : this._getExemptIssueAssignees(); - } - _getExemptIssueAssignees() { - if (this._options.exemptIssueAssignees === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); - if (this._options.exemptAssignees === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); - return []; - } - const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptAssignees); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptAssignees; - } - const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptIssueAssignees); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptAssignees; - } - _getExemptPullRequestAssignees() { - if (this._options.exemptPrAssignees === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); - if (this._options.exemptAssignees === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); - return []; - } - const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptAssignees); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptAssignees; - } - const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptPrAssignees); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptAssignees; - } - _hasAssignee(assignee) { - const cleanAssignee = Assignees._cleanAssignee(assignee); - return this._issue.assignees.some((issueAssignee) => { - const isSameAssignee = cleanAssignee === Assignees._cleanAssignee(issueAssignee.login); - if (isSameAssignee) { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `@${issueAssignee.login} is assigned on this $$type and is an exempt assignee`); - } - return isSameAssignee; - }); - } - _shouldExemptAllAssignees() { - return this._issue.isPullRequest - ? this._shouldExemptAllPullRequestAssignees() - : this._shouldExemptAllIssueAssignees(); - } - _shouldExemptAllIssueAssignees() { - if (this._options.exemptAllIssueAssignees === true) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllIssueAssignees)} is disabled. Only some specific assignees on this $$type will skip the stale process`); - return false; - } - this._logExemptAllAssigneesOption(); - return this._options.exemptAllAssignees; - } - _shouldExemptAllPullRequestAssignees() { - if (this._options.exemptAllPrAssignees === true) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllPrAssignees)} is disabled. Only some specific assignees on this $$type will skip the stale process`); - return false; - } - this._logExemptAllAssigneesOption(); - return this._options.exemptAllAssignees; - } - _logExemptAllAssigneesOption() { - if (this._options.exemptAllAssignees) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllAssignees)} is enabled. Any assignee on this $$type will skip the stale process`); - } - else { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllAssignees)} is disabled. Only some specific assignees on this $$type will skip the stale process`); - } - } - _logSkip() { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skip the assignees checks'); - } -} -exports.Assignees = Assignees; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Assignees = void 0; +const lodash_deburr_1 = __importDefault(__nccwpck_require__(1601)); +const option_1 = __nccwpck_require__(5931); +const words_to_list_1 = __nccwpck_require__(1883); +const issue_logger_1 = __nccwpck_require__(2984); +const logger_service_1 = __nccwpck_require__(1973); +class Assignees { + constructor(options, issue) { + this._options = options; + this._issue = issue; + this._issueLogger = new issue_logger_1.IssueLogger(issue); + } + static _cleanAssignee(assignee) { + return lodash_deburr_1.default(assignee.toLowerCase()); + } + shouldExemptAssignees() { + if (!this._issue.hasAssignees) { + this._issueLogger.info('This $$type has no assignee'); + this._logSkip(); + return false; + } + if (this._shouldExemptAllAssignees()) { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has an exempt assignee'); + return true; + } + const exemptAssignees = this._getExemptAssignees(); + if (exemptAssignees.length === 0) { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `No assignee option was specified to skip the stale process for this $$type`); + this._logSkip(); + return false; + } + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `Found ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length > 1 ? 's' : ''} that can exempt stale on this $$type`); + const hasExemptAssignee = exemptAssignees.some((exemptAssignee) => this._hasAssignee(exemptAssignee)); + if (!hasExemptAssignee) { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), 'No assignee on this $$type can exempt the stale process'); + this._logSkip(); + } + else { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has an exempt assignee'); + } + return hasExemptAssignee; + } + _getExemptAssignees() { + return this._issue.isPullRequest + ? this._getExemptPullRequestAssignees() + : this._getExemptIssueAssignees(); + } + _getExemptIssueAssignees() { + if (this._options.exemptIssueAssignees === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); + if (this._options.exemptAssignees === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); + return []; + } + const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptAssignees); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptAssignees; + } + const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptIssueAssignees); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptAssignees; + } + _getExemptPullRequestAssignees() { + if (this._options.exemptPrAssignees === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); + if (this._options.exemptAssignees === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is disabled. No specific assignee can skip the stale process for this $$type`); + return []; + } + const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptAssignees); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptAssignees; + } + const exemptAssignees = words_to_list_1.wordsToList(this._options.exemptPrAssignees); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrAssignees)} is set. ${logger_service_1.LoggerService.cyan(exemptAssignees.length)} assignee${exemptAssignees.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptAssignees; + } + _hasAssignee(assignee) { + const cleanAssignee = Assignees._cleanAssignee(assignee); + return this._issue.assignees.some((issueAssignee) => { + const isSameAssignee = cleanAssignee === Assignees._cleanAssignee(issueAssignee.login); + if (isSameAssignee) { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `@${issueAssignee.login} is assigned on this $$type and is an exempt assignee`); + } + return isSameAssignee; + }); + } + _shouldExemptAllAssignees() { + return this._issue.isPullRequest + ? this._shouldExemptAllPullRequestAssignees() + : this._shouldExemptAllIssueAssignees(); + } + _shouldExemptAllIssueAssignees() { + if (this._options.exemptAllIssueAssignees === true) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllIssueAssignees)} is disabled. Only some specific assignees on this $$type will skip the stale process`); + return false; + } + this._logExemptAllAssigneesOption(); + return this._options.exemptAllAssignees; + } + _shouldExemptAllPullRequestAssignees() { + if (this._options.exemptAllPrAssignees === true) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllPrAssignees)} is disabled. Only some specific assignees on this $$type will skip the stale process`); + return false; + } + this._logExemptAllAssigneesOption(); + return this._options.exemptAllAssignees; + } + _logExemptAllAssigneesOption() { + if (this._options.exemptAllAssignees) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllAssignees)} is enabled. Any assignee on this $$type will skip the stale process`); + } + else { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllAssignees)} is disabled. Only some specific assignees on this $$type will skip the stale process`); + } + } + _logSkip() { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skip the assignees checks'); + } +} +exports.Assignees = Assignees; /***/ }), @@ -147,47 +147,47 @@ exports.Assignees = Assignees; /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.ExemptDraftPullRequest = void 0; -const option_1 = __nccwpck_require__(5931); -const logger_service_1 = __nccwpck_require__(1973); -const issue_logger_1 = __nccwpck_require__(2984); -class ExemptDraftPullRequest { - constructor(options, issue) { - this._options = options; - this._issue = issue; - this._issueLogger = new issue_logger_1.IssueLogger(issue); - } - shouldExemptDraftPullRequest(pullRequestCallback) { - return __awaiter(this, void 0, void 0, function* () { - if (this._issue.isPullRequest) { - if (this._options.exemptDraftPr) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptDraftPr)} is enabled`); - const pullRequest = yield pullRequestCallback(); - if ((pullRequest === null || pullRequest === void 0 ? void 0 : pullRequest.draft) === true) { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skip the $$type draft checks`); - return true; - } - else { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type because it is not a draft`); - } - } - } - return false; - }); - } -} -exports.ExemptDraftPullRequest = ExemptDraftPullRequest; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ExemptDraftPullRequest = void 0; +const option_1 = __nccwpck_require__(5931); +const logger_service_1 = __nccwpck_require__(1973); +const issue_logger_1 = __nccwpck_require__(2984); +class ExemptDraftPullRequest { + constructor(options, issue) { + this._options = options; + this._issue = issue; + this._issueLogger = new issue_logger_1.IssueLogger(issue); + } + shouldExemptDraftPullRequest(pullRequestCallback) { + return __awaiter(this, void 0, void 0, function* () { + if (this._issue.isPullRequest) { + if (this._options.exemptDraftPr) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptDraftPr)} is enabled`); + const pullRequest = yield pullRequestCallback(); + if ((pullRequest === null || pullRequest === void 0 ? void 0 : pullRequest.draft) === true) { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skip the $$type draft checks`); + return true; + } + else { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type because it is not a draft`); + } + } + } + return false; + }); + } +} +exports.ExemptDraftPullRequest = ExemptDraftPullRequest; /***/ }), @@ -196,59 +196,59 @@ exports.ExemptDraftPullRequest = ExemptDraftPullRequest; /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.IgnoreUpdates = void 0; -const option_1 = __nccwpck_require__(5931); -const issue_logger_1 = __nccwpck_require__(2984); -class IgnoreUpdates { - constructor(options, issue) { - this._options = options; - this._issue = issue; - this._issueLogger = new issue_logger_1.IssueLogger(issue); - } - shouldIgnoreUpdates() { - return this._shouldIgnoreUpdates(); - } - _shouldIgnoreUpdates() { - return this._issue.isPullRequest - ? this._shouldIgnorePullRequestUpdates() - : this._shouldIgnoreIssueUpdates(); - } - _shouldIgnorePullRequestUpdates() { - if (this._options.ignorePrUpdates === true) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.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; - } - _shouldIgnoreIssueUpdates() { - if (this._options.ignoreIssueUpdates === true) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.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; - } - _logIgnoreUpdates() { - if (this._options.ignoreUpdates) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.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`); - } - } -} -exports.IgnoreUpdates = IgnoreUpdates; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.IgnoreUpdates = void 0; +const option_1 = __nccwpck_require__(5931); +const issue_logger_1 = __nccwpck_require__(2984); +class IgnoreUpdates { + constructor(options, issue) { + this._options = options; + this._issue = issue; + this._issueLogger = new issue_logger_1.IssueLogger(issue); + } + shouldIgnoreUpdates() { + return this._shouldIgnoreUpdates(); + } + _shouldIgnoreUpdates() { + return this._issue.isPullRequest + ? this._shouldIgnorePullRequestUpdates() + : this._shouldIgnoreIssueUpdates(); + } + _shouldIgnorePullRequestUpdates() { + if (this._options.ignorePrUpdates === true) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.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; + } + _shouldIgnoreIssueUpdates() { + if (this._options.ignoreIssueUpdates === true) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.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; + } + _logIgnoreUpdates() { + if (this._options.ignoreUpdates) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.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`); + } + } +} +exports.IgnoreUpdates = IgnoreUpdates; /***/ }), @@ -257,55 +257,55 @@ exports.IgnoreUpdates = IgnoreUpdates; /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Issue = void 0; -const is_labeled_1 = __nccwpck_require__(6792); -const is_pull_request_1 = __nccwpck_require__(5400); -const operations_1 = __nccwpck_require__(7957); -class Issue { - constructor(options, issue) { - this.operations = new operations_1.Operations(); - this._options = options; - this.title = issue.title; - this.number = issue.number; - this.created_at = issue.created_at; - this.updated_at = issue.updated_at; - this.labels = mapLabels(issue.labels); - this.pull_request = issue.pull_request; - this.state = issue.state; - this.locked = issue.locked; - this.milestone = issue.milestone; - this.assignees = issue.assignees || []; - this.isStale = is_labeled_1.isLabeled(this, this.staleLabel); - this.markedStaleThisRun = false; - } - get isPullRequest() { - return is_pull_request_1.isPullRequest(this); - } - get staleLabel() { - return this._getStaleLabel(); - } - get hasAssignees() { - return this.assignees.length > 0; - } - _getStaleLabel() { - return this.isPullRequest - ? this._options.stalePrLabel - : this._options.staleIssueLabel; - } -} -exports.Issue = Issue; -function mapLabels(labels) { - return labels.map(label => { - if (typeof label == 'string') { - return { - name: label - }; - } - return label; - }); -} + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Issue = void 0; +const is_labeled_1 = __nccwpck_require__(6792); +const is_pull_request_1 = __nccwpck_require__(5400); +const operations_1 = __nccwpck_require__(7957); +class Issue { + constructor(options, issue) { + this.operations = new operations_1.Operations(); + this._options = options; + this.title = issue.title; + this.number = issue.number; + this.created_at = issue.created_at; + this.updated_at = issue.updated_at; + this.labels = mapLabels(issue.labels); + this.pull_request = issue.pull_request; + this.state = issue.state; + this.locked = issue.locked; + this.milestone = issue.milestone; + this.assignees = issue.assignees || []; + this.isStale = is_labeled_1.isLabeled(this, this.staleLabel); + this.markedStaleThisRun = false; + } + get isPullRequest() { + return is_pull_request_1.isPullRequest(this); + } + get staleLabel() { + return this._getStaleLabel(); + } + get hasAssignees() { + return this.assignees.length > 0; + } + _getStaleLabel() { + return this.isPullRequest + ? this._options.stalePrLabel + : this._options.staleIssueLabel; + } +} +exports.Issue = Issue; +function mapLabels(labels) { + return labels.map(label => { + if (typeof label == 'string') { + return { + name: label + }; + } + return label; + }); +} /***/ }), @@ -314,816 +314,813 @@ function mapLabels(labels) { /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.IssuesProcessor = void 0; -const core = __importStar(__nccwpck_require__(2186)); -const github_1 = __nccwpck_require__(5438); -const option_1 = __nccwpck_require__(5931); -const get_humanized_date_1 = __nccwpck_require__(965); -const is_date_more_recent_than_1 = __nccwpck_require__(1473); -const is_valid_date_1 = __nccwpck_require__(891); -const is_boolean_1 = __nccwpck_require__(8236); -const is_labeled_1 = __nccwpck_require__(6792); -const clean_label_1 = __nccwpck_require__(7752); -const should_mark_when_stale_1 = __nccwpck_require__(2461); -const words_to_list_1 = __nccwpck_require__(1883); -const assignees_1 = __nccwpck_require__(7236); -const ignore_updates_1 = __nccwpck_require__(2935); -const exempt_draft_pull_request_1 = __nccwpck_require__(854); -const issue_1 = __nccwpck_require__(4783); -const issue_logger_1 = __nccwpck_require__(2984); -const logger_1 = __nccwpck_require__(6212); -const milestones_1 = __nccwpck_require__(4601); -const stale_operations_1 = __nccwpck_require__(5080); -const statistics_1 = __nccwpck_require__(3334); -const logger_service_1 = __nccwpck_require__(1973); -/*** - * Handle processing of issues for staleness/closure. - */ -class IssuesProcessor { - constructor(options) { - this.staleIssues = []; - this.closedIssues = []; - this.deletedBranchIssues = []; - this.removedLabelIssues = []; - this.addedLabelIssues = []; - this.addedCloseCommentIssues = []; - this._logger = new logger_1.Logger(); - this.options = options; - this.client = github_1.getOctokit(this.options.repoToken); - this.operations = new stale_operations_1.StaleOperations(this.options); - this._logger.info(logger_service_1.LoggerService.yellow(`Starting the stale action process...`)); - if (this.options.debugOnly) { - this._logger.warning(logger_service_1.LoggerService.yellowBright(`Executing in debug mode!`)); - this._logger.warning(logger_service_1.LoggerService.yellowBright(`The debug output will be written but no issues/PRs will be processed.`)); - } - if (this.options.enableStatistics) { - this.statistics = new statistics_1.Statistics(); - } - } - static _updatedSince(timestamp, num_days) { - const daysInMillis = 1000 * 60 * 60 * 24 * num_days; - const millisSinceLastUpdated = new Date().getTime() - new Date(timestamp).getTime(); - return millisSinceLastUpdated <= daysInMillis; - } - static _endIssueProcessing(issue) { - const consumedOperationsCount = issue.operations.getConsumedOperationsCount(); - if (consumedOperationsCount > 0) { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(logger_service_1.LoggerService.cyan(consumedOperationsCount), `operation${consumedOperationsCount > 1 ? 's' : ''} consumed for this $$type`); - } - } - static _getCloseLabelUsedOptionName(issue) { - return issue.isPullRequest ? option_1.Option.ClosePrLabel : option_1.Option.CloseIssueLabel; - } - processIssues(page = 1) { - var _a, _b; - return __awaiter(this, void 0, void 0, function* () { - // get the next batch of issues - const issues = yield this.getIssues(page); - if (issues.length <= 0) { - this._logger.info(logger_service_1.LoggerService.green(`No more issues found to process. Exiting...`)); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.setOperationsCount(this.operations.getConsumedOperationsCount()).logStats(); - return this.operations.getRemainingOperationsCount(); - } - else { - this._logger.info(`${logger_service_1.LoggerService.yellow('Processing the batch of issues ')} ${logger_service_1.LoggerService.cyan(`#${page}`)} ${logger_service_1.LoggerService.yellow(' containing ')} ${logger_service_1.LoggerService.cyan(issues.length)} ${logger_service_1.LoggerService.yellow(` issue${issues.length > 1 ? 's' : ''}...`)}`); - } - const labelsToAddWhenUnstale = words_to_list_1.wordsToList(this.options.labelsToAddWhenUnstale); - const labelsToRemoveWhenUnstale = words_to_list_1.wordsToList(this.options.labelsToRemoveWhenUnstale); - for (const issue of issues.values()) { - // Stop the processing if no more operations remains - if (!this.operations.hasRemainingOperations()) { - break; - } - const issueLogger = new issue_logger_1.IssueLogger(issue); - yield issueLogger.grouping(`$$type #${issue.number}`, () => __awaiter(this, void 0, void 0, function* () { - yield this.processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale); - })); - } - if (!this.operations.hasRemainingOperations()) { - this._logger.warning(logger_service_1.LoggerService.yellowBright(`No more operations left! Exiting...`)); - this._logger.warning(`${logger_service_1.LoggerService.yellowBright('If you think that not enough issues were processed you could try to increase the quantity related to the ')} ${this._logger.createOptionLink(option_1.Option.OperationsPerRun)} ${logger_service_1.LoggerService.yellowBright(' option which is currently set to ')} ${logger_service_1.LoggerService.cyan(this.options.operationsPerRun)}`); - (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.setOperationsCount(this.operations.getConsumedOperationsCount()).logStats(); - return 0; - } - this._logger.info(`${logger_service_1.LoggerService.green('Batch ')} ${logger_service_1.LoggerService.cyan(`#${page}`)} ${logger_service_1.LoggerService.green(' processed.')}`); - // Do the next batch - return this.processIssues(page + 1); - }); - } - processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementProcessedItemsCount(issue); - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Found this $$type last updated at: ${logger_service_1.LoggerService.cyan(issue.updated_at)}`); - // calculate string based messages for this issue - const staleMessage = issue.isPullRequest - ? this.options.stalePrMessage - : this.options.staleIssueMessage; - const closeMessage = issue.isPullRequest - ? this.options.closePrMessage - : this.options.closeIssueMessage; - const staleLabel = issue.isPullRequest - ? this.options.stalePrLabel - : this.options.staleIssueLabel; - const closeLabel = issue.isPullRequest - ? this.options.closePrLabel - : this.options.closeIssueLabel; - const skipMessage = issue.isPullRequest - ? this.options.stalePrMessage.length === 0 - : this.options.staleIssueMessage.length === 0; - const daysBeforeStale = issue.isPullRequest - ? this._getDaysBeforePrStale() - : this._getDaysBeforeIssueStale(); - if (issue.state === 'closed') { - issueLogger.info(`Skipping this $$type because it is closed`); - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process closed issues - } - if (issue.locked) { - issueLogger.info(`Skipping this $$type because it is locked`); - IssuesProcessor._endIssueProcessing(issue); - 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)); - 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)})`); - const hasAllWhitelistedLabels = onlyLabels.every((label) => { - return is_labeled_1.isLabeled(issue, label); - }); - if (!hasAllWhitelistedLabels) { - issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skipping this $$type because it doesn't have all the required labels`); - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process issues without all of the required labels - } - else { - issueLogger.info(logger_service_1.LoggerService.white('├──'), `All the required labels are present on this $$type`); - issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); - } - } - else { - issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.OnlyLabels)} was not specified`); - issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); - } - issueLogger.info(`Days before $$type stale: ${logger_service_1.LoggerService.cyan(daysBeforeStale)}`); - const shouldMarkAsStale = should_mark_when_stale_1.shouldMarkWhenStale(daysBeforeStale); - // Try to remove the close label when not close/locked issue or PR - yield this._removeCloseLabel(issue, closeLabel); - if (this.options.startDate) { - const startDate = new Date(this.options.startDate); - const createdAt = new Date(issue.created_at); - issueLogger.info(`A start date was specified for the ${get_humanized_date_1.getHumanizedDate(startDate)} (${logger_service_1.LoggerService.cyan(this.options.startDate)})`); - // Expecting that GitHub will always set a creation date on the issues and PRs - // But you never know! - if (!is_valid_date_1.isValidDate(createdAt)) { - IssuesProcessor._endIssueProcessing(issue); - core.setFailed(new Error(`Invalid issue field: "created_at". Expected a valid date`)); - } - issueLogger.info(`$$type created the ${get_humanized_date_1.getHumanizedDate(createdAt)} (${logger_service_1.LoggerService.cyan(issue.created_at)})`); - if (!is_date_more_recent_than_1.isDateMoreRecentThan(createdAt, startDate)) { - issueLogger.info(`Skipping this $$type because it was created before the specified start date`); - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process issues which were created before the start date - } - } - if (issue.isStale) { - issueLogger.info(`This $$type has a stale label`); - } - else { - issueLogger.info(`This $$type hasn't a stale label`); - } - const exemptLabels = words_to_list_1.wordsToList(issue.isPullRequest - ? this.options.exemptPrLabels - : this.options.exemptIssueLabels); - if (exemptLabels.some((exemptLabel) => is_labeled_1.isLabeled(issue, exemptLabel))) { - if (issue.isStale) { - issueLogger.info(`An exempt label was added after the stale label.`); - yield this._removeStaleLabel(issue, staleLabel); - } - issueLogger.info(`Skipping this $$type because it has an exempt label`); - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process exempt issues - } - const anyOfLabels = words_to_list_1.wordsToList(this._getAnyOfLabels(issue)); - if (anyOfLabels.length > 0) { - issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.AnyOfLabels)} was specified to only process the issues and pull requests with one of those labels (${logger_service_1.LoggerService.cyan(anyOfLabels.length)})`); - const hasOneOfWhitelistedLabels = anyOfLabels.some((label) => { - return is_labeled_1.isLabeled(issue, label); - }); - if (!hasOneOfWhitelistedLabels) { - issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skipping this $$type because it doesn't have one of the required labels`); - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process issues without any of the required labels - } - else { - issueLogger.info(logger_service_1.LoggerService.white('├──'), `One of the required labels is present on this $$type`); - issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); - } - } - else { - issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.AnyOfLabels)} was not specified`); - issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); - } - const milestones = new milestones_1.Milestones(this.options, issue); - if (milestones.shouldExemptMilestones()) { - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process exempt milestones - } - const assignees = new assignees_1.Assignees(this.options, issue); - if (assignees.shouldExemptAssignees()) { - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process exempt assignees - } - // Ignore draft PR - // Note that this check is so far below because it cost one read operation - // So it's simply better to do all the stale checks which don't cost more operation before this one - const exemptDraftPullRequest = new exempt_draft_pull_request_1.ExemptDraftPullRequest(this.options, issue); - if (yield exemptDraftPullRequest.shouldExemptDraftPullRequest(() => __awaiter(this, void 0, void 0, function* () { - return this.getPullRequest(issue); - }))) { - IssuesProcessor._endIssueProcessing(issue); - return; // Don't process draft PR - } - // Determine if this issue needs to be marked stale first - if (!issue.isStale) { - issueLogger.info(`This $$type is not stale`); - const shouldIgnoreUpdates = new ignore_updates_1.IgnoreUpdates(this.options, issue).shouldIgnoreUpdates(); - // Should this issue be marked as stale? - let shouldBeStale; - // Ignore the last update and only use the creation date - if (shouldIgnoreUpdates) { - shouldBeStale = !IssuesProcessor._updatedSince(issue.created_at, daysBeforeStale); - } - // Use the last update to check if we need to stale - else { - shouldBeStale = !IssuesProcessor._updatedSince(issue.updated_at, daysBeforeStale); - } - if (shouldBeStale) { - if (shouldIgnoreUpdates) { - issueLogger.info(`This $$type should be stale based on the creation date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`); - } - else { - issueLogger.info(`This $$type should be stale based on the last update date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`); - } - if (shouldMarkAsStale) { - issueLogger.info(`This $$type should be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`); - yield this._markStale(issue, staleMessage, staleLabel, skipMessage); - issue.isStale = true; // This issue is now considered stale - issue.markedStaleThisRun = true; - issueLogger.info(`This $$type is now stale`); - } - else { - issueLogger.info(`This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`); - } - } - else { - if (shouldIgnoreUpdates) { - issueLogger.info(`This $$type should not be stale based on the creation date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`); - } - else { - issueLogger.info(`This $$type should not be stale based on the last update date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`); - } - } - } - // Process the issue if it was marked stale - if (issue.isStale) { - issueLogger.info(`This $$type is already stale`); - yield this._processStaleIssue(issue, staleLabel, staleMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, closeMessage, closeLabel); - } - IssuesProcessor._endIssueProcessing(issue); - }); - } - // Grab comments for an issue since a given date - listIssueComments(issue, sinceDate) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - // Find any comments since date on the given issue - try { - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsCommentsCount(); - const comments = yield this.client.rest.issues.listComments({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - since: sinceDate - }); - return comments.data; - } - catch (error) { - this._logger.error(`List issue comments error: ${error.message}`); - return Promise.resolve([]); - } - }); - } - // grab issues from github in batches of 100 - getIssues(page) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - try { - this.operations.consumeOperation(); - const issueResult = yield this.client.rest.issues.listForRepo({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - state: 'open', - per_page: 100, - direction: this.options.ascending ? 'asc' : 'desc', - page - }); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsCount(issueResult.data.length); - return issueResult.data.map((issue) => new issue_1.Issue(this.options, issue)); - } - catch (error) { - this._logger.error(`Get issues for repo error: ${error.message}`); - return Promise.resolve([]); - } - }); - } - // returns the creation date of a given label on an issue (or nothing if no label existed) - ///see https://developer.github.com/v3/activity/events/ - getLabelCreationDate(issue, label) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Checking for label on this $$type`); - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsEventsCount(); - const options = this.client.rest.issues.listEvents.endpoint.merge({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - per_page: 100, - issue_number: issue.number - }); - const events = yield this.client.paginate(options); - const reversedEvents = events.reverse(); - const staleLabeledEvent = reversedEvents.find(event => event.event === 'labeled' && - clean_label_1.cleanLabel(event.label.name) === clean_label_1.cleanLabel(label)); - if (!staleLabeledEvent) { - // Must be old rather than labeled - return undefined; - } - return staleLabeledEvent.created_at; - }); - } - getPullRequest(issue) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - try { - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedPullRequestsCount(); - const pullRequest = yield this.client.rest.pulls.get({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - pull_number: issue.number - }); - return pullRequest.data; - } - catch (error) { - issueLogger.error(`Error when getting this $$type: ${error.message}`); - } - }); - } - // handle all of the stale issue logic when we find a stale issue - _processStaleIssue(issue, staleLabel, staleMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, closeMessage, closeLabel) { - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - const markedStaleOn = (yield this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at; - issueLogger.info(`$$type marked stale on: ${logger_service_1.LoggerService.cyan(markedStaleOn)}`); - const issueHasCommentsSinceStale = yield this._hasCommentsSince(issue, markedStaleOn, staleMessage); - issueLogger.info(`$$type has been commented on: ${logger_service_1.LoggerService.cyan(issueHasCommentsSinceStale)}`); - const daysBeforeClose = issue.isPullRequest - ? this._getDaysBeforePrClose() - : this._getDaysBeforeIssueClose(); - issueLogger.info(`Days before $$type close: ${logger_service_1.LoggerService.cyan(daysBeforeClose)}`); - const shouldRemoveStaleWhenUpdated = this._shouldRemoveStaleWhenUpdated(issue); - issueLogger.info(`The option ${issueLogger.createOptionLink(this._getRemoveStaleWhenUpdatedUsedOptionName(issue))} is: ${logger_service_1.LoggerService.cyan(shouldRemoveStaleWhenUpdated)}`); - if (shouldRemoveStaleWhenUpdated) { - issueLogger.info(`The stale label should not be removed`); - } - else { - issueLogger.info(`The stale label should be removed if all conditions met`); - } - if (issue.markedStaleThisRun) { - issueLogger.info(`marked stale this run, so don't check for updates`); - } - // The issue.updated_at and markedStaleOn are not always exactly in sync (they can be off by a second or 2) - // isDateMoreRecentThan makes sure they are not the same date within a certain tolerance (15 seconds in this case) - const issueHasUpdateSinceStale = is_date_more_recent_than_1.isDateMoreRecentThan(new Date(issue.updated_at), new Date(markedStaleOn), 15); - issueLogger.info(`$$type has been updated since it was marked stale: ${logger_service_1.LoggerService.cyan(issueHasUpdateSinceStale)}`); - // Should we un-stale this issue? - if (shouldRemoveStaleWhenUpdated && - (issueHasUpdateSinceStale || issueHasCommentsSinceStale) && - !issue.markedStaleThisRun) { - issueLogger.info(`Remove the stale label since the $$type has been updated and the workflow should remove the stale label when updated`); - yield this._removeStaleLabel(issue, staleLabel); - // Are there labels to remove or add when an issue is no longer stale? - yield this._removeLabelsWhenUnstale(issue, labelsToRemoveWhenUnstale); - yield this._addLabelsWhenUnstale(issue, labelsToAddWhenUnstale); - issueLogger.info(`Skipping the process since the $$type is now un-stale`); - return; // Nothing to do because it is no longer stale - } - // Now start closing logic - if (daysBeforeClose < 0) { - return; // Nothing to do because we aren't closing stale issues - } - const issueHasUpdateInCloseWindow = IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose); - issueLogger.info(`$$type has been updated in the last ${daysBeforeClose} days: ${logger_service_1.LoggerService.cyan(issueHasUpdateInCloseWindow)}`); - if (!issueHasCommentsSinceStale && !issueHasUpdateInCloseWindow) { - issueLogger.info(`Closing $$type because it was last updated on: ${logger_service_1.LoggerService.cyan(issue.updated_at)}`); - yield this._closeIssue(issue, closeMessage, closeLabel); - if (this.options.deleteBranch && issue.pull_request) { - issueLogger.info(`Deleting the branch since the option ${issueLogger.createOptionLink(option_1.Option.DeleteBranch)} is enabled`); - yield this._deleteBranch(issue); - this.deletedBranchIssues.push(issue); - } - } - else { - issueLogger.info(`Stale $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceStale}, hasUpdate? ${issueHasUpdateInCloseWindow})`); - } - }); - } - // checks to see if a given issue is still stale (has had activity on it) - _hasCommentsSince(issue, sinceDate, staleMessage) { - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Checking for comments on $$type since: ${logger_service_1.LoggerService.cyan(sinceDate)}`); - if (!sinceDate) { - return true; - } - // find any comments since the date - const comments = yield this.listIssueComments(issue, sinceDate); - const filteredComments = comments.filter(comment => { - var _a, _b; - return ((_a = comment.user) === null || _a === void 0 ? void 0 : _a.type) === 'User' && - ((_b = comment.body) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== staleMessage.toLowerCase(); - }); - issueLogger.info(`Comments that are not the stale comment or another bot: ${logger_service_1.LoggerService.cyan(filteredComments.length)}`); - // if there are any user comments returned - return filteredComments.length > 0; - }); - } - // Mark an issue as stale with a comment and a label - _markStale(issue, staleMessage, staleLabel, skipMessage) { - var _a, _b, _c; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Marking this $$type as stale`); - this.staleIssues.push(issue); - // if the issue is being marked stale, the updated date should be changed to right now - // so that close calculations work correctly - const newUpdatedAtDate = new Date(); - issue.updated_at = newUpdatedAtDate.toString(); - if (!skipMessage) { - try { - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsComment(issue); - if (!this.options.debugOnly) { - yield this.client.rest.issues.createComment({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - body: staleMessage - }); - } - } - catch (error) { - issueLogger.error(`Error when creating a comment: ${error.message}`); - } - } - try { - this._consumeIssueOperation(issue); - (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.incrementAddedItemsLabel(issue); - (_c = this.statistics) === null || _c === void 0 ? void 0 : _c.incrementStaleItemsCount(issue); - if (!this.options.debugOnly) { - yield this.client.rest.issues.addLabels({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - labels: [staleLabel] - }); - } - } - catch (error) { - issueLogger.error(`Error when adding a label: ${error.message}`); - } - }); - } - // Close an issue based on staleness - _closeIssue(issue, closeMessage, closeLabel) { - var _a, _b, _c; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Closing $$type for being stale`); - this.closedIssues.push(issue); - if (closeMessage) { - try { - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsComment(issue); - this.addedCloseCommentIssues.push(issue); - if (!this.options.debugOnly) { - yield this.client.rest.issues.createComment({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - body: closeMessage - }); - } - } - catch (error) { - issueLogger.error(`Error when creating a comment: ${error.message}`); - } - } - if (closeLabel) { - try { - this._consumeIssueOperation(issue); - (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.incrementAddedItemsLabel(issue); - if (!this.options.debugOnly) { - yield this.client.rest.issues.addLabels({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - labels: [closeLabel] - }); - } - } - catch (error) { - issueLogger.error(`Error when adding a label: ${error.message}`); - } - } - try { - this._consumeIssueOperation(issue); - (_c = this.statistics) === null || _c === void 0 ? void 0 : _c.incrementClosedItemsCount(issue); - if (!this.options.debugOnly) { - yield this.client.rest.issues.update({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - state: 'closed', - state_reason: this.options.closeIssueReason || undefined - }); - } - } - catch (error) { - issueLogger.error(`Error when updating this $$type: ${error.message}`); - } - }); - } - // Delete the branch on closed pull request - _deleteBranch(issue) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Delete - branch from closed $ - $type - - - ${issue.title}`); - const pullRequest = yield this.getPullRequest(issue); - if (!pullRequest) { - issueLogger.info(`Not deleting this branch as no pull request was found for this $$type`); - return; - } - const branch = pullRequest.head.ref; - issueLogger.info(`Deleting the branch "${logger_service_1.LoggerService.cyan(branch)}" from closed $$type`); - try { - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedBranchesCount(); - if (!this.options.debugOnly) { - yield this.client.rest.git.deleteRef({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - ref: `heads/${branch}` - }); - } - } - catch (error) { - issueLogger.error(`Error when deleting the branch "${logger_service_1.LoggerService.cyan(branch)}" from $$type: ${error.message}`); - } - }); - } - // Remove a label from an issue or a pull request - _removeLabel(issue, label, isSubStep = false) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`${isSubStep ? logger_service_1.LoggerService.white('├── ') : ''}Removing the label "${logger_service_1.LoggerService.cyan(label)}" from this $$type...`); - this.removedLabelIssues.push(issue); - try { - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedItemsLabelsCount(issue); - if (!this.options.debugOnly) { - yield this.client.rest.issues.removeLabel({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - name: label - }); - } - issueLogger.info(`${isSubStep ? logger_service_1.LoggerService.white('└── ') : ''}The label "${logger_service_1.LoggerService.cyan(label)}" was removed`); - } - catch (error) { - issueLogger.error(`${isSubStep ? logger_service_1.LoggerService.white('└── ') : ''}Error when removing the label: "${logger_service_1.LoggerService.cyan(error.message)}"`); - } - }); - } - _getDaysBeforeIssueStale() { - return isNaN(this.options.daysBeforeIssueStale) - ? this.options.daysBeforeStale - : this.options.daysBeforeIssueStale; - } - _getDaysBeforePrStale() { - return isNaN(this.options.daysBeforePrStale) - ? this.options.daysBeforeStale - : this.options.daysBeforePrStale; - } - _getDaysBeforeIssueClose() { - return isNaN(this.options.daysBeforeIssueClose) - ? this.options.daysBeforeClose - : this.options.daysBeforeIssueClose; - } - _getDaysBeforePrClose() { - return isNaN(this.options.daysBeforePrClose) - ? this.options.daysBeforeClose - : this.options.daysBeforePrClose; - } - _getOnlyLabels(issue) { - if (issue.isPullRequest) { - if (this.options.onlyPrLabels !== '') { - return this.options.onlyPrLabels; - } - } - else { - if (this.options.onlyIssueLabels !== '') { - return this.options.onlyIssueLabels; - } - } - return this.options.onlyLabels; - } - _isIncludeOnlyAssigned(issue) { - return this.options.includeOnlyAssigned && !issue.hasAssignees; - } - _getAnyOfLabels(issue) { - if (issue.isPullRequest) { - if (this.options.anyOfPrLabels !== '') { - return this.options.anyOfPrLabels; - } - } - else { - if (this.options.anyOfIssueLabels !== '') { - return this.options.anyOfIssueLabels; - } - } - return this.options.anyOfLabels; - } - _shouldRemoveStaleWhenUpdated(issue) { - if (issue.isPullRequest) { - if (is_boolean_1.isBoolean(this.options.removePrStaleWhenUpdated)) { - return this.options.removePrStaleWhenUpdated; - } - return this.options.removeStaleWhenUpdated; - } - if (is_boolean_1.isBoolean(this.options.removeIssueStaleWhenUpdated)) { - return this.options.removeIssueStaleWhenUpdated; - } - return this.options.removeStaleWhenUpdated; - } - _removeLabelsWhenUnstale(issue, removeLabels) { - return __awaiter(this, void 0, void 0, function* () { - if (!removeLabels.length) { - return; - } - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Removing all the labels specified via the ${this._logger.createOptionLink(option_1.Option.LabelsToRemoveWhenUnstale)} option.`); - for (const label of removeLabels.values()) { - yield this._removeLabel(issue, label); - } - }); - } - _addLabelsWhenUnstale(issue, labelsToAdd) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - if (!labelsToAdd.length) { - return; - } - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Adding all the labels specified via the ${this._logger.createOptionLink(option_1.Option.LabelsToAddWhenUnstale)} option.`); - this.addedLabelIssues.push(issue); - try { - this._consumeIssueOperation(issue); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsLabel(issue); - if (!this.options.debugOnly) { - yield this.client.rest.issues.addLabels({ - owner: github_1.context.repo.owner, - repo: github_1.context.repo.repo, - issue_number: issue.number, - labels: labelsToAdd - }); - } - } - catch (error) { - this._logger.error(`Error when adding labels after updated from stale: ${error.message}`); - } - }); - } - _removeStaleLabel(issue, staleLabel) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`The $$type is no longer stale. Removing the stale label...`); - yield this._removeLabel(issue, staleLabel); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementUndoStaleItemsCount(issue); - }); - } - _removeCloseLabel(issue, closeLabel) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`The $$type is not closed nor locked. Trying to remove the close label...`); - if (!closeLabel) { - issueLogger.info(logger_service_1.LoggerService.white('├──'), `The ${issueLogger.createOptionLink(IssuesProcessor._getCloseLabelUsedOptionName(issue))} option was not set`); - issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skipping the removal of the close label`); - return Promise.resolve(); - } - if (is_labeled_1.isLabeled(issue, closeLabel)) { - issueLogger.info(logger_service_1.LoggerService.white('├──'), `The $$type has a close label "${logger_service_1.LoggerService.cyan(closeLabel)}". Removing the close label...`); - yield this._removeLabel(issue, closeLabel, true); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedCloseItemsLabelsCount(issue); - } - else { - issueLogger.info(logger_service_1.LoggerService.white('└──'), `There is no close label on this $$type. Skipping`); - return Promise.resolve(); - } - }); - } - _consumeIssueOperation(issue) { - this.operations.consumeOperation(); - issue.operations.consumeOperation(); - } - _getDaysBeforeStaleUsedOptionName(issue) { - return issue.isPullRequest - ? this._getDaysBeforePrStaleUsedOptionName() - : this._getDaysBeforeIssueStaleUsedOptionName(); - } - _getDaysBeforeIssueStaleUsedOptionName() { - return isNaN(this.options.daysBeforeIssueStale) - ? option_1.Option.DaysBeforeStale - : option_1.Option.DaysBeforeIssueStale; - } - _getDaysBeforePrStaleUsedOptionName() { - return isNaN(this.options.daysBeforePrStale) - ? option_1.Option.DaysBeforeStale - : option_1.Option.DaysBeforePrStale; - } - _getRemoveStaleWhenUpdatedUsedOptionName(issue) { - if (issue.isPullRequest) { - if (is_boolean_1.isBoolean(this.options.removePrStaleWhenUpdated)) { - return option_1.Option.RemovePrStaleWhenUpdated; - } - return option_1.Option.RemoveStaleWhenUpdated; - } - if (is_boolean_1.isBoolean(this.options.removeIssueStaleWhenUpdated)) { - return option_1.Option.RemoveIssueStaleWhenUpdated; - } - return option_1.Option.RemoveStaleWhenUpdated; - } -} -exports.IssuesProcessor = IssuesProcessor; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.IssuesProcessor = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const github_1 = __nccwpck_require__(5438); +const option_1 = __nccwpck_require__(5931); +const get_humanized_date_1 = __nccwpck_require__(965); +const is_date_more_recent_than_1 = __nccwpck_require__(1473); +const is_valid_date_1 = __nccwpck_require__(891); +const is_boolean_1 = __nccwpck_require__(8236); +const is_labeled_1 = __nccwpck_require__(6792); +const clean_label_1 = __nccwpck_require__(7752); +const should_mark_when_stale_1 = __nccwpck_require__(2461); +const words_to_list_1 = __nccwpck_require__(1883); +const assignees_1 = __nccwpck_require__(7236); +const ignore_updates_1 = __nccwpck_require__(2935); +const exempt_draft_pull_request_1 = __nccwpck_require__(854); +const issue_1 = __nccwpck_require__(4783); +const issue_logger_1 = __nccwpck_require__(2984); +const logger_1 = __nccwpck_require__(6212); +const milestones_1 = __nccwpck_require__(4601); +const stale_operations_1 = __nccwpck_require__(5080); +const statistics_1 = __nccwpck_require__(3334); +const logger_service_1 = __nccwpck_require__(1973); +/*** + * Handle processing of issues for staleness/closure. + */ +class IssuesProcessor { + constructor(options) { + this.staleIssues = []; + this.closedIssues = []; + this.deletedBranchIssues = []; + this.removedLabelIssues = []; + this.addedLabelIssues = []; + this.addedCloseCommentIssues = []; + this._logger = new logger_1.Logger(); + this.options = options; + this.client = github_1.getOctokit(this.options.repoToken); + this.operations = new stale_operations_1.StaleOperations(this.options); + this._logger.info(logger_service_1.LoggerService.yellow(`Starting the stale action process...`)); + if (this.options.debugOnly) { + this._logger.warning(logger_service_1.LoggerService.yellowBright(`Executing in debug mode!`)); + this._logger.warning(logger_service_1.LoggerService.yellowBright(`The debug output will be written but no issues/PRs will be processed.`)); + } + if (this.options.enableStatistics) { + this.statistics = new statistics_1.Statistics(); + } + } + static _updatedSince(timestamp, num_days) { + const daysInMillis = 1000 * 60 * 60 * 24 * num_days; + const millisSinceLastUpdated = new Date().getTime() - new Date(timestamp).getTime(); + return millisSinceLastUpdated <= daysInMillis; + } + static _endIssueProcessing(issue) { + const consumedOperationsCount = issue.operations.getConsumedOperationsCount(); + if (consumedOperationsCount > 0) { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(logger_service_1.LoggerService.cyan(consumedOperationsCount), `operation${consumedOperationsCount > 1 ? 's' : ''} consumed for this $$type`); + } + } + static _getCloseLabelUsedOptionName(issue) { + return issue.isPullRequest ? option_1.Option.ClosePrLabel : option_1.Option.CloseIssueLabel; + } + processIssues(page = 1) { + var _a, _b; + return __awaiter(this, void 0, void 0, function* () { + // get the next batch of issues + const issues = yield this.getIssues(page); + if (issues.length <= 0) { + this._logger.info(logger_service_1.LoggerService.green(`No more issues found to process. Exiting...`)); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.setOperationsCount(this.operations.getConsumedOperationsCount()).logStats(); + return this.operations.getRemainingOperationsCount(); + } + else { + this._logger.info(`${logger_service_1.LoggerService.yellow('Processing the batch of issues ')} ${logger_service_1.LoggerService.cyan(`#${page}`)} ${logger_service_1.LoggerService.yellow(' containing ')} ${logger_service_1.LoggerService.cyan(issues.length)} ${logger_service_1.LoggerService.yellow(` issue${issues.length > 1 ? 's' : ''}...`)}`); + } + const labelsToAddWhenUnstale = words_to_list_1.wordsToList(this.options.labelsToAddWhenUnstale); + const labelsToRemoveWhenUnstale = words_to_list_1.wordsToList(this.options.labelsToRemoveWhenUnstale); + for (const issue of issues.values()) { + // Stop the processing if no more operations remains + if (!this.operations.hasRemainingOperations()) { + break; + } + const issueLogger = new issue_logger_1.IssueLogger(issue); + yield issueLogger.grouping(`$$type #${issue.number}`, () => __awaiter(this, void 0, void 0, function* () { + yield this.processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale); + })); + } + if (!this.operations.hasRemainingOperations()) { + this._logger.warning(logger_service_1.LoggerService.yellowBright(`No more operations left! Exiting...`)); + this._logger.warning(`${logger_service_1.LoggerService.yellowBright('If you think that not enough issues were processed you could try to increase the quantity related to the ')} ${this._logger.createOptionLink(option_1.Option.OperationsPerRun)} ${logger_service_1.LoggerService.yellowBright(' option which is currently set to ')} ${logger_service_1.LoggerService.cyan(this.options.operationsPerRun)}`); + (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.setOperationsCount(this.operations.getConsumedOperationsCount()).logStats(); + return 0; + } + this._logger.info(`${logger_service_1.LoggerService.green('Batch ')} ${logger_service_1.LoggerService.cyan(`#${page}`)} ${logger_service_1.LoggerService.green(' processed.')}`); + // Do the next batch + return this.processIssues(page + 1); + }); + } + processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementProcessedItemsCount(issue); + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Found this $$type last updated at: ${logger_service_1.LoggerService.cyan(issue.updated_at)}`); + // calculate string based messages for this issue + const staleMessage = issue.isPullRequest + ? this.options.stalePrMessage + : this.options.staleIssueMessage; + const closeMessage = issue.isPullRequest + ? this.options.closePrMessage + : this.options.closeIssueMessage; + const staleLabel = issue.isPullRequest + ? this.options.stalePrLabel + : this.options.staleIssueLabel; + const closeLabel = issue.isPullRequest + ? this.options.closePrLabel + : this.options.closeIssueLabel; + const skipMessage = issue.isPullRequest + ? this.options.stalePrMessage.length === 0 + : this.options.staleIssueMessage.length === 0; + const daysBeforeStale = issue.isPullRequest + ? this._getDaysBeforePrStale() + : this._getDaysBeforeIssueStale(); + if (issue.state === 'closed') { + issueLogger.info(`Skipping this $$type because it is closed`); + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process closed issues + } + if (issue.locked) { + issueLogger.info(`Skipping this $$type because it is locked`); + IssuesProcessor._endIssueProcessing(issue); + 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)); + 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)})`); + const hasAllWhitelistedLabels = onlyLabels.every((label) => { + return is_labeled_1.isLabeled(issue, label); + }); + if (!hasAllWhitelistedLabels) { + issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skipping this $$type because it doesn't have all the required labels`); + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process issues without all of the required labels + } + else { + issueLogger.info(logger_service_1.LoggerService.white('├──'), `All the required labels are present on this $$type`); + issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); + } + } + else { + issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.OnlyLabels)} was not specified`); + issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); + } + issueLogger.info(`Days before $$type stale: ${logger_service_1.LoggerService.cyan(daysBeforeStale)}`); + const shouldMarkAsStale = should_mark_when_stale_1.shouldMarkWhenStale(daysBeforeStale); + // Try to remove the close label when not close/locked issue or PR + yield this._removeCloseLabel(issue, closeLabel); + if (this.options.startDate) { + const startDate = new Date(this.options.startDate); + const createdAt = new Date(issue.created_at); + issueLogger.info(`A start date was specified for the ${get_humanized_date_1.getHumanizedDate(startDate)} (${logger_service_1.LoggerService.cyan(this.options.startDate)})`); + // Expecting that GitHub will always set a creation date on the issues and PRs + // But you never know! + if (!is_valid_date_1.isValidDate(createdAt)) { + IssuesProcessor._endIssueProcessing(issue); + core.setFailed(new Error(`Invalid issue field: "created_at". Expected a valid date`)); + } + issueLogger.info(`$$type created the ${get_humanized_date_1.getHumanizedDate(createdAt)} (${logger_service_1.LoggerService.cyan(issue.created_at)})`); + if (!is_date_more_recent_than_1.isDateMoreRecentThan(createdAt, startDate)) { + issueLogger.info(`Skipping this $$type because it was created before the specified start date`); + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process issues which were created before the start date + } + } + if (issue.isStale) { + issueLogger.info(`This $$type includes a stale label`); + } + else { + issueLogger.info(`This $$type does not include a stale label`); + } + const exemptLabels = words_to_list_1.wordsToList(issue.isPullRequest + ? this.options.exemptPrLabels + : this.options.exemptIssueLabels); + const hasExemptLabel = exemptLabels.some((exemptLabel) => is_labeled_1.isLabeled(issue, exemptLabel)); + if (hasExemptLabel) { + issueLogger.info(`Skipping this $$type because it contains an exempt label, see ${issueLogger.createOptionLink(issue.isPullRequest ? option_1.Option.ExemptPrLabels : option_1.Option.ExemptIssueLabels)} for more details`); + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process exempt issues + } + const anyOfLabels = words_to_list_1.wordsToList(this._getAnyOfLabels(issue)); + if (anyOfLabels.length > 0) { + issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.AnyOfLabels)} was specified to only process the issues and pull requests with one of those labels (${logger_service_1.LoggerService.cyan(anyOfLabels.length)})`); + const hasOneOfWhitelistedLabels = anyOfLabels.some((label) => { + return is_labeled_1.isLabeled(issue, label); + }); + if (!hasOneOfWhitelistedLabels) { + issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skipping this $$type because it doesn't have one of the required labels`); + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process issues without any of the required labels + } + else { + issueLogger.info(logger_service_1.LoggerService.white('├──'), `One of the required labels is present on this $$type`); + issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); + } + } + else { + issueLogger.info(`The option ${issueLogger.createOptionLink(option_1.Option.AnyOfLabels)} was not specified`); + issueLogger.info(logger_service_1.LoggerService.white('└──'), `Continuing the process for this $$type`); + } + const milestones = new milestones_1.Milestones(this.options, issue); + if (milestones.shouldExemptMilestones()) { + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process exempt milestones + } + const assignees = new assignees_1.Assignees(this.options, issue); + if (assignees.shouldExemptAssignees()) { + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process exempt assignees + } + // Ignore draft PR + // Note that this check is so far below because it cost one read operation + // So it's simply better to do all the stale checks which don't cost more operation before this one + const exemptDraftPullRequest = new exempt_draft_pull_request_1.ExemptDraftPullRequest(this.options, issue); + if (yield exemptDraftPullRequest.shouldExemptDraftPullRequest(() => __awaiter(this, void 0, void 0, function* () { + return this.getPullRequest(issue); + }))) { + IssuesProcessor._endIssueProcessing(issue); + return; // Don't process draft PR + } + // Determine if this issue needs to be marked stale first + if (!issue.isStale) { + issueLogger.info(`This $$type is not stale`); + const shouldIgnoreUpdates = new ignore_updates_1.IgnoreUpdates(this.options, issue).shouldIgnoreUpdates(); + // Should this issue be marked as stale? + let shouldBeStale; + // Ignore the last update and only use the creation date + if (shouldIgnoreUpdates) { + shouldBeStale = !IssuesProcessor._updatedSince(issue.created_at, daysBeforeStale); + } + // Use the last update to check if we need to stale + else { + shouldBeStale = !IssuesProcessor._updatedSince(issue.updated_at, daysBeforeStale); + } + if (shouldBeStale) { + if (shouldIgnoreUpdates) { + issueLogger.info(`This $$type should be stale based on the creation date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`); + } + else { + issueLogger.info(`This $$type should be stale based on the last update date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`); + } + if (shouldMarkAsStale) { + issueLogger.info(`This $$type should be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`); + yield this._markStale(issue, staleMessage, staleLabel, skipMessage); + issue.isStale = true; // This issue is now considered stale + issue.markedStaleThisRun = true; + issueLogger.info(`This $$type is now stale`); + } + else { + issueLogger.info(`This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`); + } + } + else { + if (shouldIgnoreUpdates) { + issueLogger.info(`This $$type should not be stale based on the creation date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`); + } + else { + issueLogger.info(`This $$type should not be stale based on the last update date the ${get_humanized_date_1.getHumanizedDate(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`); + } + } + } + // Process the issue if it was marked stale + if (issue.isStale) { + issueLogger.info(`This $$type is already stale`); + yield this._processStaleIssue(issue, staleLabel, staleMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, closeMessage, closeLabel); + } + IssuesProcessor._endIssueProcessing(issue); + }); + } + // Grab comments for an issue since a given date + listIssueComments(issue, sinceDate) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + // Find any comments since date on the given issue + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsCommentsCount(); + const comments = yield this.client.rest.issues.listComments({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + since: sinceDate + }); + return comments.data; + } + catch (error) { + this._logger.error(`List issue comments error: ${error.message}`); + return Promise.resolve([]); + } + }); + } + // grab issues from github in batches of 100 + getIssues(page) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + try { + this.operations.consumeOperation(); + const issueResult = yield this.client.rest.issues.listForRepo({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + state: 'open', + per_page: 100, + direction: this.options.ascending ? 'asc' : 'desc', + page + }); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsCount(issueResult.data.length); + return issueResult.data.map((issue) => new issue_1.Issue(this.options, issue)); + } + catch (error) { + this._logger.error(`Get issues for repo error: ${error.message}`); + return Promise.resolve([]); + } + }); + } + // returns the creation date of a given label on an issue (or nothing if no label existed) + ///see https://developer.github.com/v3/activity/events/ + getLabelCreationDate(issue, label) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Checking for label on this $$type`); + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsEventsCount(); + const options = this.client.rest.issues.listEvents.endpoint.merge({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + per_page: 100, + issue_number: issue.number + }); + const events = yield this.client.paginate(options); + const reversedEvents = events.reverse(); + const staleLabeledEvent = reversedEvents.find(event => event.event === 'labeled' && + clean_label_1.cleanLabel(event.label.name) === clean_label_1.cleanLabel(label)); + if (!staleLabeledEvent) { + // Must be old rather than labeled + return undefined; + } + return staleLabeledEvent.created_at; + }); + } + getPullRequest(issue) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedPullRequestsCount(); + const pullRequest = yield this.client.rest.pulls.get({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + pull_number: issue.number + }); + return pullRequest.data; + } + catch (error) { + issueLogger.error(`Error when getting this $$type: ${error.message}`); + } + }); + } + // handle all of the stale issue logic when we find a stale issue + _processStaleIssue(issue, staleLabel, staleMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, closeMessage, closeLabel) { + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + const markedStaleOn = (yield this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at; + issueLogger.info(`$$type marked stale on: ${logger_service_1.LoggerService.cyan(markedStaleOn)}`); + const issueHasCommentsSinceStale = yield this._hasCommentsSince(issue, markedStaleOn, staleMessage); + issueLogger.info(`$$type has been commented on: ${logger_service_1.LoggerService.cyan(issueHasCommentsSinceStale)}`); + const daysBeforeClose = issue.isPullRequest + ? this._getDaysBeforePrClose() + : this._getDaysBeforeIssueClose(); + issueLogger.info(`Days before $$type close: ${logger_service_1.LoggerService.cyan(daysBeforeClose)}`); + const shouldRemoveStaleWhenUpdated = this._shouldRemoveStaleWhenUpdated(issue); + issueLogger.info(`The option ${issueLogger.createOptionLink(this._getRemoveStaleWhenUpdatedUsedOptionName(issue))} is: ${logger_service_1.LoggerService.cyan(shouldRemoveStaleWhenUpdated)}`); + if (shouldRemoveStaleWhenUpdated) { + issueLogger.info(`The stale label should not be removed`); + } + else { + issueLogger.info(`The stale label should be removed if all conditions met`); + } + if (issue.markedStaleThisRun) { + issueLogger.info(`marked stale this run, so don't check for updates`); + } + // The issue.updated_at and markedStaleOn are not always exactly in sync (they can be off by a second or 2) + // isDateMoreRecentThan makes sure they are not the same date within a certain tolerance (15 seconds in this case) + const issueHasUpdateSinceStale = is_date_more_recent_than_1.isDateMoreRecentThan(new Date(issue.updated_at), new Date(markedStaleOn), 15); + issueLogger.info(`$$type has been updated since it was marked stale: ${logger_service_1.LoggerService.cyan(issueHasUpdateSinceStale)}`); + // Should we un-stale this issue? + if (shouldRemoveStaleWhenUpdated && + (issueHasUpdateSinceStale || issueHasCommentsSinceStale) && + !issue.markedStaleThisRun) { + issueLogger.info(`Remove the stale label since the $$type has been updated and the workflow should remove the stale label when updated`); + yield this._removeStaleLabel(issue, staleLabel); + // Are there labels to remove or add when an issue is no longer stale? + yield this._removeLabelsWhenUnstale(issue, labelsToRemoveWhenUnstale); + yield this._addLabelsWhenUnstale(issue, labelsToAddWhenUnstale); + issueLogger.info(`Skipping the process since the $$type is now un-stale`); + return; // Nothing to do because it is no longer stale + } + // Now start closing logic + if (daysBeforeClose < 0) { + return; // Nothing to do because we aren't closing stale issues + } + const issueHasUpdateInCloseWindow = IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose); + issueLogger.info(`$$type has been updated in the last ${daysBeforeClose} days: ${logger_service_1.LoggerService.cyan(issueHasUpdateInCloseWindow)}`); + if (!issueHasCommentsSinceStale && !issueHasUpdateInCloseWindow) { + issueLogger.info(`Closing $$type because it was last updated on: ${logger_service_1.LoggerService.cyan(issue.updated_at)}`); + yield this._closeIssue(issue, closeMessage, closeLabel); + if (this.options.deleteBranch && issue.pull_request) { + issueLogger.info(`Deleting the branch since the option ${issueLogger.createOptionLink(option_1.Option.DeleteBranch)} is enabled`); + yield this._deleteBranch(issue); + this.deletedBranchIssues.push(issue); + } + } + else { + issueLogger.info(`Stale $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceStale}, hasUpdate? ${issueHasUpdateInCloseWindow})`); + } + }); + } + // checks to see if a given issue is still stale (has had activity on it) + _hasCommentsSince(issue, sinceDate, staleMessage) { + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Checking for comments on $$type since: ${logger_service_1.LoggerService.cyan(sinceDate)}`); + if (!sinceDate) { + return true; + } + // find any comments since the date + const comments = yield this.listIssueComments(issue, sinceDate); + const filteredComments = comments.filter(comment => { + var _a, _b; + return ((_a = comment.user) === null || _a === void 0 ? void 0 : _a.type) === 'User' && + ((_b = comment.body) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== staleMessage.toLowerCase(); + }); + issueLogger.info(`Comments that are not the stale comment or another bot: ${logger_service_1.LoggerService.cyan(filteredComments.length)}`); + // if there are any user comments returned + return filteredComments.length > 0; + }); + } + // Mark an issue as stale with a comment and a label + _markStale(issue, staleMessage, staleLabel, skipMessage) { + var _a, _b, _c; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Marking this $$type as stale`); + this.staleIssues.push(issue); + // if the issue is being marked stale, the updated date should be changed to right now + // so that close calculations work correctly + const newUpdatedAtDate = new Date(); + issue.updated_at = newUpdatedAtDate.toString(); + if (!skipMessage) { + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsComment(issue); + if (!this.options.debugOnly) { + yield this.client.rest.issues.createComment({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + body: staleMessage + }); + } + } + catch (error) { + issueLogger.error(`Error when creating a comment: ${error.message}`); + } + } + try { + this._consumeIssueOperation(issue); + (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.incrementAddedItemsLabel(issue); + (_c = this.statistics) === null || _c === void 0 ? void 0 : _c.incrementStaleItemsCount(issue); + if (!this.options.debugOnly) { + yield this.client.rest.issues.addLabels({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + labels: [staleLabel] + }); + } + } + catch (error) { + issueLogger.error(`Error when adding a label: ${error.message}`); + } + }); + } + // Close an issue based on staleness + _closeIssue(issue, closeMessage, closeLabel) { + var _a, _b, _c; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Closing $$type for being stale`); + this.closedIssues.push(issue); + if (closeMessage) { + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsComment(issue); + this.addedCloseCommentIssues.push(issue); + if (!this.options.debugOnly) { + yield this.client.rest.issues.createComment({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + body: closeMessage + }); + } + } + catch (error) { + issueLogger.error(`Error when creating a comment: ${error.message}`); + } + } + if (closeLabel) { + try { + this._consumeIssueOperation(issue); + (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.incrementAddedItemsLabel(issue); + if (!this.options.debugOnly) { + yield this.client.rest.issues.addLabels({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + labels: [closeLabel] + }); + } + } + catch (error) { + issueLogger.error(`Error when adding a label: ${error.message}`); + } + } + try { + this._consumeIssueOperation(issue); + (_c = this.statistics) === null || _c === void 0 ? void 0 : _c.incrementClosedItemsCount(issue); + if (!this.options.debugOnly) { + yield this.client.rest.issues.update({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + state: 'closed', + state_reason: this.options.closeIssueReason || undefined + }); + } + } + catch (error) { + issueLogger.error(`Error when updating this $$type: ${error.message}`); + } + }); + } + // Delete the branch on closed pull request + _deleteBranch(issue) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Delete + branch from closed $ + $type + - + ${issue.title}`); + const pullRequest = yield this.getPullRequest(issue); + if (!pullRequest) { + issueLogger.info(`Not deleting this branch as no pull request was found for this $$type`); + return; + } + const branch = pullRequest.head.ref; + issueLogger.info(`Deleting the branch "${logger_service_1.LoggerService.cyan(branch)}" from closed $$type`); + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedBranchesCount(); + if (!this.options.debugOnly) { + yield this.client.rest.git.deleteRef({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + ref: `heads/${branch}` + }); + } + } + catch (error) { + issueLogger.error(`Error when deleting the branch "${logger_service_1.LoggerService.cyan(branch)}" from $$type: ${error.message}`); + } + }); + } + // Remove a label from an issue or a pull request + _removeLabel(issue, label, isSubStep = false) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`${isSubStep ? logger_service_1.LoggerService.white('├── ') : ''}Removing the label "${logger_service_1.LoggerService.cyan(label)}" from this $$type...`); + this.removedLabelIssues.push(issue); + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedItemsLabelsCount(issue); + if (!this.options.debugOnly) { + yield this.client.rest.issues.removeLabel({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + name: label + }); + } + issueLogger.info(`${isSubStep ? logger_service_1.LoggerService.white('└── ') : ''}The label "${logger_service_1.LoggerService.cyan(label)}" was removed`); + } + catch (error) { + issueLogger.error(`${isSubStep ? logger_service_1.LoggerService.white('└── ') : ''}Error when removing the label: "${logger_service_1.LoggerService.cyan(error.message)}"`); + } + }); + } + _getDaysBeforeIssueStale() { + return isNaN(this.options.daysBeforeIssueStale) + ? this.options.daysBeforeStale + : this.options.daysBeforeIssueStale; + } + _getDaysBeforePrStale() { + return isNaN(this.options.daysBeforePrStale) + ? this.options.daysBeforeStale + : this.options.daysBeforePrStale; + } + _getDaysBeforeIssueClose() { + return isNaN(this.options.daysBeforeIssueClose) + ? this.options.daysBeforeClose + : this.options.daysBeforeIssueClose; + } + _getDaysBeforePrClose() { + return isNaN(this.options.daysBeforePrClose) + ? this.options.daysBeforeClose + : this.options.daysBeforePrClose; + } + _getOnlyLabels(issue) { + if (issue.isPullRequest) { + if (this.options.onlyPrLabels !== '') { + return this.options.onlyPrLabels; + } + } + else { + if (this.options.onlyIssueLabels !== '') { + return this.options.onlyIssueLabels; + } + } + return this.options.onlyLabels; + } + _isIncludeOnlyAssigned(issue) { + return this.options.includeOnlyAssigned && !issue.hasAssignees; + } + _getAnyOfLabels(issue) { + if (issue.isPullRequest) { + if (this.options.anyOfPrLabels !== '') { + return this.options.anyOfPrLabels; + } + } + else { + if (this.options.anyOfIssueLabels !== '') { + return this.options.anyOfIssueLabels; + } + } + return this.options.anyOfLabels; + } + _shouldRemoveStaleWhenUpdated(issue) { + if (issue.isPullRequest) { + if (is_boolean_1.isBoolean(this.options.removePrStaleWhenUpdated)) { + return this.options.removePrStaleWhenUpdated; + } + return this.options.removeStaleWhenUpdated; + } + if (is_boolean_1.isBoolean(this.options.removeIssueStaleWhenUpdated)) { + return this.options.removeIssueStaleWhenUpdated; + } + return this.options.removeStaleWhenUpdated; + } + _removeLabelsWhenUnstale(issue, removeLabels) { + return __awaiter(this, void 0, void 0, function* () { + if (!removeLabels.length) { + return; + } + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Removing all the labels specified via the ${this._logger.createOptionLink(option_1.Option.LabelsToRemoveWhenUnstale)} option.`); + for (const label of removeLabels.values()) { + yield this._removeLabel(issue, label); + } + }); + } + _addLabelsWhenUnstale(issue, labelsToAdd) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + if (!labelsToAdd.length) { + return; + } + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Adding all the labels specified via the ${this._logger.createOptionLink(option_1.Option.LabelsToAddWhenUnstale)} option.`); + this.addedLabelIssues.push(issue); + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsLabel(issue); + if (!this.options.debugOnly) { + yield this.client.rest.issues.addLabels({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + labels: labelsToAdd + }); + } + } + catch (error) { + this._logger.error(`Error when adding labels after updated from stale: ${error.message}`); + } + }); + } + _removeStaleLabel(issue, staleLabel) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`The $$type is no longer stale. Removing the stale label...`); + yield this._removeLabel(issue, staleLabel); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementUndoStaleItemsCount(issue); + }); + } + _removeCloseLabel(issue, closeLabel) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`The $$type is not closed nor locked. Trying to remove the close label...`); + if (!closeLabel) { + issueLogger.info(logger_service_1.LoggerService.white('├──'), `The ${issueLogger.createOptionLink(IssuesProcessor._getCloseLabelUsedOptionName(issue))} option was not set`); + issueLogger.info(logger_service_1.LoggerService.white('└──'), `Skipping the removal of the close label`); + return Promise.resolve(); + } + if (is_labeled_1.isLabeled(issue, closeLabel)) { + issueLogger.info(logger_service_1.LoggerService.white('├──'), `The $$type has a close label "${logger_service_1.LoggerService.cyan(closeLabel)}". Removing the close label...`); + yield this._removeLabel(issue, closeLabel, true); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedCloseItemsLabelsCount(issue); + } + else { + issueLogger.info(logger_service_1.LoggerService.white('└──'), `There is no close label on this $$type. Skipping`); + return Promise.resolve(); + } + }); + } + _consumeIssueOperation(issue) { + this.operations.consumeOperation(); + issue.operations.consumeOperation(); + } + _getDaysBeforeStaleUsedOptionName(issue) { + return issue.isPullRequest + ? this._getDaysBeforePrStaleUsedOptionName() + : this._getDaysBeforeIssueStaleUsedOptionName(); + } + _getDaysBeforeIssueStaleUsedOptionName() { + return isNaN(this.options.daysBeforeIssueStale) + ? option_1.Option.DaysBeforeStale + : option_1.Option.DaysBeforeIssueStale; + } + _getDaysBeforePrStaleUsedOptionName() { + return isNaN(this.options.daysBeforePrStale) + ? option_1.Option.DaysBeforeStale + : option_1.Option.DaysBeforePrStale; + } + _getRemoveStaleWhenUpdatedUsedOptionName(issue) { + if (issue.isPullRequest) { + if (is_boolean_1.isBoolean(this.options.removePrStaleWhenUpdated)) { + return option_1.Option.RemovePrStaleWhenUpdated; + } + return option_1.Option.RemoveStaleWhenUpdated; + } + if (is_boolean_1.isBoolean(this.options.removeIssueStaleWhenUpdated)) { + return option_1.Option.RemoveIssueStaleWhenUpdated; + } + return option_1.Option.RemoveStaleWhenUpdated; + } +} +exports.IssuesProcessor = IssuesProcessor; /***/ }), @@ -1132,85 +1129,85 @@ exports.IssuesProcessor = IssuesProcessor; /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.IssueLogger = void 0; -const logger_1 = __nccwpck_require__(6212); -const logger_service_1 = __nccwpck_require__(1973); -/** - * @description - * Each log will prefix the message with the issue number - * - * @example - * warning('No stale') => "[#123] No stale" - * - * Each log method can have special tokens: - * - $$type => will replace this by either "pull request" or "issue" depending of the type of issue - * - * @example - * warning('The $$type will stale') => "The pull request will stale" - */ -class IssueLogger extends logger_1.Logger { - constructor(issue) { - super(); - this._issue = issue; - } - warning(...message) { - super.warning(this._format(...message)); - } - info(...message) { - super.info(this._format(...message)); - } - error(...message) { - super.error(this._format(...message)); - } - grouping(message, fn) { - const _super = Object.create(null, { - grouping: { get: () => super.grouping } - }); - return __awaiter(this, void 0, void 0, function* () { - return _super.grouping.call(this, this._format(message), fn); - }); - } - _replaceTokens(message) { - return this._replaceTypeToken(message); - } - _replaceTypeToken(message) { - return message - .replace(/^\$\$type/, this._issue.isPullRequest ? 'Pull request' : 'Issue') - .replace(/\$\$type/g, this._issue.isPullRequest ? 'pull request' : 'issue'); - } - _prefixWithIssueNumber(message) { - return `${this._getPrefix()} ${message}`; - } - _getIssueNumber() { - return this._issue.number; - } - _format(...message) { - return this._prefixWithIssueNumber(this._replaceTokens(message.join(' '))); - } - _getPrefix() { - return this._issue.isPullRequest - ? this._getPullRequestPrefix() - : this._getIssuePrefix(); - } - _getIssuePrefix() { - return logger_service_1.LoggerService.red(`[#${this._getIssueNumber()}]`); - } - _getPullRequestPrefix() { - return logger_service_1.LoggerService.blue(`[#${this._getIssueNumber()}]`); - } -} -exports.IssueLogger = IssueLogger; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.IssueLogger = void 0; +const logger_1 = __nccwpck_require__(6212); +const logger_service_1 = __nccwpck_require__(1973); +/** + * @description + * Each log will prefix the message with the issue number + * + * @example + * warning('No stale') => "[#123] No stale" + * + * Each log method can have special tokens: + * - $$type => will replace this by either "pull request" or "issue" depending of the type of issue + * + * @example + * warning('The $$type will stale') => "The pull request will stale" + */ +class IssueLogger extends logger_1.Logger { + constructor(issue) { + super(); + this._issue = issue; + } + warning(...message) { + super.warning(this._format(...message)); + } + info(...message) { + super.info(this._format(...message)); + } + error(...message) { + super.error(this._format(...message)); + } + grouping(message, fn) { + const _super = Object.create(null, { + grouping: { get: () => super.grouping } + }); + return __awaiter(this, void 0, void 0, function* () { + return _super.grouping.call(this, this._format(message), fn); + }); + } + _replaceTokens(message) { + return this._replaceTypeToken(message); + } + _replaceTypeToken(message) { + return message + .replace(/^\$\$type/, this._issue.isPullRequest ? 'Pull request' : 'Issue') + .replace(/\$\$type/g, this._issue.isPullRequest ? 'pull request' : 'issue'); + } + _prefixWithIssueNumber(message) { + return `${this._getPrefix()} ${message}`; + } + _getIssueNumber() { + return this._issue.number; + } + _format(...message) { + return this._prefixWithIssueNumber(this._replaceTokens(message.join(' '))); + } + _getPrefix() { + return this._issue.isPullRequest + ? this._getPullRequestPrefix() + : this._getIssuePrefix(); + } + _getIssuePrefix() { + return logger_service_1.LoggerService.red(`[#${this._getIssueNumber()}]`); + } + _getPullRequestPrefix() { + return logger_service_1.LoggerService.blue(`[#${this._getIssueNumber()}]`); + } +} +exports.IssueLogger = IssueLogger; /***/ }), @@ -1219,66 +1216,66 @@ exports.IssueLogger = IssueLogger; /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Logger = void 0; -const core = __importStar(__nccwpck_require__(2186)); -const terminal_link_1 = __importDefault(__nccwpck_require__(1898)); -const logger_service_1 = __nccwpck_require__(1973); -class Logger { - warning(...message) { - core.warning(logger_service_1.LoggerService.whiteBright(message.join(' '))); - } - info(...message) { - core.info(logger_service_1.LoggerService.whiteBright(message.join(' '))); - } - error(...message) { - core.error(logger_service_1.LoggerService.whiteBright(message.join(' '))); - } - grouping(message, fn) { - return __awaiter(this, void 0, void 0, function* () { - return core.group(logger_service_1.LoggerService.whiteBright(message), fn); - }); - } - createLink(name, link) { - return terminal_link_1.default(name, link); - } - createOptionLink(option) { - return logger_service_1.LoggerService.magenta(this.createLink(option, `https://github.com/actions/stale#${option}`)); - } -} -exports.Logger = Logger; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Logger = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const terminal_link_1 = __importDefault(__nccwpck_require__(1898)); +const logger_service_1 = __nccwpck_require__(1973); +class Logger { + warning(...message) { + core.warning(logger_service_1.LoggerService.whiteBright(message.join(' '))); + } + info(...message) { + core.info(logger_service_1.LoggerService.whiteBright(message.join(' '))); + } + error(...message) { + core.error(logger_service_1.LoggerService.whiteBright(message.join(' '))); + } + grouping(message, fn) { + return __awaiter(this, void 0, void 0, function* () { + return core.group(logger_service_1.LoggerService.whiteBright(message), fn); + }); + } + createLink(name, link) { + return terminal_link_1.default(name, link); + } + createOptionLink(option) { + return logger_service_1.LoggerService.magenta(this.createLink(option, `https://github.com/actions/stale#${option}`)); + } +} +exports.Logger = Logger; /***/ }), @@ -1287,145 +1284,145 @@ exports.Logger = Logger; /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Milestones = void 0; -const lodash_deburr_1 = __importDefault(__nccwpck_require__(1601)); -const option_1 = __nccwpck_require__(5931); -const words_to_list_1 = __nccwpck_require__(1883); -const issue_logger_1 = __nccwpck_require__(2984); -const logger_service_1 = __nccwpck_require__(1973); -class Milestones { - constructor(options, issue) { - this._options = options; - this._issue = issue; - this._issueLogger = new issue_logger_1.IssueLogger(issue); - } - static _cleanMilestone(milestone) { - return lodash_deburr_1.default(milestone.toLowerCase()); - } - shouldExemptMilestones() { - if (!this._issue.milestone) { - this._issueLogger.info('This $$type has no milestone'); - this._logSkip(); - return false; - } - if (this._shouldExemptAllMilestones()) { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has a milestone'); - return true; - } - const exemptMilestones = this._getExemptMilestones(); - if (exemptMilestones.length === 0) { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `No milestone option was specified to skip the stale process for this $$type`); - this._logSkip(); - return false; - } - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `Found ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length > 1 ? 's' : ''} that can exempt stale on this $$type`); - const hasExemptMilestone = exemptMilestones.some((exemptMilestone) => this._hasMilestone(exemptMilestone)); - if (!hasExemptMilestone) { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), 'No milestone on this $$type can exempt the stale process'); - this._logSkip(); - } - else { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has an exempt milestone'); - } - return hasExemptMilestone; - } - _getExemptMilestones() { - return this._issue.isPullRequest - ? this._getExemptPullRequestMilestones() - : this._getExemptIssueMilestones(); - } - _getExemptIssueMilestones() { - if (this._options.exemptIssueMilestones === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); - if (this._options.exemptMilestones === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); - return []; - } - const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptMilestones); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptMilestones; - } - const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptIssueMilestones); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptMilestones; - } - _getExemptPullRequestMilestones() { - if (this._options.exemptPrMilestones === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); - if (this._options.exemptMilestones === '') { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); - return []; - } - const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptMilestones); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptMilestones; - } - const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptPrMilestones); - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); - return exemptMilestones; - } - _hasMilestone(milestone) { - if (!this._issue.milestone) { - return false; - } - const cleanMilestone = Milestones._cleanMilestone(milestone); - const isSameMilestone = cleanMilestone === - Milestones._cleanMilestone(this._issue.milestone.title); - if (isSameMilestone) { - this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The milestone "${logger_service_1.LoggerService.cyan(milestone)}" is set on this $$type and is an exempt milestone`); - } - return isSameMilestone; - } - _shouldExemptAllMilestones() { - if (this._issue.milestone) { - return this._issue.isPullRequest - ? this._shouldExemptAllPullRequestMilestones() - : this._shouldExemptAllIssueMilestones(); - } - return false; - } - _shouldExemptAllIssueMilestones() { - if (this._options.exemptAllIssueMilestones === true) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllIssueMilestones)} is disabled. Only some specific milestones on this $$type will skip the stale process`); - return false; - } - this._logExemptAllMilestonesOption(); - return this._options.exemptAllMilestones; - } - _shouldExemptAllPullRequestMilestones() { - if (this._options.exemptAllPrMilestones === true) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllPrMilestones)} is disabled. Only some specific milestones on this $$type will skip the stale process`); - return false; - } - this._logExemptAllMilestonesOption(); - return this._options.exemptAllMilestones; - } - _logExemptAllMilestonesOption() { - if (this._options.exemptAllMilestones) { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllMilestones)} is enabled. Any milestone on this $$type will skip the stale process`); - } - else { - this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllMilestones)} is disabled. Only some specific milestones on this $$type will skip the stale process`); - } - } - _logSkip() { - this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skip the milestones checks'); - } -} -exports.Milestones = Milestones; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Milestones = void 0; +const lodash_deburr_1 = __importDefault(__nccwpck_require__(1601)); +const option_1 = __nccwpck_require__(5931); +const words_to_list_1 = __nccwpck_require__(1883); +const issue_logger_1 = __nccwpck_require__(2984); +const logger_service_1 = __nccwpck_require__(1973); +class Milestones { + constructor(options, issue) { + this._options = options; + this._issue = issue; + this._issueLogger = new issue_logger_1.IssueLogger(issue); + } + static _cleanMilestone(milestone) { + return lodash_deburr_1.default(milestone.toLowerCase()); + } + shouldExemptMilestones() { + if (!this._issue.milestone) { + this._issueLogger.info('This $$type has no milestone'); + this._logSkip(); + return false; + } + if (this._shouldExemptAllMilestones()) { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has a milestone'); + return true; + } + const exemptMilestones = this._getExemptMilestones(); + if (exemptMilestones.length === 0) { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `No milestone option was specified to skip the stale process for this $$type`); + this._logSkip(); + return false; + } + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `Found ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length > 1 ? 's' : ''} that can exempt stale on this $$type`); + const hasExemptMilestone = exemptMilestones.some((exemptMilestone) => this._hasMilestone(exemptMilestone)); + if (!hasExemptMilestone) { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), 'No milestone on this $$type can exempt the stale process'); + this._logSkip(); + } + else { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skipping this $$type because it has an exempt milestone'); + } + return hasExemptMilestone; + } + _getExemptMilestones() { + return this._issue.isPullRequest + ? this._getExemptPullRequestMilestones() + : this._getExemptIssueMilestones(); + } + _getExemptIssueMilestones() { + if (this._options.exemptIssueMilestones === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); + if (this._options.exemptMilestones === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); + return []; + } + const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptMilestones); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptMilestones; + } + const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptIssueMilestones); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptIssueMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptMilestones; + } + _getExemptPullRequestMilestones() { + if (this._options.exemptPrMilestones === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); + if (this._options.exemptMilestones === '') { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is disabled. No specific milestone can skip the stale process for this $$type`); + return []; + } + const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptMilestones); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptMilestones; + } + const exemptMilestones = words_to_list_1.wordsToList(this._options.exemptPrMilestones); + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptPrMilestones)} is set. ${logger_service_1.LoggerService.cyan(exemptMilestones.length)} milestone${exemptMilestones.length === 1 ? '' : 's'} can skip the stale process for this $$type`); + return exemptMilestones; + } + _hasMilestone(milestone) { + if (!this._issue.milestone) { + return false; + } + const cleanMilestone = Milestones._cleanMilestone(milestone); + const isSameMilestone = cleanMilestone === + Milestones._cleanMilestone(this._issue.milestone.title); + if (isSameMilestone) { + this._issueLogger.info(logger_service_1.LoggerService.white('├──'), `The milestone "${logger_service_1.LoggerService.cyan(milestone)}" is set on this $$type and is an exempt milestone`); + } + return isSameMilestone; + } + _shouldExemptAllMilestones() { + if (this._issue.milestone) { + return this._issue.isPullRequest + ? this._shouldExemptAllPullRequestMilestones() + : this._shouldExemptAllIssueMilestones(); + } + return false; + } + _shouldExemptAllIssueMilestones() { + if (this._options.exemptAllIssueMilestones === true) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllIssueMilestones)} is disabled. Only some specific milestones on this $$type will skip the stale process`); + return false; + } + this._logExemptAllMilestonesOption(); + return this._options.exemptAllMilestones; + } + _shouldExemptAllPullRequestMilestones() { + if (this._options.exemptAllPrMilestones === true) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.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_1.Option.ExemptAllPrMilestones)} is disabled. Only some specific milestones on this $$type will skip the stale process`); + return false; + } + this._logExemptAllMilestonesOption(); + return this._options.exemptAllMilestones; + } + _logExemptAllMilestonesOption() { + if (this._options.exemptAllMilestones) { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllMilestones)} is enabled. Any milestone on this $$type will skip the stale process`); + } + else { + this._issueLogger.info(`The option ${this._issueLogger.createOptionLink(option_1.Option.ExemptAllMilestones)} is disabled. Only some specific milestones on this $$type will skip the stale process`); + } + } + _logSkip() { + this._issueLogger.info(logger_service_1.LoggerService.white('└──'), 'Skip the milestones checks'); + } +} +exports.Milestones = Milestones; /***/ }), @@ -1434,25 +1431,25 @@ exports.Milestones = Milestones; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Operations = void 0; -class Operations { - constructor() { - this._operationsConsumed = 0; - } - consumeOperation() { - return this.consumeOperations(1); - } - consumeOperations(quantity) { - this._operationsConsumed += quantity; - return this; - } - getConsumedOperationsCount() { - return this._operationsConsumed; - } -} -exports.Operations = Operations; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Operations = void 0; +class Operations { + constructor() { + this._operationsConsumed = 0; + } + consumeOperation() { + return this.consumeOperations(1); + } + consumeOperations(quantity) { + this._operationsConsumed += quantity; + return this; + } + getConsumedOperationsCount() { + return this._operationsConsumed; + } +} +exports.Operations = Operations; /***/ }), @@ -1461,23 +1458,23 @@ exports.Operations = Operations; /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.StaleOperations = void 0; -const operations_1 = __nccwpck_require__(7957); -class StaleOperations extends operations_1.Operations { - constructor(options) { - super(); - this._options = options; - } - hasRemainingOperations() { - return this._operationsConsumed < this._options.operationsPerRun; - } - getRemainingOperationsCount() { - return this._options.operationsPerRun - this._operationsConsumed; - } -} -exports.StaleOperations = StaleOperations; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.StaleOperations = void 0; +const operations_1 = __nccwpck_require__(7957); +class StaleOperations extends operations_1.Operations { + constructor(options) { + super(); + this._options = options; + } + hasRemainingOperations() { + return this._operationsConsumed < this._options.operationsPerRun; + } + getRemainingOperationsCount() { + return this._options.operationsPerRun - this._operationsConsumed; + } +} +exports.StaleOperations = StaleOperations; /***/ }), @@ -1486,364 +1483,364 @@ exports.StaleOperations = StaleOperations; /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Statistics = void 0; -const logger_1 = __nccwpck_require__(6212); -const logger_service_1 = __nccwpck_require__(1973); -class Statistics { - constructor() { - this._logger = new logger_1.Logger(); - this.processedIssuesCount = 0; - this.processedPullRequestsCount = 0; - this.staleIssuesCount = 0; - this.stalePullRequestsCount = 0; - this.undoStaleIssuesCount = 0; - this.undoStalePullRequestsCount = 0; - this.operationsCount = 0; - this.closedIssuesCount = 0; - this.closedPullRequestsCount = 0; - this.deletedIssuesLabelsCount = 0; - this.deletedPullRequestsLabelsCount = 0; - this.deletedCloseIssuesLabelsCount = 0; - this.deletedClosePullRequestsLabelsCount = 0; - this.deletedBranchesCount = 0; - this.addedIssuesLabelsCount = 0; - this.addedPullRequestsLabelsCount = 0; - this.addedIssuesCommentsCount = 0; - this.addedPullRequestsCommentsCount = 0; - this.fetchedItemsCount = 0; - this.fetchedItemsEventsCount = 0; - this.fetchedItemsCommentsCount = 0; - this.fetchedPullRequestsCount = 0; - } - incrementProcessedItemsCount(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementProcessedPullRequestsCount(increment); - } - return this._incrementProcessedIssuesCount(increment); - } - incrementStaleItemsCount(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementStalePullRequestsCount(increment); - } - return this._incrementStaleIssuesCount(increment); - } - incrementUndoStaleItemsCount(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementUndoStalePullRequestsCount(increment); - } - return this._incrementUndoStaleIssuesCount(increment); - } - setOperationsCount(operationsCount) { - this.operationsCount = operationsCount; - return this; - } - incrementClosedItemsCount(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementClosedPullRequestsCount(increment); - } - return this._incrementClosedIssuesCount(increment); - } - incrementDeletedItemsLabelsCount(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementDeletedPullRequestsLabelsCount(increment); - } - return this._incrementDeletedIssuesLabelsCount(increment); - } - incrementDeletedCloseItemsLabelsCount(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementDeletedClosePullRequestsLabelsCount(increment); - } - return this._incrementDeletedCloseIssuesLabelsCount(increment); - } - incrementDeletedBranchesCount(increment = 1) { - this.deletedBranchesCount += increment; - return this; - } - incrementAddedItemsLabel(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementAddedPullRequestsLabel(increment); - } - return this._incrementAddedIssuesLabel(increment); - } - incrementAddedItemsComment(issue, increment = 1) { - if (issue.isPullRequest) { - return this._incrementAddedPullRequestsComment(increment); - } - return this._incrementAddedIssuesComment(increment); - } - incrementFetchedItemsCount(increment = 1) { - this.fetchedItemsCount += increment; - return this; - } - incrementFetchedItemsEventsCount(increment = 1) { - this.fetchedItemsEventsCount += increment; - return this; - } - incrementFetchedItemsCommentsCount(increment = 1) { - this.fetchedItemsCommentsCount += increment; - return this; - } - incrementFetchedPullRequestsCount(increment = 1) { - this.fetchedPullRequestsCount += increment; - return this; - } - logStats() { - this._logger.info(logger_service_1.LoggerService.yellow(logger_service_1.LoggerService.bold(`Statistics:`))); - this._logProcessedIssuesAndPullRequestsCount(); - this._logStaleIssuesAndPullRequestsCount(); - this._logUndoStaleIssuesAndPullRequestsCount(); - this._logClosedIssuesAndPullRequestsCount(); - this._logDeletedIssuesAndPullRequestsLabelsCount(); - this._logDeletedCloseIssuesAndPullRequestsLabelsCount(); - this._logDeletedBranchesCount(); - this._logAddedIssuesAndPullRequestsLabelsCount(); - this._logAddedIssuesAndPullRequestsCommentsCount(); - this._logFetchedItemsCount(); - this._logFetchedItemsEventsCount(); - this._logFetchedItemsCommentsCount(); - this._logFetchedPullRequestsCount(); - this._logOperationsCount(); - return this; - } - _incrementProcessedIssuesCount(increment = 1) { - this.processedIssuesCount += increment; - return this; - } - _incrementProcessedPullRequestsCount(increment = 1) { - this.processedPullRequestsCount += increment; - return this; - } - _incrementStaleIssuesCount(increment = 1) { - this.staleIssuesCount += increment; - return this; - } - _incrementStalePullRequestsCount(increment = 1) { - this.stalePullRequestsCount += increment; - return this; - } - _incrementUndoStaleIssuesCount(increment = 1) { - this.undoStaleIssuesCount += increment; - return this; - } - _incrementUndoStalePullRequestsCount(increment = 1) { - this.undoStalePullRequestsCount += increment; - return this; - } - _incrementClosedIssuesCount(increment = 1) { - this.closedIssuesCount += increment; - return this; - } - _incrementClosedPullRequestsCount(increment = 1) { - this.closedPullRequestsCount += increment; - return this; - } - _incrementDeletedIssuesLabelsCount(increment = 1) { - this.deletedIssuesLabelsCount += increment; - return this; - } - _incrementDeletedPullRequestsLabelsCount(increment = 1) { - this.deletedPullRequestsLabelsCount += increment; - return this; - } - _incrementDeletedCloseIssuesLabelsCount(increment = 1) { - this.deletedCloseIssuesLabelsCount += increment; - return this; - } - _incrementDeletedClosePullRequestsLabelsCount(increment = 1) { - this.deletedClosePullRequestsLabelsCount += increment; - return this; - } - _incrementAddedIssuesLabel(increment = 1) { - this.addedIssuesLabelsCount += increment; - return this; - } - _incrementAddedPullRequestsLabel(increment = 1) { - this.addedPullRequestsLabelsCount += increment; - return this; - } - _incrementAddedIssuesComment(increment = 1) { - this.addedIssuesCommentsCount += increment; - return this; - } - _incrementAddedPullRequestsComment(increment = 1) { - this.addedPullRequestsCommentsCount += increment; - return this; - } - _logProcessedIssuesAndPullRequestsCount() { - this._logGroup('Processed items', [ - { - name: 'Processed issues', - count: this.processedIssuesCount - }, - { - name: 'Processed PRs', - count: this.processedPullRequestsCount - } - ]); - } - _logStaleIssuesAndPullRequestsCount() { - this._logGroup('New stale items', [ - { - name: 'New stale issues', - count: this.staleIssuesCount - }, - { - name: 'New stale PRs', - count: this.stalePullRequestsCount - } - ]); - } - _logUndoStaleIssuesAndPullRequestsCount() { - this._logGroup('No longer stale items', [ - { - name: 'No longer stale issues', - count: this.undoStaleIssuesCount - }, - { - name: 'No longer stale PRs', - count: this.undoStalePullRequestsCount - } - ]); - } - _logClosedIssuesAndPullRequestsCount() { - this._logGroup('Closed items', [ - { - name: 'Closed issues', - count: this.closedIssuesCount - }, - { - name: 'Closed PRs', - count: this.closedPullRequestsCount - } - ]); - } - _logDeletedIssuesAndPullRequestsLabelsCount() { - this._logGroup('Deleted items labels', [ - { - name: 'Deleted issues labels', - count: this.deletedIssuesLabelsCount - }, - { - name: 'Deleted PRs labels', - count: this.deletedPullRequestsLabelsCount - } - ]); - } - _logDeletedCloseIssuesAndPullRequestsLabelsCount() { - this._logGroup('Deleted close items labels', [ - { - name: 'Deleted close issues labels', - count: this.deletedCloseIssuesLabelsCount - }, - { - name: 'Deleted close PRs labels', - count: this.deletedClosePullRequestsLabelsCount - } - ]); - } - _logDeletedBranchesCount() { - this._logCount('Deleted branches', this.deletedBranchesCount); - } - _logAddedIssuesAndPullRequestsLabelsCount() { - this._logGroup('Added items labels', [ - { - name: 'Added issues labels', - count: this.addedIssuesLabelsCount - }, - { - name: 'Added PRs labels', - count: this.addedPullRequestsLabelsCount - } - ]); - } - _logAddedIssuesAndPullRequestsCommentsCount() { - this._logGroup('Added items comments', [ - { - name: 'Added issues comments', - count: this.addedIssuesCommentsCount - }, - { - name: 'Added PRs comments', - count: this.addedPullRequestsCommentsCount - } - ]); - } - _logFetchedItemsCount() { - this._logCount('Fetched items', this.fetchedItemsCount); - } - _logFetchedItemsEventsCount() { - this._logCount('Fetched items events', this.fetchedItemsEventsCount); - } - _logFetchedItemsCommentsCount() { - this._logCount('Fetched items comments', this.fetchedItemsCommentsCount); - } - _logFetchedPullRequestsCount() { - this._logCount('Fetched pull requests', this.fetchedPullRequestsCount); - } - _logOperationsCount() { - this._logCount('Operations performed', this.operationsCount); - } - _logCount(name, count) { - if (count > 0) { - this._logger.info(`${name}:`, logger_service_1.LoggerService.cyan(count)); - } - } - _logGroup(groupName, values) { - if (this._isGroupValuesPartiallySet(values)) { - this._logCount(groupName, this._getGroupValuesTotalCount(values)); - this._logGroupValues(values); - } - else { - // Only one value will be display - for (const value of values) { - this._logCount(value.name, value.count); - } - } - } - /** - * @private - * @description - * If there is a least two elements with a valid count then it's partially set - * Useful to defined if we should display the values as a group or not - * - * @param {IGroupValue[]} values The list of group values to check - */ - _isGroupValuesPartiallySet(values) { - return (values - .map((value) => { - return value.count > 0; - }) - .filter((isSet) => isSet).length >= 2); - } - _getGroupValuesTotalCount(values) { - return values.reduce((count, value) => { - return count + value.count; - }, 0); - } - _getAllGroupValuesSet(values) { - return values.filter((value) => { - return value.count > 0; - }); - } - _logGroupValues(values) { - const onlyValuesSet = this._getAllGroupValuesSet(values); - const longestValue = this._getLongestGroupValue(onlyValuesSet); - for (const [index, value] of onlyValuesSet.entries()) { - const prefix = index === onlyValuesSet.length - 1 ? '└──' : '├──'; - this._logCount(`${logger_service_1.LoggerService.white(prefix)} ${value.name.padEnd(longestValue, ' ')}`, value.count); - } - } - _getLongestGroupValue(values) { - return values.reduce((longestValue, value) => { - return value.name.length > longestValue - ? value.name.length - : longestValue; - }, 0); - } -} -exports.Statistics = Statistics; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Statistics = void 0; +const logger_1 = __nccwpck_require__(6212); +const logger_service_1 = __nccwpck_require__(1973); +class Statistics { + constructor() { + this._logger = new logger_1.Logger(); + this.processedIssuesCount = 0; + this.processedPullRequestsCount = 0; + this.staleIssuesCount = 0; + this.stalePullRequestsCount = 0; + this.undoStaleIssuesCount = 0; + this.undoStalePullRequestsCount = 0; + this.operationsCount = 0; + this.closedIssuesCount = 0; + this.closedPullRequestsCount = 0; + this.deletedIssuesLabelsCount = 0; + this.deletedPullRequestsLabelsCount = 0; + this.deletedCloseIssuesLabelsCount = 0; + this.deletedClosePullRequestsLabelsCount = 0; + this.deletedBranchesCount = 0; + this.addedIssuesLabelsCount = 0; + this.addedPullRequestsLabelsCount = 0; + this.addedIssuesCommentsCount = 0; + this.addedPullRequestsCommentsCount = 0; + this.fetchedItemsCount = 0; + this.fetchedItemsEventsCount = 0; + this.fetchedItemsCommentsCount = 0; + this.fetchedPullRequestsCount = 0; + } + incrementProcessedItemsCount(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementProcessedPullRequestsCount(increment); + } + return this._incrementProcessedIssuesCount(increment); + } + incrementStaleItemsCount(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementStalePullRequestsCount(increment); + } + return this._incrementStaleIssuesCount(increment); + } + incrementUndoStaleItemsCount(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementUndoStalePullRequestsCount(increment); + } + return this._incrementUndoStaleIssuesCount(increment); + } + setOperationsCount(operationsCount) { + this.operationsCount = operationsCount; + return this; + } + incrementClosedItemsCount(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementClosedPullRequestsCount(increment); + } + return this._incrementClosedIssuesCount(increment); + } + incrementDeletedItemsLabelsCount(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementDeletedPullRequestsLabelsCount(increment); + } + return this._incrementDeletedIssuesLabelsCount(increment); + } + incrementDeletedCloseItemsLabelsCount(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementDeletedClosePullRequestsLabelsCount(increment); + } + return this._incrementDeletedCloseIssuesLabelsCount(increment); + } + incrementDeletedBranchesCount(increment = 1) { + this.deletedBranchesCount += increment; + return this; + } + incrementAddedItemsLabel(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementAddedPullRequestsLabel(increment); + } + return this._incrementAddedIssuesLabel(increment); + } + incrementAddedItemsComment(issue, increment = 1) { + if (issue.isPullRequest) { + return this._incrementAddedPullRequestsComment(increment); + } + return this._incrementAddedIssuesComment(increment); + } + incrementFetchedItemsCount(increment = 1) { + this.fetchedItemsCount += increment; + return this; + } + incrementFetchedItemsEventsCount(increment = 1) { + this.fetchedItemsEventsCount += increment; + return this; + } + incrementFetchedItemsCommentsCount(increment = 1) { + this.fetchedItemsCommentsCount += increment; + return this; + } + incrementFetchedPullRequestsCount(increment = 1) { + this.fetchedPullRequestsCount += increment; + return this; + } + logStats() { + this._logger.info(logger_service_1.LoggerService.yellow(logger_service_1.LoggerService.bold(`Statistics:`))); + this._logProcessedIssuesAndPullRequestsCount(); + this._logStaleIssuesAndPullRequestsCount(); + this._logUndoStaleIssuesAndPullRequestsCount(); + this._logClosedIssuesAndPullRequestsCount(); + this._logDeletedIssuesAndPullRequestsLabelsCount(); + this._logDeletedCloseIssuesAndPullRequestsLabelsCount(); + this._logDeletedBranchesCount(); + this._logAddedIssuesAndPullRequestsLabelsCount(); + this._logAddedIssuesAndPullRequestsCommentsCount(); + this._logFetchedItemsCount(); + this._logFetchedItemsEventsCount(); + this._logFetchedItemsCommentsCount(); + this._logFetchedPullRequestsCount(); + this._logOperationsCount(); + return this; + } + _incrementProcessedIssuesCount(increment = 1) { + this.processedIssuesCount += increment; + return this; + } + _incrementProcessedPullRequestsCount(increment = 1) { + this.processedPullRequestsCount += increment; + return this; + } + _incrementStaleIssuesCount(increment = 1) { + this.staleIssuesCount += increment; + return this; + } + _incrementStalePullRequestsCount(increment = 1) { + this.stalePullRequestsCount += increment; + return this; + } + _incrementUndoStaleIssuesCount(increment = 1) { + this.undoStaleIssuesCount += increment; + return this; + } + _incrementUndoStalePullRequestsCount(increment = 1) { + this.undoStalePullRequestsCount += increment; + return this; + } + _incrementClosedIssuesCount(increment = 1) { + this.closedIssuesCount += increment; + return this; + } + _incrementClosedPullRequestsCount(increment = 1) { + this.closedPullRequestsCount += increment; + return this; + } + _incrementDeletedIssuesLabelsCount(increment = 1) { + this.deletedIssuesLabelsCount += increment; + return this; + } + _incrementDeletedPullRequestsLabelsCount(increment = 1) { + this.deletedPullRequestsLabelsCount += increment; + return this; + } + _incrementDeletedCloseIssuesLabelsCount(increment = 1) { + this.deletedCloseIssuesLabelsCount += increment; + return this; + } + _incrementDeletedClosePullRequestsLabelsCount(increment = 1) { + this.deletedClosePullRequestsLabelsCount += increment; + return this; + } + _incrementAddedIssuesLabel(increment = 1) { + this.addedIssuesLabelsCount += increment; + return this; + } + _incrementAddedPullRequestsLabel(increment = 1) { + this.addedPullRequestsLabelsCount += increment; + return this; + } + _incrementAddedIssuesComment(increment = 1) { + this.addedIssuesCommentsCount += increment; + return this; + } + _incrementAddedPullRequestsComment(increment = 1) { + this.addedPullRequestsCommentsCount += increment; + return this; + } + _logProcessedIssuesAndPullRequestsCount() { + this._logGroup('Processed items', [ + { + name: 'Processed issues', + count: this.processedIssuesCount + }, + { + name: 'Processed PRs', + count: this.processedPullRequestsCount + } + ]); + } + _logStaleIssuesAndPullRequestsCount() { + this._logGroup('New stale items', [ + { + name: 'New stale issues', + count: this.staleIssuesCount + }, + { + name: 'New stale PRs', + count: this.stalePullRequestsCount + } + ]); + } + _logUndoStaleIssuesAndPullRequestsCount() { + this._logGroup('No longer stale items', [ + { + name: 'No longer stale issues', + count: this.undoStaleIssuesCount + }, + { + name: 'No longer stale PRs', + count: this.undoStalePullRequestsCount + } + ]); + } + _logClosedIssuesAndPullRequestsCount() { + this._logGroup('Closed items', [ + { + name: 'Closed issues', + count: this.closedIssuesCount + }, + { + name: 'Closed PRs', + count: this.closedPullRequestsCount + } + ]); + } + _logDeletedIssuesAndPullRequestsLabelsCount() { + this._logGroup('Deleted items labels', [ + { + name: 'Deleted issues labels', + count: this.deletedIssuesLabelsCount + }, + { + name: 'Deleted PRs labels', + count: this.deletedPullRequestsLabelsCount + } + ]); + } + _logDeletedCloseIssuesAndPullRequestsLabelsCount() { + this._logGroup('Deleted close items labels', [ + { + name: 'Deleted close issues labels', + count: this.deletedCloseIssuesLabelsCount + }, + { + name: 'Deleted close PRs labels', + count: this.deletedClosePullRequestsLabelsCount + } + ]); + } + _logDeletedBranchesCount() { + this._logCount('Deleted branches', this.deletedBranchesCount); + } + _logAddedIssuesAndPullRequestsLabelsCount() { + this._logGroup('Added items labels', [ + { + name: 'Added issues labels', + count: this.addedIssuesLabelsCount + }, + { + name: 'Added PRs labels', + count: this.addedPullRequestsLabelsCount + } + ]); + } + _logAddedIssuesAndPullRequestsCommentsCount() { + this._logGroup('Added items comments', [ + { + name: 'Added issues comments', + count: this.addedIssuesCommentsCount + }, + { + name: 'Added PRs comments', + count: this.addedPullRequestsCommentsCount + } + ]); + } + _logFetchedItemsCount() { + this._logCount('Fetched items', this.fetchedItemsCount); + } + _logFetchedItemsEventsCount() { + this._logCount('Fetched items events', this.fetchedItemsEventsCount); + } + _logFetchedItemsCommentsCount() { + this._logCount('Fetched items comments', this.fetchedItemsCommentsCount); + } + _logFetchedPullRequestsCount() { + this._logCount('Fetched pull requests', this.fetchedPullRequestsCount); + } + _logOperationsCount() { + this._logCount('Operations performed', this.operationsCount); + } + _logCount(name, count) { + if (count > 0) { + this._logger.info(`${name}:`, logger_service_1.LoggerService.cyan(count)); + } + } + _logGroup(groupName, values) { + if (this._isGroupValuesPartiallySet(values)) { + this._logCount(groupName, this._getGroupValuesTotalCount(values)); + this._logGroupValues(values); + } + else { + // Only one value will be display + for (const value of values) { + this._logCount(value.name, value.count); + } + } + } + /** + * @private + * @description + * If there is a least two elements with a valid count then it's partially set + * Useful to defined if we should display the values as a group or not + * + * @param {IGroupValue[]} values The list of group values to check + */ + _isGroupValuesPartiallySet(values) { + return (values + .map((value) => { + return value.count > 0; + }) + .filter((isSet) => isSet).length >= 2); + } + _getGroupValuesTotalCount(values) { + return values.reduce((count, value) => { + return count + value.count; + }, 0); + } + _getAllGroupValuesSet(values) { + return values.filter((value) => { + return value.count > 0; + }); + } + _logGroupValues(values) { + const onlyValuesSet = this._getAllGroupValuesSet(values); + const longestValue = this._getLongestGroupValue(onlyValuesSet); + for (const [index, value] of onlyValuesSet.entries()) { + const prefix = index === onlyValuesSet.length - 1 ? '└──' : '├──'; + this._logCount(`${logger_service_1.LoggerService.white(prefix)} ${value.name.padEnd(longestValue, ' ')}`, value.count); + } + } + _getLongestGroupValue(values) { + return values.reduce((longestValue, value) => { + return value.name.length > longestValue + ? value.name.length + : longestValue; + }, 0); + } +} +exports.Statistics = Statistics; /***/ }), @@ -1852,61 +1849,61 @@ exports.Statistics = Statistics; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Option = void 0; -var Option; -(function (Option) { - Option["RepoToken"] = "repo-token"; - Option["StaleIssueMessage"] = "stale-issue-message"; - Option["StalePrMessage"] = "stale-pr-message"; - Option["CloseIssueMessage"] = "close-issue-message"; - Option["ClosePrMessage"] = "close-pr-message"; - Option["DaysBeforeStale"] = "days-before-stale"; - Option["DaysBeforeIssueStale"] = "days-before-issue-stale"; - Option["DaysBeforePrStale"] = "days-before-pr-stale"; - Option["DaysBeforeClose"] = "days-before-close"; - Option["DaysBeforeIssueClose"] = "days-before-issue-close"; - Option["DaysBeforePrClose"] = "days-before-pr-close"; - Option["StaleIssueLabel"] = "stale-issue-label"; - Option["CloseIssueLabel"] = "close-issue-label"; - Option["ExemptIssueLabels"] = "exempt-issue-labels"; - Option["StalePrLabel"] = "stale-pr-label"; - Option["ClosePrLabel"] = "close-pr-label"; - Option["ExemptPrLabels"] = "exempt-pr-labels"; - Option["OnlyLabels"] = "only-labels"; - Option["OnlyIssueLabels"] = "only-issue-labels"; - Option["OnlyPrLabels"] = "only-pr-labels"; - Option["AnyOfLabels"] = "any-of-labels"; - Option["OperationsPerRun"] = "operations-per-run"; - Option["RemoveStaleWhenUpdated"] = "remove-stale-when-updated"; - Option["RemoveIssueStaleWhenUpdated"] = "remove-issue-stale-when-updated"; - Option["RemovePrStaleWhenUpdated"] = "remove-pr-stale-when-updated"; - Option["DebugOnly"] = "debug-only"; - Option["Ascending"] = "ascending"; - Option["DeleteBranch"] = "delete-branch"; - Option["StartDate"] = "start-date"; - Option["ExemptMilestones"] = "exempt-milestones"; - Option["ExemptIssueMilestones"] = "exempt-issue-milestones"; - Option["ExemptPrMilestones"] = "exempt-pr-milestones"; - Option["ExemptAllMilestones"] = "exempt-all-milestones"; - Option["ExemptAllIssueMilestones"] = "exempt-all-issue-milestones"; - Option["ExemptAllPrMilestones"] = "exempt-all-pr-milestones"; - Option["ExemptAssignees"] = "exempt-assignees"; - Option["ExemptIssueAssignees"] = "exempt-issue-assignees"; - Option["ExemptPrAssignees"] = "exempt-pr-assignees"; - Option["ExemptAllAssignees"] = "exempt-all-assignees"; - Option["ExemptAllIssueAssignees"] = "exempt-all-issue-assignees"; - Option["ExemptAllPrAssignees"] = "exempt-all-pr-assignees"; - Option["EnableStatistics"] = "enable-statistics"; - Option["LabelsToRemoveWhenUnstale"] = "labels-to-remove-when-unstale"; - Option["LabelsToAddWhenUnstale"] = "labels-to-add-when-unstale"; - Option["IgnoreUpdates"] = "ignore-updates"; - Option["IgnoreIssueUpdates"] = "ignore-issue-updates"; - Option["IgnorePrUpdates"] = "ignore-pr-updates"; - Option["ExemptDraftPr"] = "exempt-draft-pr"; - Option["CloseIssueReason"] = "close-issue-reason"; -})(Option = exports.Option || (exports.Option = {})); + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Option = void 0; +var Option; +(function (Option) { + Option["RepoToken"] = "repo-token"; + Option["StaleIssueMessage"] = "stale-issue-message"; + Option["StalePrMessage"] = "stale-pr-message"; + Option["CloseIssueMessage"] = "close-issue-message"; + Option["ClosePrMessage"] = "close-pr-message"; + Option["DaysBeforeStale"] = "days-before-stale"; + Option["DaysBeforeIssueStale"] = "days-before-issue-stale"; + Option["DaysBeforePrStale"] = "days-before-pr-stale"; + Option["DaysBeforeClose"] = "days-before-close"; + Option["DaysBeforeIssueClose"] = "days-before-issue-close"; + Option["DaysBeforePrClose"] = "days-before-pr-close"; + Option["StaleIssueLabel"] = "stale-issue-label"; + Option["CloseIssueLabel"] = "close-issue-label"; + Option["ExemptIssueLabels"] = "exempt-issue-labels"; + Option["StalePrLabel"] = "stale-pr-label"; + Option["ClosePrLabel"] = "close-pr-label"; + Option["ExemptPrLabels"] = "exempt-pr-labels"; + Option["OnlyLabels"] = "only-labels"; + Option["OnlyIssueLabels"] = "only-issue-labels"; + Option["OnlyPrLabels"] = "only-pr-labels"; + Option["AnyOfLabels"] = "any-of-labels"; + Option["OperationsPerRun"] = "operations-per-run"; + Option["RemoveStaleWhenUpdated"] = "remove-stale-when-updated"; + Option["RemoveIssueStaleWhenUpdated"] = "remove-issue-stale-when-updated"; + Option["RemovePrStaleWhenUpdated"] = "remove-pr-stale-when-updated"; + Option["DebugOnly"] = "debug-only"; + Option["Ascending"] = "ascending"; + Option["DeleteBranch"] = "delete-branch"; + Option["StartDate"] = "start-date"; + Option["ExemptMilestones"] = "exempt-milestones"; + Option["ExemptIssueMilestones"] = "exempt-issue-milestones"; + Option["ExemptPrMilestones"] = "exempt-pr-milestones"; + Option["ExemptAllMilestones"] = "exempt-all-milestones"; + Option["ExemptAllIssueMilestones"] = "exempt-all-issue-milestones"; + Option["ExemptAllPrMilestones"] = "exempt-all-pr-milestones"; + Option["ExemptAssignees"] = "exempt-assignees"; + Option["ExemptIssueAssignees"] = "exempt-issue-assignees"; + Option["ExemptPrAssignees"] = "exempt-pr-assignees"; + Option["ExemptAllAssignees"] = "exempt-all-assignees"; + Option["ExemptAllIssueAssignees"] = "exempt-all-issue-assignees"; + Option["ExemptAllPrAssignees"] = "exempt-all-pr-assignees"; + Option["EnableStatistics"] = "enable-statistics"; + Option["LabelsToRemoveWhenUnstale"] = "labels-to-remove-when-unstale"; + Option["LabelsToAddWhenUnstale"] = "labels-to-add-when-unstale"; + Option["IgnoreUpdates"] = "ignore-updates"; + Option["IgnoreIssueUpdates"] = "ignore-issue-updates"; + Option["IgnorePrUpdates"] = "ignore-pr-updates"; + Option["ExemptDraftPr"] = "exempt-draft-pr"; + Option["CloseIssueReason"] = "close-issue-reason"; +})(Option = exports.Option || (exports.Option = {})); /***/ }), @@ -1915,25 +1912,25 @@ var Option; /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.cleanLabel = void 0; -const lodash_deburr_1 = __importDefault(__nccwpck_require__(1601)); -/** - * @description - * Clean a label by lowercasing it and deburring it for consistency - * - * @param {string} label A raw GitHub label - * - * @return {string} A lowercased, deburred version of the passed in label - */ -function cleanLabel(label) { - return lodash_deburr_1.default(label === null || label === void 0 ? void 0 : label.toLowerCase()); -} -exports.cleanLabel = cleanLabel; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.cleanLabel = void 0; +const lodash_deburr_1 = __importDefault(__nccwpck_require__(1601)); +/** + * @description + * Clean a label by lowercasing it and deburring it for consistency + * + * @param {string} label A raw GitHub label + * + * @return {string} A lowercased, deburred version of the passed in label + */ +function cleanLabel(label) { + return lodash_deburr_1.default(label === null || label === void 0 ? void 0 : label.toLowerCase()); +} +exports.cleanLabel = cleanLabel; /***/ }), @@ -1942,22 +1939,22 @@ exports.cleanLabel = cleanLabel; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getHumanizedDate = void 0; -function getHumanizedDate(date) { - const year = date.getFullYear(); - let month = `${date.getMonth() + 1}`; - let day = `${date.getDate()}`; - if (month.length < 2) { - month = `0${month}`; - } - if (day.length < 2) { - day = `0${day}`; - } - return [day, month, year].join('-'); -} -exports.getHumanizedDate = getHumanizedDate; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getHumanizedDate = void 0; +function getHumanizedDate(date) { + const year = date.getFullYear(); + let month = `${date.getMonth() + 1}`; + let day = `${date.getDate()}`; + if (month.length < 2) { + month = `0${month}`; + } + if (day.length < 2) { + day = `0${day}`; + } + return [day, month, year].join('-'); +} +exports.getHumanizedDate = getHumanizedDate; /***/ }), @@ -1966,26 +1963,26 @@ exports.getHumanizedDate = getHumanizedDate; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -/// returns false if the dates are equal within the `equalityToleranceInSeconds` number of seconds -/// otherwise returns true if `comparedDate` is after `date` -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isDateEqualTo = exports.isDateMoreRecentThan = void 0; -function isDateMoreRecentThan(date, comparedDate, equalityToleranceInSeconds = 0) { - if (equalityToleranceInSeconds > 0) { - const areDatesEqual = isDateEqualTo(date, comparedDate, equalityToleranceInSeconds); - return !areDatesEqual && date > comparedDate; - } - return date > comparedDate; -} -exports.isDateMoreRecentThan = isDateMoreRecentThan; -function isDateEqualTo(date, otherDate, toleranceInSeconds) { - const timestamp = date.getTime(); - const otherTimestamp = otherDate.getTime(); - const deltaInSeconds = Math.abs(timestamp - otherTimestamp) / 1000; - return deltaInSeconds <= toleranceInSeconds; -} -exports.isDateEqualTo = isDateEqualTo; + +/// returns false if the dates are equal within the `equalityToleranceInSeconds` number of seconds +/// otherwise returns true if `comparedDate` is after `date` +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isDateEqualTo = exports.isDateMoreRecentThan = void 0; +function isDateMoreRecentThan(date, comparedDate, equalityToleranceInSeconds = 0) { + if (equalityToleranceInSeconds > 0) { + const areDatesEqual = isDateEqualTo(date, comparedDate, equalityToleranceInSeconds); + return !areDatesEqual && date > comparedDate; + } + return date > comparedDate; +} +exports.isDateMoreRecentThan = isDateMoreRecentThan; +function isDateEqualTo(date, otherDate, toleranceInSeconds) { + const timestamp = date.getTime(); + const otherTimestamp = otherDate.getTime(); + const deltaInSeconds = Math.abs(timestamp - otherTimestamp) / 1000; + return deltaInSeconds <= toleranceInSeconds; +} +exports.isDateEqualTo = isDateEqualTo; /***/ }), @@ -1994,27 +1991,27 @@ exports.isDateEqualTo = isDateEqualTo; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isValidDate = void 0; -/** - * @description - * Check if a date is valid - * - * @see - * https://stackoverflow.com/a/1353711/4440414 - * - * @param {Readonly} date The date to check - * - * @returns {boolean} true when the given date is valid - */ -function isValidDate(date) { - if (Object.prototype.toString.call(date) === '[object Date]') { - return !isNaN(date.getTime()); - } - return false; -} -exports.isValidDate = isValidDate; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isValidDate = void 0; +/** + * @description + * Check if a date is valid + * + * @see + * https://stackoverflow.com/a/1353711/4440414 + * + * @param {Readonly} date The date to check + * + * @returns {boolean} true when the given date is valid + */ +function isValidDate(date) { + if (Object.prototype.toString.call(date) === '[object Date]') { + return !isNaN(date.getTime()); + } + return false; +} +exports.isValidDate = isValidDate; /***/ }), @@ -2023,13 +2020,13 @@ exports.isValidDate = isValidDate; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isBoolean = void 0; -function isBoolean(value) { - return value === true || value === false; -} -exports.isBoolean = isBoolean; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isBoolean = void 0; +function isBoolean(value) { + return value === true || value === false; +} +exports.isBoolean = isBoolean; /***/ }), @@ -2038,25 +2035,25 @@ exports.isBoolean = isBoolean; /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isLabeled = void 0; -const clean_label_1 = __nccwpck_require__(7752); -/** - * @description - * Check if the given label is listed as a label of the given issue - * - * @param {Readonly} issue A GitHub issue containing some labels - * @param {Readonly} label The label to check the presence with - * - * @return {boolean} Return true when the given label is also in the given issue labels - */ -function isLabeled(issue, label) { - return !!issue.labels.find((issueLabel) => { - return clean_label_1.cleanLabel(label) === clean_label_1.cleanLabel(issueLabel.name); - }); -} -exports.isLabeled = isLabeled; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isLabeled = void 0; +const clean_label_1 = __nccwpck_require__(7752); +/** + * @description + * Check if the given label is listed as a label of the given issue + * + * @param {Readonly} issue A GitHub issue containing some labels + * @param {Readonly} label The label to check the presence with + * + * @return {boolean} Return true when the given label is also in the given issue labels + */ +function isLabeled(issue, label) { + return !!issue.labels.find((issueLabel) => { + return clean_label_1.cleanLabel(label) === clean_label_1.cleanLabel(issueLabel.name); + }); +} +exports.isLabeled = isLabeled; /***/ }), @@ -2065,13 +2062,13 @@ exports.isLabeled = isLabeled; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isPullRequest = void 0; -function isPullRequest(issue) { - return !!issue.pull_request; -} -exports.isPullRequest = isPullRequest; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isPullRequest = void 0; +function isPullRequest(issue) { + return !!issue.pull_request; +} +exports.isPullRequest = isPullRequest; /***/ }), @@ -2080,13 +2077,13 @@ exports.isPullRequest = isPullRequest; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.shouldMarkWhenStale = void 0; -function shouldMarkWhenStale(daysBeforeStale) { - return daysBeforeStale >= 0; -} -exports.shouldMarkWhenStale = shouldMarkWhenStale; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.shouldMarkWhenStale = void 0; +function shouldMarkWhenStale(daysBeforeStale) { + return daysBeforeStale >= 0; +} +exports.shouldMarkWhenStale = shouldMarkWhenStale; /***/ }), @@ -2095,32 +2092,32 @@ exports.shouldMarkWhenStale = shouldMarkWhenStale; /***/ ((__unused_webpack_module, exports) => { "use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.wordsToList = void 0; -/** - * @description - * Transform a string of comma separated words - * to an array of words - * - * @example - * wordsToList('label') => ['label'] - * wordsToList('label,label') => ['label', 'label'] - * wordsToList('kebab-label') => ['kebab-label'] - * wordsToList('kebab%20label') => ['kebab%20label'] - * wordsToList('label with words') => ['label with words'] - * - * @param {Readonly} words A string of comma separated words - * - * @return {string[]} A list of words - */ -function wordsToList(words) { - if (!words.length) { - return []; - } - return words.split(',').map((word) => word.trim()); -} -exports.wordsToList = wordsToList; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.wordsToList = void 0; +/** + * @description + * Transform a string of comma separated words + * to an array of words + * + * @example + * wordsToList('label') => ['label'] + * wordsToList('label,label') => ['label', 'label'] + * wordsToList('kebab-label') => ['kebab-label'] + * wordsToList('kebab%20label') => ['kebab%20label'] + * wordsToList('label with words') => ['label with words'] + * + * @param {Readonly} words A string of comma separated words + * + * @return {string[]} A list of words + */ +function wordsToList(words) { + if (!words.length) { + return []; + } + return words.split(',').map((word) => word.trim()); +} +exports.wordsToList = wordsToList; /***/ }), @@ -2129,170 +2126,170 @@ exports.wordsToList = wordsToList; /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -const core = __importStar(__nccwpck_require__(2186)); -const issues_processor_1 = __nccwpck_require__(3292); -const is_valid_date_1 = __nccwpck_require__(891); -function _run() { - return __awaiter(this, void 0, void 0, function* () { - try { - const args = _getAndValidateArgs(); - const issueProcessor = new issues_processor_1.IssuesProcessor(args); - yield issueProcessor.processIssues(); - yield processOutput(issueProcessor.staleIssues, issueProcessor.closedIssues); - } - catch (error) { - core.error(error); - core.setFailed(error.message); - } - }); -} -function _getAndValidateArgs() { - const args = { - repoToken: core.getInput('repo-token'), - staleIssueMessage: core.getInput('stale-issue-message'), - stalePrMessage: core.getInput('stale-pr-message'), - closeIssueMessage: core.getInput('close-issue-message'), - closePrMessage: core.getInput('close-pr-message'), - daysBeforeStale: parseFloat(core.getInput('days-before-stale', { required: true })), - daysBeforeIssueStale: parseFloat(core.getInput('days-before-issue-stale')), - daysBeforePrStale: parseFloat(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 })), - removeStaleWhenUpdated: !(core.getInput('remove-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', - deleteBranch: core.getInput('delete-branch') === 'true', - startDate: 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'), - 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'), - 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'), - ignoreUpdates: core.getInput('ignore-updates') === 'true', - ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'), - ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'), - exemptDraftPr: core.getInput('exempt-draft-pr') === 'true', - closeIssueReason: core.getInput('close-issue-reason'), - includeOnlyAssigned: core.getInput('include-only-assigned') === 'true' - }; - for (const numberInput of ['days-before-stale']) { - if (isNaN(parseFloat(core.getInput(numberInput)))) { - const errorMessage = `Option "${numberInput}" did not parse to a valid float`; - core.setFailed(errorMessage); - throw new Error(errorMessage); - } - } - for (const numberInput of ['days-before-close', 'operations-per-run']) { - if (isNaN(parseInt(core.getInput(numberInput)))) { - const errorMessage = `Option "${numberInput}" did not parse to a valid integer`; - core.setFailed(errorMessage); - throw new Error(errorMessage); - } - } - for (const optionalDateInput of ['start-date']) { - // Ignore empty dates because it is considered as the right type for a default value (so a valid one) - if (core.getInput(optionalDateInput) !== '') { - if (!is_valid_date_1.isValidDate(new Date(core.getInput(optionalDateInput)))) { - const errorMessage = `Option "${optionalDateInput}" did not parse to a valid date`; - core.setFailed(errorMessage); - throw new Error(errorMessage); - } - } - } - const validCloseReasons = ['', 'completed', 'not_planned']; - if (!validCloseReasons.includes(args.closeIssueReason)) { - const errorMessage = `Unrecognized close-issue-reason "${args.closeIssueReason}", valid values are: ${validCloseReasons.filter(Boolean).join(', ')}`; - core.setFailed(errorMessage); - throw new Error(errorMessage); - } - return args; -} -function processOutput(staledIssues, closedIssues) { - return __awaiter(this, void 0, void 0, function* () { - core.setOutput('staled-issues-prs', JSON.stringify(staledIssues)); - 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} argumentName The name of the argument to check - * - * @returns {boolean | undefined} The value matching the given argument name - */ -function _toOptionalBoolean(argumentName) { - const argument = core.getInput(argumentName); - if (argument === 'true') { - return true; - } - else if (argument === 'false') { - return false; - } - return undefined; -} -void _run(); + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +const core = __importStar(__nccwpck_require__(2186)); +const issues_processor_1 = __nccwpck_require__(3292); +const is_valid_date_1 = __nccwpck_require__(891); +function _run() { + return __awaiter(this, void 0, void 0, function* () { + try { + const args = _getAndValidateArgs(); + const issueProcessor = new issues_processor_1.IssuesProcessor(args); + yield issueProcessor.processIssues(); + yield processOutput(issueProcessor.staleIssues, issueProcessor.closedIssues); + } + catch (error) { + core.error(error); + core.setFailed(error.message); + } + }); +} +function _getAndValidateArgs() { + const args = { + repoToken: core.getInput('repo-token'), + staleIssueMessage: core.getInput('stale-issue-message'), + stalePrMessage: core.getInput('stale-pr-message'), + closeIssueMessage: core.getInput('close-issue-message'), + closePrMessage: core.getInput('close-pr-message'), + daysBeforeStale: parseFloat(core.getInput('days-before-stale', { required: true })), + daysBeforeIssueStale: parseFloat(core.getInput('days-before-issue-stale')), + daysBeforePrStale: parseFloat(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 })), + removeStaleWhenUpdated: !(core.getInput('remove-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', + deleteBranch: core.getInput('delete-branch') === 'true', + startDate: 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'), + 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'), + 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'), + ignoreUpdates: core.getInput('ignore-updates') === 'true', + ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'), + ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'), + exemptDraftPr: core.getInput('exempt-draft-pr') === 'true', + closeIssueReason: core.getInput('close-issue-reason'), + includeOnlyAssigned: core.getInput('include-only-assigned') === 'true' + }; + for (const numberInput of ['days-before-stale']) { + if (isNaN(parseFloat(core.getInput(numberInput)))) { + const errorMessage = `Option "${numberInput}" did not parse to a valid float`; + core.setFailed(errorMessage); + throw new Error(errorMessage); + } + } + for (const numberInput of ['days-before-close', 'operations-per-run']) { + if (isNaN(parseInt(core.getInput(numberInput)))) { + const errorMessage = `Option "${numberInput}" did not parse to a valid integer`; + core.setFailed(errorMessage); + throw new Error(errorMessage); + } + } + for (const optionalDateInput of ['start-date']) { + // Ignore empty dates because it is considered as the right type for a default value (so a valid one) + if (core.getInput(optionalDateInput) !== '') { + if (!is_valid_date_1.isValidDate(new Date(core.getInput(optionalDateInput)))) { + const errorMessage = `Option "${optionalDateInput}" did not parse to a valid date`; + core.setFailed(errorMessage); + throw new Error(errorMessage); + } + } + } + const validCloseReasons = ['', 'completed', 'not_planned']; + if (!validCloseReasons.includes(args.closeIssueReason)) { + const errorMessage = `Unrecognized close-issue-reason "${args.closeIssueReason}", valid values are: ${validCloseReasons.filter(Boolean).join(', ')}`; + core.setFailed(errorMessage); + throw new Error(errorMessage); + } + return args; +} +function processOutput(staledIssues, closedIssues) { + return __awaiter(this, void 0, void 0, function* () { + core.setOutput('staled-issues-prs', JSON.stringify(staledIssues)); + 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} argumentName The name of the argument to check + * + * @returns {boolean | undefined} The value matching the given argument name + */ +function _toOptionalBoolean(argumentName) { + const argument = core.getInput(argumentName); + if (argument === 'true') { + return true; + } + else if (argument === 'false') { + return false; + } + return undefined; +} +void _run(); /***/ }), @@ -2301,49 +2298,49 @@ void _run(); /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.LoggerService = void 0; -const ansi_styles_1 = __importDefault(__nccwpck_require__(2068)); -class LoggerService { - static whiteBright(message) { - return this._format(message, 'whiteBright'); - } - static yellowBright(message) { - return this._format(message, 'yellowBright'); - } - static magenta(message) { - return this._format(message, 'magenta'); - } - static cyan(message) { - return this._format(message, 'cyan'); - } - static yellow(message) { - return this._format(message, 'yellow'); - } - static white(message) { - return this._format(message, 'white'); - } - static green(message) { - return this._format(message, 'green'); - } - static red(message) { - return this._format(message, 'red'); - } - static blue(message) { - return this._format(message, 'blue'); - } - static bold(message) { - return this._format(message, 'bold'); - } - static _format(message, style) { - return `${ansi_styles_1.default[style].open}${message}${ansi_styles_1.default[style].close}`; - } -} -exports.LoggerService = LoggerService; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.LoggerService = void 0; +const ansi_styles_1 = __importDefault(__nccwpck_require__(2068)); +class LoggerService { + static whiteBright(message) { + return this._format(message, 'whiteBright'); + } + static yellowBright(message) { + return this._format(message, 'yellowBright'); + } + static magenta(message) { + return this._format(message, 'magenta'); + } + static cyan(message) { + return this._format(message, 'cyan'); + } + static yellow(message) { + return this._format(message, 'yellow'); + } + static white(message) { + return this._format(message, 'white'); + } + static green(message) { + return this._format(message, 'green'); + } + static red(message) { + return this._format(message, 'red'); + } + static blue(message) { + return this._format(message, 'blue'); + } + static bold(message) { + return this._format(message, 'bold'); + } + static _format(message, style) { + return `${ansi_styles_1.default[style].open}${message}${ansi_styles_1.default[style].close}`; + } +} +exports.LoggerService = LoggerService; /***/ }), @@ -10621,1303 +10618,1303 @@ exports.parseURL = __nccwpck_require__(33).parseURL; /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; - -const punycode = __nccwpck_require__(4213); -const tr46 = __nccwpck_require__(2299); - -const specialSchemes = { - ftp: 21, - file: null, - gopher: 70, - http: 80, - https: 443, - ws: 80, - wss: 443 -}; - -const failure = Symbol("failure"); - -function countSymbols(str) { - return punycode.ucs2.decode(str).length; -} - -function at(input, idx) { - const c = input[idx]; - return isNaN(c) ? undefined : String.fromCodePoint(c); -} - -function isASCIIDigit(c) { - return c >= 0x30 && c <= 0x39; -} - -function isASCIIAlpha(c) { - return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); -} - -function isASCIIAlphanumeric(c) { - return isASCIIAlpha(c) || isASCIIDigit(c); -} - -function isASCIIHex(c) { - return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); -} - -function isSingleDot(buffer) { - return buffer === "." || buffer.toLowerCase() === "%2e"; -} - -function isDoubleDot(buffer) { - buffer = buffer.toLowerCase(); - return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e"; -} - -function isWindowsDriveLetterCodePoints(cp1, cp2) { - return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124); -} - -function isWindowsDriveLetterString(string) { - return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|"); -} - -function isNormalizedWindowsDriveLetterString(string) { - return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":"; -} - -function containsForbiddenHostCodePoint(string) { - return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1; -} - -function containsForbiddenHostCodePointExcludingPercent(string) { - return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1; -} - -function isSpecialScheme(scheme) { - return specialSchemes[scheme] !== undefined; -} - -function isSpecial(url) { - return isSpecialScheme(url.scheme); -} - -function defaultPort(scheme) { - return specialSchemes[scheme]; -} - -function percentEncode(c) { - let hex = c.toString(16).toUpperCase(); - if (hex.length === 1) { - hex = "0" + hex; - } - - return "%" + hex; -} - -function utf8PercentEncode(c) { - const buf = new Buffer(c); - - let str = ""; - - for (let i = 0; i < buf.length; ++i) { - str += percentEncode(buf[i]); - } - - return str; -} - -function utf8PercentDecode(str) { - const input = new Buffer(str); - const output = []; - for (let i = 0; i < input.length; ++i) { - if (input[i] !== 37) { - output.push(input[i]); - } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) { - output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16)); - i += 2; - } else { - output.push(input[i]); - } - } - return new Buffer(output).toString(); -} - -function isC0ControlPercentEncode(c) { - return c <= 0x1F || c > 0x7E; -} - -const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]); -function isPathPercentEncode(c) { - return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c); -} - -const extraUserinfoPercentEncodeSet = - new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]); -function isUserinfoPercentEncode(c) { - return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c); -} - -function percentEncodeChar(c, encodeSetPredicate) { - const cStr = String.fromCodePoint(c); - - if (encodeSetPredicate(c)) { - return utf8PercentEncode(cStr); - } - - return cStr; -} - -function parseIPv4Number(input) { - let R = 10; - - if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") { - input = input.substring(2); - R = 16; - } else if (input.length >= 2 && input.charAt(0) === "0") { - input = input.substring(1); - R = 8; - } - - if (input === "") { - return 0; - } - - const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/); - if (regex.test(input)) { - return failure; - } - - return parseInt(input, R); -} - -function parseIPv4(input) { - const parts = input.split("."); - if (parts[parts.length - 1] === "") { - if (parts.length > 1) { - parts.pop(); - } - } - - if (parts.length > 4) { - return input; - } - - const numbers = []; - for (const part of parts) { - if (part === "") { - return input; - } - const n = parseIPv4Number(part); - if (n === failure) { - return input; - } - - numbers.push(n); - } - - for (let i = 0; i < numbers.length - 1; ++i) { - if (numbers[i] > 255) { - return failure; - } - } - if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) { - return failure; - } - - let ipv4 = numbers.pop(); - let counter = 0; - - for (const n of numbers) { - ipv4 += n * Math.pow(256, 3 - counter); - ++counter; - } - - return ipv4; -} - -function serializeIPv4(address) { - let output = ""; - let n = address; - - for (let i = 1; i <= 4; ++i) { - output = String(n % 256) + output; - if (i !== 4) { - output = "." + output; - } - n = Math.floor(n / 256); - } - - return output; -} - -function parseIPv6(input) { - const address = [0, 0, 0, 0, 0, 0, 0, 0]; - let pieceIndex = 0; - let compress = null; - let pointer = 0; - - input = punycode.ucs2.decode(input); - - if (input[pointer] === 58) { - if (input[pointer + 1] !== 58) { - return failure; - } - - pointer += 2; - ++pieceIndex; - compress = pieceIndex; - } - - while (pointer < input.length) { - if (pieceIndex === 8) { - return failure; - } - - if (input[pointer] === 58) { - if (compress !== null) { - return failure; - } - ++pointer; - ++pieceIndex; - compress = pieceIndex; - continue; - } - - let value = 0; - let length = 0; - - while (length < 4 && isASCIIHex(input[pointer])) { - value = value * 0x10 + parseInt(at(input, pointer), 16); - ++pointer; - ++length; - } - - if (input[pointer] === 46) { - if (length === 0) { - return failure; - } - - pointer -= length; - - if (pieceIndex > 6) { - return failure; - } - - let numbersSeen = 0; - - while (input[pointer] !== undefined) { - let ipv4Piece = null; - - if (numbersSeen > 0) { - if (input[pointer] === 46 && numbersSeen < 4) { - ++pointer; - } else { - return failure; - } - } - - if (!isASCIIDigit(input[pointer])) { - return failure; - } - - while (isASCIIDigit(input[pointer])) { - const number = parseInt(at(input, pointer)); - if (ipv4Piece === null) { - ipv4Piece = number; - } else if (ipv4Piece === 0) { - return failure; - } else { - ipv4Piece = ipv4Piece * 10 + number; - } - if (ipv4Piece > 255) { - return failure; - } - ++pointer; - } - - address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece; - - ++numbersSeen; - - if (numbersSeen === 2 || numbersSeen === 4) { - ++pieceIndex; - } - } - - if (numbersSeen !== 4) { - return failure; - } - - break; - } else if (input[pointer] === 58) { - ++pointer; - if (input[pointer] === undefined) { - return failure; - } - } else if (input[pointer] !== undefined) { - return failure; - } - - address[pieceIndex] = value; - ++pieceIndex; - } - - if (compress !== null) { - let swaps = pieceIndex - compress; - pieceIndex = 7; - while (pieceIndex !== 0 && swaps > 0) { - const temp = address[compress + swaps - 1]; - address[compress + swaps - 1] = address[pieceIndex]; - address[pieceIndex] = temp; - --pieceIndex; - --swaps; - } - } else if (compress === null && pieceIndex !== 8) { - return failure; - } - - return address; -} - -function serializeIPv6(address) { - let output = ""; - const seqResult = findLongestZeroSequence(address); - const compress = seqResult.idx; - let ignore0 = false; - - for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) { - if (ignore0 && address[pieceIndex] === 0) { - continue; - } else if (ignore0) { - ignore0 = false; - } - - if (compress === pieceIndex) { - const separator = pieceIndex === 0 ? "::" : ":"; - output += separator; - ignore0 = true; - continue; - } - - output += address[pieceIndex].toString(16); - - if (pieceIndex !== 7) { - output += ":"; - } - } - - return output; -} - -function parseHost(input, isSpecialArg) { - if (input[0] === "[") { - if (input[input.length - 1] !== "]") { - return failure; - } - - return parseIPv6(input.substring(1, input.length - 1)); - } - - if (!isSpecialArg) { - return parseOpaqueHost(input); - } - - const domain = utf8PercentDecode(input); - const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false); - if (asciiDomain === null) { - return failure; - } - - if (containsForbiddenHostCodePoint(asciiDomain)) { - return failure; - } - - const ipv4Host = parseIPv4(asciiDomain); - if (typeof ipv4Host === "number" || ipv4Host === failure) { - return ipv4Host; - } - - return asciiDomain; -} - -function parseOpaqueHost(input) { - if (containsForbiddenHostCodePointExcludingPercent(input)) { - return failure; - } - - let output = ""; - const decoded = punycode.ucs2.decode(input); - for (let i = 0; i < decoded.length; ++i) { - output += percentEncodeChar(decoded[i], isC0ControlPercentEncode); - } - return output; -} - -function findLongestZeroSequence(arr) { - let maxIdx = null; - let maxLen = 1; // only find elements > 1 - let currStart = null; - let currLen = 0; - - for (let i = 0; i < arr.length; ++i) { - if (arr[i] !== 0) { - if (currLen > maxLen) { - maxIdx = currStart; - maxLen = currLen; - } - - currStart = null; - currLen = 0; - } else { - if (currStart === null) { - currStart = i; - } - ++currLen; - } - } - - // if trailing zeros - if (currLen > maxLen) { - maxIdx = currStart; - maxLen = currLen; - } - - return { - idx: maxIdx, - len: maxLen - }; -} - -function serializeHost(host) { - if (typeof host === "number") { - return serializeIPv4(host); - } - - // IPv6 serializer - if (host instanceof Array) { - return "[" + serializeIPv6(host) + "]"; - } - - return host; -} - -function trimControlChars(url) { - return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, ""); -} - -function trimTabAndNewline(url) { - return url.replace(/\u0009|\u000A|\u000D/g, ""); -} - -function shortenPath(url) { - const path = url.path; - if (path.length === 0) { - return; - } - if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) { - return; - } - - path.pop(); -} - -function includesCredentials(url) { - return url.username !== "" || url.password !== ""; -} - -function cannotHaveAUsernamePasswordPort(url) { - return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file"; -} - -function isNormalizedWindowsDriveLetter(string) { - return /^[A-Za-z]:$/.test(string); -} - -function URLStateMachine(input, base, encodingOverride, url, stateOverride) { - this.pointer = 0; - this.input = input; - this.base = base || null; - this.encodingOverride = encodingOverride || "utf-8"; - this.stateOverride = stateOverride; - this.url = url; - this.failure = false; - this.parseError = false; - - if (!this.url) { - this.url = { - scheme: "", - username: "", - password: "", - host: null, - port: null, - path: [], - query: null, - fragment: null, - - cannotBeABaseURL: false - }; - - const res = trimControlChars(this.input); - if (res !== this.input) { - this.parseError = true; - } - this.input = res; - } - - const res = trimTabAndNewline(this.input); - if (res !== this.input) { - this.parseError = true; - } - this.input = res; - - this.state = stateOverride || "scheme start"; - - this.buffer = ""; - this.atFlag = false; - this.arrFlag = false; - this.passwordTokenSeenFlag = false; - - this.input = punycode.ucs2.decode(this.input); - - for (; this.pointer <= this.input.length; ++this.pointer) { - const c = this.input[this.pointer]; - const cStr = isNaN(c) ? undefined : String.fromCodePoint(c); - - // exec state machine - const ret = this["parse " + this.state](c, cStr); - if (!ret) { - break; // terminate algorithm - } else if (ret === failure) { - this.failure = true; - break; - } - } -} - -URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) { - if (isASCIIAlpha(c)) { - this.buffer += cStr.toLowerCase(); - this.state = "scheme"; - } else if (!this.stateOverride) { - this.state = "no scheme"; - --this.pointer; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) { - if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) { - this.buffer += cStr.toLowerCase(); - } else if (c === 58) { - if (this.stateOverride) { - if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) { - return false; - } - - if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) { - return false; - } - - if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") { - return false; - } - - if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) { - return false; - } - } - this.url.scheme = this.buffer; - this.buffer = ""; - if (this.stateOverride) { - return false; - } - if (this.url.scheme === "file") { - if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) { - this.parseError = true; - } - this.state = "file"; - } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) { - this.state = "special relative or authority"; - } else if (isSpecial(this.url)) { - this.state = "special authority slashes"; - } else if (this.input[this.pointer + 1] === 47) { - this.state = "path or authority"; - ++this.pointer; - } else { - this.url.cannotBeABaseURL = true; - this.url.path.push(""); - this.state = "cannot-be-a-base-URL path"; - } - } else if (!this.stateOverride) { - this.buffer = ""; - this.state = "no scheme"; - this.pointer = -1; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) { - if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) { - return failure; - } else if (this.base.cannotBeABaseURL && c === 35) { - this.url.scheme = this.base.scheme; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.url.cannotBeABaseURL = true; - this.state = "fragment"; - } else if (this.base.scheme === "file") { - this.state = "file"; - --this.pointer; - } else { - this.state = "relative"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) { - if (c === 47 && this.input[this.pointer + 1] === 47) { - this.state = "special authority ignore slashes"; - ++this.pointer; - } else { - this.parseError = true; - this.state = "relative"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) { - if (c === 47) { - this.state = "authority"; - } else { - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse relative"] = function parseRelative(c) { - this.url.scheme = this.base.scheme; - if (isNaN(c)) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - } else if (c === 47) { - this.state = "relative slash"; - } else if (c === 63) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.state = "fragment"; - } else if (isSpecial(this.url) && c === 92) { - this.parseError = true; - this.state = "relative slash"; - } else { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(0, this.base.path.length - 1); - - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) { - if (isSpecial(this.url) && (c === 47 || c === 92)) { - if (c === 92) { - this.parseError = true; - } - this.state = "special authority ignore slashes"; - } else if (c === 47) { - this.state = "authority"; - } else { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) { - if (c === 47 && this.input[this.pointer + 1] === 47) { - this.state = "special authority ignore slashes"; - ++this.pointer; - } else { - this.parseError = true; - this.state = "special authority ignore slashes"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) { - if (c !== 47 && c !== 92) { - this.state = "authority"; - --this.pointer; - } else { - this.parseError = true; - } - - return true; -}; - -URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) { - if (c === 64) { - this.parseError = true; - if (this.atFlag) { - this.buffer = "%40" + this.buffer; - } - this.atFlag = true; - - // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars - const len = countSymbols(this.buffer); - for (let pointer = 0; pointer < len; ++pointer) { - const codePoint = this.buffer.codePointAt(pointer); - - if (codePoint === 58 && !this.passwordTokenSeenFlag) { - this.passwordTokenSeenFlag = true; - continue; - } - const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode); - if (this.passwordTokenSeenFlag) { - this.url.password += encodedCodePoints; - } else { - this.url.username += encodedCodePoints; - } - } - this.buffer = ""; - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92)) { - if (this.atFlag && this.buffer === "") { - this.parseError = true; - return failure; - } - this.pointer -= countSymbols(this.buffer) + 1; - this.buffer = ""; - this.state = "host"; - } else { - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse hostname"] = -URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) { - if (this.stateOverride && this.url.scheme === "file") { - --this.pointer; - this.state = "file host"; - } else if (c === 58 && !this.arrFlag) { - if (this.buffer === "") { - this.parseError = true; - return failure; - } - - const host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - - this.url.host = host; - this.buffer = ""; - this.state = "port"; - if (this.stateOverride === "hostname") { - return false; - } - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92)) { - --this.pointer; - if (isSpecial(this.url) && this.buffer === "") { - this.parseError = true; - return failure; - } else if (this.stateOverride && this.buffer === "" && - (includesCredentials(this.url) || this.url.port !== null)) { - this.parseError = true; - return false; - } - - const host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - - this.url.host = host; - this.buffer = ""; - this.state = "path start"; - if (this.stateOverride) { - return false; - } - } else { - if (c === 91) { - this.arrFlag = true; - } else if (c === 93) { - this.arrFlag = false; - } - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) { - if (isASCIIDigit(c)) { - this.buffer += cStr; - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92) || - this.stateOverride) { - if (this.buffer !== "") { - const port = parseInt(this.buffer); - if (port > Math.pow(2, 16) - 1) { - this.parseError = true; - return failure; - } - this.url.port = port === defaultPort(this.url.scheme) ? null : port; - this.buffer = ""; - } - if (this.stateOverride) { - return false; - } - this.state = "path start"; - --this.pointer; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]); - -URLStateMachine.prototype["parse file"] = function parseFile(c) { - this.url.scheme = "file"; - - if (c === 47 || c === 92) { - if (c === 92) { - this.parseError = true; - } - this.state = "file slash"; - } else if (this.base !== null && this.base.scheme === "file") { - if (isNaN(c)) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - } else if (c === 63) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.state = "fragment"; - } else { - if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points - !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) || - (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points - !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - shortenPath(this.url); - } else { - this.parseError = true; - } - - this.state = "path"; - --this.pointer; - } - } else { - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) { - if (c === 47 || c === 92) { - if (c === 92) { - this.parseError = true; - } - this.state = "file host"; - } else { - if (this.base !== null && this.base.scheme === "file") { - if (isNormalizedWindowsDriveLetterString(this.base.path[0])) { - this.url.path.push(this.base.path[0]); - } else { - this.url.host = this.base.host; - } - } - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) { - if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) { - --this.pointer; - if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) { - this.parseError = true; - this.state = "path"; - } else if (this.buffer === "") { - this.url.host = ""; - if (this.stateOverride) { - return false; - } - this.state = "path start"; - } else { - let host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - if (host === "localhost") { - host = ""; - } - this.url.host = host; - - if (this.stateOverride) { - return false; - } - - this.buffer = ""; - this.state = "path start"; - } - } else { - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse path start"] = function parsePathStart(c) { - if (isSpecial(this.url)) { - if (c === 92) { - this.parseError = true; - } - this.state = "path"; - - if (c !== 47 && c !== 92) { - --this.pointer; - } - } else if (!this.stateOverride && c === 63) { - this.url.query = ""; - this.state = "query"; - } else if (!this.stateOverride && c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } else if (c !== undefined) { - this.state = "path"; - if (c !== 47) { - --this.pointer; - } - } - - return true; -}; - -URLStateMachine.prototype["parse path"] = function parsePath(c) { - if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) || - (!this.stateOverride && (c === 63 || c === 35))) { - if (isSpecial(this.url) && c === 92) { - this.parseError = true; - } - - if (isDoubleDot(this.buffer)) { - shortenPath(this.url); - if (c !== 47 && !(isSpecial(this.url) && c === 92)) { - this.url.path.push(""); - } - } else if (isSingleDot(this.buffer) && c !== 47 && - !(isSpecial(this.url) && c === 92)) { - this.url.path.push(""); - } else if (!isSingleDot(this.buffer)) { - if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) { - if (this.url.host !== "" && this.url.host !== null) { - this.parseError = true; - this.url.host = ""; - } - this.buffer = this.buffer[0] + ":"; - } - this.url.path.push(this.buffer); - } - this.buffer = ""; - if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) { - while (this.url.path.length > 1 && this.url.path[0] === "") { - this.parseError = true; - this.url.path.shift(); - } - } - if (c === 63) { - this.url.query = ""; - this.state = "query"; - } - if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } - } else { - // TODO: If c is not a URL code point and not "%", parse error. - - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.buffer += percentEncodeChar(c, isPathPercentEncode); - } - - return true; -}; - -URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) { - if (c === 63) { - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } else { - // TODO: Add: not a URL code point - if (!isNaN(c) && c !== 37) { - this.parseError = true; - } - - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - if (!isNaN(c)) { - this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode); - } - } - - return true; -}; - -URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) { - if (isNaN(c) || (!this.stateOverride && c === 35)) { - if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") { - this.encodingOverride = "utf-8"; - } - - const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead - for (let i = 0; i < buffer.length; ++i) { - if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 || - buffer[i] === 0x3C || buffer[i] === 0x3E) { - this.url.query += percentEncode(buffer[i]); - } else { - this.url.query += String.fromCodePoint(buffer[i]); - } - } - - this.buffer = ""; - if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } - } else { - // TODO: If c is not a URL code point and not "%", parse error. - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse fragment"] = function parseFragment(c) { - if (isNaN(c)) { // do nothing - } else if (c === 0x0) { - this.parseError = true; - } else { - // TODO: If c is not a URL code point and not "%", parse error. - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode); - } - - return true; -}; - -function serializeURL(url, excludeFragment) { - let output = url.scheme + ":"; - if (url.host !== null) { - output += "//"; - - if (url.username !== "" || url.password !== "") { - output += url.username; - if (url.password !== "") { - output += ":" + url.password; - } - output += "@"; - } - - output += serializeHost(url.host); - - if (url.port !== null) { - output += ":" + url.port; - } - } else if (url.host === null && url.scheme === "file") { - output += "//"; - } - - if (url.cannotBeABaseURL) { - output += url.path[0]; - } else { - for (const string of url.path) { - output += "/" + string; - } - } - - if (url.query !== null) { - output += "?" + url.query; - } - - if (!excludeFragment && url.fragment !== null) { - output += "#" + url.fragment; - } - - return output; -} - -function serializeOrigin(tuple) { - let result = tuple.scheme + "://"; - result += serializeHost(tuple.host); - - if (tuple.port !== null) { - result += ":" + tuple.port; - } - - return result; -} - -module.exports.serializeURL = serializeURL; - -module.exports.serializeURLOrigin = function (url) { - // https://url.spec.whatwg.org/#concept-url-origin - switch (url.scheme) { - case "blob": - try { - return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0])); - } catch (e) { - // serializing an opaque origin returns "null" - return "null"; - } - case "ftp": - case "gopher": - case "http": - case "https": - case "ws": - case "wss": - return serializeOrigin({ - scheme: url.scheme, - host: url.host, - port: url.port - }); - case "file": - // spec says "exercise to the reader", chrome says "file://" - return "file://"; - default: - // serializing an opaque origin returns "null" - return "null"; - } -}; - -module.exports.basicURLParse = function (input, options) { - if (options === undefined) { - options = {}; - } - - const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride); - if (usm.failure) { - return "failure"; - } - - return usm.url; -}; - -module.exports.setTheUsername = function (url, username) { - url.username = ""; - const decoded = punycode.ucs2.decode(username); - for (let i = 0; i < decoded.length; ++i) { - url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode); - } -}; - -module.exports.setThePassword = function (url, password) { - url.password = ""; - const decoded = punycode.ucs2.decode(password); - for (let i = 0; i < decoded.length; ++i) { - url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode); - } -}; - -module.exports.serializeHost = serializeHost; - -module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort; - -module.exports.serializeInteger = function (integer) { - return String(integer); -}; - -module.exports.parseURL = function (input, options) { - if (options === undefined) { - options = {}; - } - - // We don't handle blobs, so this just delegates: - return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride }); -}; + +const punycode = __nccwpck_require__(4213); +const tr46 = __nccwpck_require__(2299); + +const specialSchemes = { + ftp: 21, + file: null, + gopher: 70, + http: 80, + https: 443, + ws: 80, + wss: 443 +}; + +const failure = Symbol("failure"); + +function countSymbols(str) { + return punycode.ucs2.decode(str).length; +} + +function at(input, idx) { + const c = input[idx]; + return isNaN(c) ? undefined : String.fromCodePoint(c); +} + +function isASCIIDigit(c) { + return c >= 0x30 && c <= 0x39; +} + +function isASCIIAlpha(c) { + return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); +} + +function isASCIIAlphanumeric(c) { + return isASCIIAlpha(c) || isASCIIDigit(c); +} + +function isASCIIHex(c) { + return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); +} + +function isSingleDot(buffer) { + return buffer === "." || buffer.toLowerCase() === "%2e"; +} + +function isDoubleDot(buffer) { + buffer = buffer.toLowerCase(); + return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e"; +} + +function isWindowsDriveLetterCodePoints(cp1, cp2) { + return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124); +} + +function isWindowsDriveLetterString(string) { + return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|"); +} + +function isNormalizedWindowsDriveLetterString(string) { + return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":"; +} + +function containsForbiddenHostCodePoint(string) { + return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1; +} + +function containsForbiddenHostCodePointExcludingPercent(string) { + return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1; +} + +function isSpecialScheme(scheme) { + return specialSchemes[scheme] !== undefined; +} + +function isSpecial(url) { + return isSpecialScheme(url.scheme); +} + +function defaultPort(scheme) { + return specialSchemes[scheme]; +} + +function percentEncode(c) { + let hex = c.toString(16).toUpperCase(); + if (hex.length === 1) { + hex = "0" + hex; + } + + return "%" + hex; +} + +function utf8PercentEncode(c) { + const buf = new Buffer(c); + + let str = ""; + + for (let i = 0; i < buf.length; ++i) { + str += percentEncode(buf[i]); + } + + return str; +} + +function utf8PercentDecode(str) { + const input = new Buffer(str); + const output = []; + for (let i = 0; i < input.length; ++i) { + if (input[i] !== 37) { + output.push(input[i]); + } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) { + output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16)); + i += 2; + } else { + output.push(input[i]); + } + } + return new Buffer(output).toString(); +} + +function isC0ControlPercentEncode(c) { + return c <= 0x1F || c > 0x7E; +} + +const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]); +function isPathPercentEncode(c) { + return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c); +} + +const extraUserinfoPercentEncodeSet = + new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]); +function isUserinfoPercentEncode(c) { + return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c); +} + +function percentEncodeChar(c, encodeSetPredicate) { + const cStr = String.fromCodePoint(c); + + if (encodeSetPredicate(c)) { + return utf8PercentEncode(cStr); + } + + return cStr; +} + +function parseIPv4Number(input) { + let R = 10; + + if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") { + input = input.substring(2); + R = 16; + } else if (input.length >= 2 && input.charAt(0) === "0") { + input = input.substring(1); + R = 8; + } + + if (input === "") { + return 0; + } + + const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/); + if (regex.test(input)) { + return failure; + } + + return parseInt(input, R); +} + +function parseIPv4(input) { + const parts = input.split("."); + if (parts[parts.length - 1] === "") { + if (parts.length > 1) { + parts.pop(); + } + } + + if (parts.length > 4) { + return input; + } + + const numbers = []; + for (const part of parts) { + if (part === "") { + return input; + } + const n = parseIPv4Number(part); + if (n === failure) { + return input; + } + + numbers.push(n); + } + + for (let i = 0; i < numbers.length - 1; ++i) { + if (numbers[i] > 255) { + return failure; + } + } + if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) { + return failure; + } + + let ipv4 = numbers.pop(); + let counter = 0; + + for (const n of numbers) { + ipv4 += n * Math.pow(256, 3 - counter); + ++counter; + } + + return ipv4; +} + +function serializeIPv4(address) { + let output = ""; + let n = address; + + for (let i = 1; i <= 4; ++i) { + output = String(n % 256) + output; + if (i !== 4) { + output = "." + output; + } + n = Math.floor(n / 256); + } + + return output; +} + +function parseIPv6(input) { + const address = [0, 0, 0, 0, 0, 0, 0, 0]; + let pieceIndex = 0; + let compress = null; + let pointer = 0; + + input = punycode.ucs2.decode(input); + + if (input[pointer] === 58) { + if (input[pointer + 1] !== 58) { + return failure; + } + + pointer += 2; + ++pieceIndex; + compress = pieceIndex; + } + + while (pointer < input.length) { + if (pieceIndex === 8) { + return failure; + } + + if (input[pointer] === 58) { + if (compress !== null) { + return failure; + } + ++pointer; + ++pieceIndex; + compress = pieceIndex; + continue; + } + + let value = 0; + let length = 0; + + while (length < 4 && isASCIIHex(input[pointer])) { + value = value * 0x10 + parseInt(at(input, pointer), 16); + ++pointer; + ++length; + } + + if (input[pointer] === 46) { + if (length === 0) { + return failure; + } + + pointer -= length; + + if (pieceIndex > 6) { + return failure; + } + + let numbersSeen = 0; + + while (input[pointer] !== undefined) { + let ipv4Piece = null; + + if (numbersSeen > 0) { + if (input[pointer] === 46 && numbersSeen < 4) { + ++pointer; + } else { + return failure; + } + } + + if (!isASCIIDigit(input[pointer])) { + return failure; + } + + while (isASCIIDigit(input[pointer])) { + const number = parseInt(at(input, pointer)); + if (ipv4Piece === null) { + ipv4Piece = number; + } else if (ipv4Piece === 0) { + return failure; + } else { + ipv4Piece = ipv4Piece * 10 + number; + } + if (ipv4Piece > 255) { + return failure; + } + ++pointer; + } + + address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece; + + ++numbersSeen; + + if (numbersSeen === 2 || numbersSeen === 4) { + ++pieceIndex; + } + } + + if (numbersSeen !== 4) { + return failure; + } + + break; + } else if (input[pointer] === 58) { + ++pointer; + if (input[pointer] === undefined) { + return failure; + } + } else if (input[pointer] !== undefined) { + return failure; + } + + address[pieceIndex] = value; + ++pieceIndex; + } + + if (compress !== null) { + let swaps = pieceIndex - compress; + pieceIndex = 7; + while (pieceIndex !== 0 && swaps > 0) { + const temp = address[compress + swaps - 1]; + address[compress + swaps - 1] = address[pieceIndex]; + address[pieceIndex] = temp; + --pieceIndex; + --swaps; + } + } else if (compress === null && pieceIndex !== 8) { + return failure; + } + + return address; +} + +function serializeIPv6(address) { + let output = ""; + const seqResult = findLongestZeroSequence(address); + const compress = seqResult.idx; + let ignore0 = false; + + for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) { + if (ignore0 && address[pieceIndex] === 0) { + continue; + } else if (ignore0) { + ignore0 = false; + } + + if (compress === pieceIndex) { + const separator = pieceIndex === 0 ? "::" : ":"; + output += separator; + ignore0 = true; + continue; + } + + output += address[pieceIndex].toString(16); + + if (pieceIndex !== 7) { + output += ":"; + } + } + + return output; +} + +function parseHost(input, isSpecialArg) { + if (input[0] === "[") { + if (input[input.length - 1] !== "]") { + return failure; + } + + return parseIPv6(input.substring(1, input.length - 1)); + } + + if (!isSpecialArg) { + return parseOpaqueHost(input); + } + + const domain = utf8PercentDecode(input); + const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false); + if (asciiDomain === null) { + return failure; + } + + if (containsForbiddenHostCodePoint(asciiDomain)) { + return failure; + } + + const ipv4Host = parseIPv4(asciiDomain); + if (typeof ipv4Host === "number" || ipv4Host === failure) { + return ipv4Host; + } + + return asciiDomain; +} + +function parseOpaqueHost(input) { + if (containsForbiddenHostCodePointExcludingPercent(input)) { + return failure; + } + + let output = ""; + const decoded = punycode.ucs2.decode(input); + for (let i = 0; i < decoded.length; ++i) { + output += percentEncodeChar(decoded[i], isC0ControlPercentEncode); + } + return output; +} + +function findLongestZeroSequence(arr) { + let maxIdx = null; + let maxLen = 1; // only find elements > 1 + let currStart = null; + let currLen = 0; + + for (let i = 0; i < arr.length; ++i) { + if (arr[i] !== 0) { + if (currLen > maxLen) { + maxIdx = currStart; + maxLen = currLen; + } + + currStart = null; + currLen = 0; + } else { + if (currStart === null) { + currStart = i; + } + ++currLen; + } + } + + // if trailing zeros + if (currLen > maxLen) { + maxIdx = currStart; + maxLen = currLen; + } + + return { + idx: maxIdx, + len: maxLen + }; +} + +function serializeHost(host) { + if (typeof host === "number") { + return serializeIPv4(host); + } + + // IPv6 serializer + if (host instanceof Array) { + return "[" + serializeIPv6(host) + "]"; + } + + return host; +} + +function trimControlChars(url) { + return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, ""); +} + +function trimTabAndNewline(url) { + return url.replace(/\u0009|\u000A|\u000D/g, ""); +} + +function shortenPath(url) { + const path = url.path; + if (path.length === 0) { + return; + } + if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) { + return; + } + + path.pop(); +} + +function includesCredentials(url) { + return url.username !== "" || url.password !== ""; +} + +function cannotHaveAUsernamePasswordPort(url) { + return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file"; +} + +function isNormalizedWindowsDriveLetter(string) { + return /^[A-Za-z]:$/.test(string); +} + +function URLStateMachine(input, base, encodingOverride, url, stateOverride) { + this.pointer = 0; + this.input = input; + this.base = base || null; + this.encodingOverride = encodingOverride || "utf-8"; + this.stateOverride = stateOverride; + this.url = url; + this.failure = false; + this.parseError = false; + + if (!this.url) { + this.url = { + scheme: "", + username: "", + password: "", + host: null, + port: null, + path: [], + query: null, + fragment: null, + + cannotBeABaseURL: false + }; + + const res = trimControlChars(this.input); + if (res !== this.input) { + this.parseError = true; + } + this.input = res; + } + + const res = trimTabAndNewline(this.input); + if (res !== this.input) { + this.parseError = true; + } + this.input = res; + + this.state = stateOverride || "scheme start"; + + this.buffer = ""; + this.atFlag = false; + this.arrFlag = false; + this.passwordTokenSeenFlag = false; + + this.input = punycode.ucs2.decode(this.input); + + for (; this.pointer <= this.input.length; ++this.pointer) { + const c = this.input[this.pointer]; + const cStr = isNaN(c) ? undefined : String.fromCodePoint(c); + + // exec state machine + const ret = this["parse " + this.state](c, cStr); + if (!ret) { + break; // terminate algorithm + } else if (ret === failure) { + this.failure = true; + break; + } + } +} + +URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) { + if (isASCIIAlpha(c)) { + this.buffer += cStr.toLowerCase(); + this.state = "scheme"; + } else if (!this.stateOverride) { + this.state = "no scheme"; + --this.pointer; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) { + if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) { + this.buffer += cStr.toLowerCase(); + } else if (c === 58) { + if (this.stateOverride) { + if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) { + return false; + } + + if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) { + return false; + } + + if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") { + return false; + } + + if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) { + return false; + } + } + this.url.scheme = this.buffer; + this.buffer = ""; + if (this.stateOverride) { + return false; + } + if (this.url.scheme === "file") { + if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) { + this.parseError = true; + } + this.state = "file"; + } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) { + this.state = "special relative or authority"; + } else if (isSpecial(this.url)) { + this.state = "special authority slashes"; + } else if (this.input[this.pointer + 1] === 47) { + this.state = "path or authority"; + ++this.pointer; + } else { + this.url.cannotBeABaseURL = true; + this.url.path.push(""); + this.state = "cannot-be-a-base-URL path"; + } + } else if (!this.stateOverride) { + this.buffer = ""; + this.state = "no scheme"; + this.pointer = -1; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) { + if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) { + return failure; + } else if (this.base.cannotBeABaseURL && c === 35) { + this.url.scheme = this.base.scheme; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.url.cannotBeABaseURL = true; + this.state = "fragment"; + } else if (this.base.scheme === "file") { + this.state = "file"; + --this.pointer; + } else { + this.state = "relative"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) { + if (c === 47 && this.input[this.pointer + 1] === 47) { + this.state = "special authority ignore slashes"; + ++this.pointer; + } else { + this.parseError = true; + this.state = "relative"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) { + if (c === 47) { + this.state = "authority"; + } else { + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse relative"] = function parseRelative(c) { + this.url.scheme = this.base.scheme; + if (isNaN(c)) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + } else if (c === 47) { + this.state = "relative slash"; + } else if (c === 63) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.state = "fragment"; + } else if (isSpecial(this.url) && c === 92) { + this.parseError = true; + this.state = "relative slash"; + } else { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(0, this.base.path.length - 1); + + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) { + if (isSpecial(this.url) && (c === 47 || c === 92)) { + if (c === 92) { + this.parseError = true; + } + this.state = "special authority ignore slashes"; + } else if (c === 47) { + this.state = "authority"; + } else { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) { + if (c === 47 && this.input[this.pointer + 1] === 47) { + this.state = "special authority ignore slashes"; + ++this.pointer; + } else { + this.parseError = true; + this.state = "special authority ignore slashes"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) { + if (c !== 47 && c !== 92) { + this.state = "authority"; + --this.pointer; + } else { + this.parseError = true; + } + + return true; +}; + +URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) { + if (c === 64) { + this.parseError = true; + if (this.atFlag) { + this.buffer = "%40" + this.buffer; + } + this.atFlag = true; + + // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars + const len = countSymbols(this.buffer); + for (let pointer = 0; pointer < len; ++pointer) { + const codePoint = this.buffer.codePointAt(pointer); + + if (codePoint === 58 && !this.passwordTokenSeenFlag) { + this.passwordTokenSeenFlag = true; + continue; + } + const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode); + if (this.passwordTokenSeenFlag) { + this.url.password += encodedCodePoints; + } else { + this.url.username += encodedCodePoints; + } + } + this.buffer = ""; + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92)) { + if (this.atFlag && this.buffer === "") { + this.parseError = true; + return failure; + } + this.pointer -= countSymbols(this.buffer) + 1; + this.buffer = ""; + this.state = "host"; + } else { + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse hostname"] = +URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) { + if (this.stateOverride && this.url.scheme === "file") { + --this.pointer; + this.state = "file host"; + } else if (c === 58 && !this.arrFlag) { + if (this.buffer === "") { + this.parseError = true; + return failure; + } + + const host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + + this.url.host = host; + this.buffer = ""; + this.state = "port"; + if (this.stateOverride === "hostname") { + return false; + } + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92)) { + --this.pointer; + if (isSpecial(this.url) && this.buffer === "") { + this.parseError = true; + return failure; + } else if (this.stateOverride && this.buffer === "" && + (includesCredentials(this.url) || this.url.port !== null)) { + this.parseError = true; + return false; + } + + const host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + + this.url.host = host; + this.buffer = ""; + this.state = "path start"; + if (this.stateOverride) { + return false; + } + } else { + if (c === 91) { + this.arrFlag = true; + } else if (c === 93) { + this.arrFlag = false; + } + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) { + if (isASCIIDigit(c)) { + this.buffer += cStr; + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92) || + this.stateOverride) { + if (this.buffer !== "") { + const port = parseInt(this.buffer); + if (port > Math.pow(2, 16) - 1) { + this.parseError = true; + return failure; + } + this.url.port = port === defaultPort(this.url.scheme) ? null : port; + this.buffer = ""; + } + if (this.stateOverride) { + return false; + } + this.state = "path start"; + --this.pointer; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]); + +URLStateMachine.prototype["parse file"] = function parseFile(c) { + this.url.scheme = "file"; + + if (c === 47 || c === 92) { + if (c === 92) { + this.parseError = true; + } + this.state = "file slash"; + } else if (this.base !== null && this.base.scheme === "file") { + if (isNaN(c)) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + } else if (c === 63) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.state = "fragment"; + } else { + if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points + !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) || + (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points + !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + shortenPath(this.url); + } else { + this.parseError = true; + } + + this.state = "path"; + --this.pointer; + } + } else { + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) { + if (c === 47 || c === 92) { + if (c === 92) { + this.parseError = true; + } + this.state = "file host"; + } else { + if (this.base !== null && this.base.scheme === "file") { + if (isNormalizedWindowsDriveLetterString(this.base.path[0])) { + this.url.path.push(this.base.path[0]); + } else { + this.url.host = this.base.host; + } + } + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) { + if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) { + --this.pointer; + if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) { + this.parseError = true; + this.state = "path"; + } else if (this.buffer === "") { + this.url.host = ""; + if (this.stateOverride) { + return false; + } + this.state = "path start"; + } else { + let host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + if (host === "localhost") { + host = ""; + } + this.url.host = host; + + if (this.stateOverride) { + return false; + } + + this.buffer = ""; + this.state = "path start"; + } + } else { + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse path start"] = function parsePathStart(c) { + if (isSpecial(this.url)) { + if (c === 92) { + this.parseError = true; + } + this.state = "path"; + + if (c !== 47 && c !== 92) { + --this.pointer; + } + } else if (!this.stateOverride && c === 63) { + this.url.query = ""; + this.state = "query"; + } else if (!this.stateOverride && c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } else if (c !== undefined) { + this.state = "path"; + if (c !== 47) { + --this.pointer; + } + } + + return true; +}; + +URLStateMachine.prototype["parse path"] = function parsePath(c) { + if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) || + (!this.stateOverride && (c === 63 || c === 35))) { + if (isSpecial(this.url) && c === 92) { + this.parseError = true; + } + + if (isDoubleDot(this.buffer)) { + shortenPath(this.url); + if (c !== 47 && !(isSpecial(this.url) && c === 92)) { + this.url.path.push(""); + } + } else if (isSingleDot(this.buffer) && c !== 47 && + !(isSpecial(this.url) && c === 92)) { + this.url.path.push(""); + } else if (!isSingleDot(this.buffer)) { + if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) { + if (this.url.host !== "" && this.url.host !== null) { + this.parseError = true; + this.url.host = ""; + } + this.buffer = this.buffer[0] + ":"; + } + this.url.path.push(this.buffer); + } + this.buffer = ""; + if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) { + while (this.url.path.length > 1 && this.url.path[0] === "") { + this.parseError = true; + this.url.path.shift(); + } + } + if (c === 63) { + this.url.query = ""; + this.state = "query"; + } + if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } + } else { + // TODO: If c is not a URL code point and not "%", parse error. + + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.buffer += percentEncodeChar(c, isPathPercentEncode); + } + + return true; +}; + +URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) { + if (c === 63) { + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } else { + // TODO: Add: not a URL code point + if (!isNaN(c) && c !== 37) { + this.parseError = true; + } + + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + if (!isNaN(c)) { + this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode); + } + } + + return true; +}; + +URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) { + if (isNaN(c) || (!this.stateOverride && c === 35)) { + if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") { + this.encodingOverride = "utf-8"; + } + + const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead + for (let i = 0; i < buffer.length; ++i) { + if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 || + buffer[i] === 0x3C || buffer[i] === 0x3E) { + this.url.query += percentEncode(buffer[i]); + } else { + this.url.query += String.fromCodePoint(buffer[i]); + } + } + + this.buffer = ""; + if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } + } else { + // TODO: If c is not a URL code point and not "%", parse error. + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse fragment"] = function parseFragment(c) { + if (isNaN(c)) { // do nothing + } else if (c === 0x0) { + this.parseError = true; + } else { + // TODO: If c is not a URL code point and not "%", parse error. + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode); + } + + return true; +}; + +function serializeURL(url, excludeFragment) { + let output = url.scheme + ":"; + if (url.host !== null) { + output += "//"; + + if (url.username !== "" || url.password !== "") { + output += url.username; + if (url.password !== "") { + output += ":" + url.password; + } + output += "@"; + } + + output += serializeHost(url.host); + + if (url.port !== null) { + output += ":" + url.port; + } + } else if (url.host === null && url.scheme === "file") { + output += "//"; + } + + if (url.cannotBeABaseURL) { + output += url.path[0]; + } else { + for (const string of url.path) { + output += "/" + string; + } + } + + if (url.query !== null) { + output += "?" + url.query; + } + + if (!excludeFragment && url.fragment !== null) { + output += "#" + url.fragment; + } + + return output; +} + +function serializeOrigin(tuple) { + let result = tuple.scheme + "://"; + result += serializeHost(tuple.host); + + if (tuple.port !== null) { + result += ":" + tuple.port; + } + + return result; +} + +module.exports.serializeURL = serializeURL; + +module.exports.serializeURLOrigin = function (url) { + // https://url.spec.whatwg.org/#concept-url-origin + switch (url.scheme) { + case "blob": + try { + return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0])); + } catch (e) { + // serializing an opaque origin returns "null" + return "null"; + } + case "ftp": + case "gopher": + case "http": + case "https": + case "ws": + case "wss": + return serializeOrigin({ + scheme: url.scheme, + host: url.host, + port: url.port + }); + case "file": + // spec says "exercise to the reader", chrome says "file://" + return "file://"; + default: + // serializing an opaque origin returns "null" + return "null"; + } +}; + +module.exports.basicURLParse = function (input, options) { + if (options === undefined) { + options = {}; + } + + const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride); + if (usm.failure) { + return "failure"; + } + + return usm.url; +}; + +module.exports.setTheUsername = function (url, username) { + url.username = ""; + const decoded = punycode.ucs2.decode(username); + for (let i = 0; i < decoded.length; ++i) { + url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode); + } +}; + +module.exports.setThePassword = function (url, password) { + url.password = ""; + const decoded = punycode.ucs2.decode(password); + for (let i = 0; i < decoded.length; ++i) { + url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode); + } +}; + +module.exports.serializeHost = serializeHost; + +module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort; + +module.exports.serializeInteger = function (integer) { + return String(integer); +}; + +module.exports.parseURL = function (input, options) { + if (options === undefined) { + options = {}; + } + + // We don't handle blobs, so this just delegates: + return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride }); +}; /***/ }), diff --git a/package-lock.json b/package-lock.json index eee7fc99..87867f62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stale-action", - "version": "2.0.0", + "version": "7.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "stale-action", - "version": "2.0.0", + "version": "7.0.0", "license": "MIT", "dependencies": { "@actions/core": "^1.10.0", diff --git a/package.json b/package.json index fbd06900..996ffb99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stale-action", - "version": "2.0.0", + "version": "7.0.0", "private": true, "description": "Marks old issues and PRs as stale", "main": "lib/main.js", diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 70e3bf24..07aff68f 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -321,9 +321,9 @@ export class IssuesProcessor { } if (issue.isStale) { - issueLogger.info(`This $$type has a stale label`); + issueLogger.info(`This $$type includes a stale label`); } else { - issueLogger.info(`This $$type hasn't a stale label`); + issueLogger.info(`This $$type does not include a stale label`); } const exemptLabels: string[] = wordsToList( @@ -332,17 +332,16 @@ export class IssuesProcessor { : this.options.exemptIssueLabels ); - if ( - exemptLabels.some((exemptLabel: Readonly): boolean => - isLabeled(issue, exemptLabel) - ) - ) { - if (issue.isStale) { - issueLogger.info(`An exempt label was added after the stale label.`); - await this._removeStaleLabel(issue, staleLabel); - } + const hasExemptLabel = exemptLabels.some((exemptLabel: Readonly) => + isLabeled(issue, exemptLabel) + ); - issueLogger.info(`Skipping this $$type because it has an exempt label`); + if (hasExemptLabel) { + issueLogger.info( + `Skipping this $$type because it contains an exempt label, see ${issueLogger.createOptionLink( + issue.isPullRequest ? Option.ExemptPrLabels : Option.ExemptIssueLabels + )} for more details` + ); IssuesProcessor._endIssueProcessing(issue); return; // Don't process exempt issues } @@ -427,6 +426,7 @@ export class IssuesProcessor { // Determine if this issue needs to be marked stale first if (!issue.isStale) { issueLogger.info(`This $$type is not stale`); + const shouldIgnoreUpdates: boolean = new IgnoreUpdates( this.options, issue