fix(logs): coloured logs (#465)

* refactor(logs): replace chalk by ansi-styles

* test(logs): fix the failing tests due to ansi styles

I was not able to disable or mock ansi-styles so instead I found a way to make the tests pass
it's not perfect but it's still nice because the logs will keep their trustful colour when running through the tests

* refactor(logs): simplify the syntax to colour the logs

* chore(rebase): update files due to rebase

* refactor(logger): reduce code duplication
This commit is contained in:
Geoffrey Testelin 2021-06-02 23:04:34 +02:00 committed by GitHub
parent e884599072
commit 5fbbfba142
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 671 additions and 2262 deletions

View File

@ -28,7 +28,7 @@
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-extraneous-class": "off",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",

2453
dist/index.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,5 @@ module.exports = {
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true,
setupFilesAfterEnv: [`./jest/test.ts`]
verbose: true
};

View File

@ -1,11 +0,0 @@
import chalk from 'chalk';
// Disabled the colors to:
// - improve the performances
// - avoid to mock chalk
// - avoid to have failing tests when testing the logs due to the extra text the log message will contains
//
// Note:
// If you need to debug the log colours you can remove this line temporarily
// But some tests will fail
chalk.level = 0;

99
package-lock.json generated
View File

@ -217,6 +217,17 @@
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
}
}
}
}
@ -2081,13 +2092,10 @@
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true
},
"anymatch": {
"version": "2.0.0",
@ -2556,57 +2564,6 @@
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"char-regex": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
@ -3167,7 +3124,33 @@
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
}
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
}
}
},

View File

@ -43,7 +43,7 @@
"@typescript-eslint/eslint-plugin": "^4.16.1",
"@typescript-eslint/parser": "^4.22.1",
"@vercel/ncc": "^0.27.0",
"chalk": "^4.1.0",
"ansi-styles": "5.2.0",
"eslint": "^7.21.0",
"eslint-plugin-github": "^4.1.2",
"eslint-plugin-jest": "^24.3.6",

View File

@ -1,4 +1,3 @@
import chalk from 'chalk';
import deburr from 'lodash.deburr';
import {Option} from '../enums/option';
import {wordsToList} from '../functions/words-to-list';
@ -6,6 +5,7 @@ import {IAssignee} from '../interfaces/assignee';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {LoggerService} from '../services/logger.service';
type CleanAssignee = string;
@ -34,7 +34,7 @@ export class Assignees {
if (this._shouldExemptAllAssignees()) {
this._issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
'Skipping this $$type because it has an exempt assignee'
);
@ -45,7 +45,7 @@ export class Assignees {
if (exemptAssignees.length === 0) {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`No assignee option was specified to skip the stale process for this $$type`
);
this._logSkip();
@ -54,8 +54,8 @@ export class Assignees {
}
this._issueLogger.info(
chalk.white('├──'),
`Found ${chalk.cyan(exemptAssignees.length)} assignee${
LoggerService.white('├──'),
`Found ${LoggerService.cyan(exemptAssignees.length)} assignee${
exemptAssignees.length > 1 ? 's' : ''
} that can exempt stale on this $$type`
);
@ -67,13 +67,13 @@ export class Assignees {
if (!hasExemptAssignee) {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
'No assignee on this $$type can exempt the stale process'
);
this._logSkip();
} else {
this._issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
'Skipping this $$type because it has an exempt assignee'
);
}
@ -90,7 +90,7 @@ export class Assignees {
private _getExemptIssueAssignees(): string[] {
if (this._options.exemptIssueAssignees === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
@ -98,7 +98,7 @@ export class Assignees {
if (this._options.exemptAssignees === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
@ -112,10 +112,10 @@ export class Assignees {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAssignees
)} is set. ${chalk.cyan(exemptAssignees.length)} assignee${
)} is set. ${LoggerService.cyan(exemptAssignees.length)} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -128,10 +128,10 @@ export class Assignees {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueAssignees
)} is set. ${chalk.cyan(exemptAssignees.length)} assignee${
)} is set. ${LoggerService.cyan(exemptAssignees.length)} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -142,7 +142,7 @@ export class Assignees {
private _getExemptPullRequestAssignees(): string[] {
if (this._options.exemptPrAssignees === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
@ -150,7 +150,7 @@ export class Assignees {
if (this._options.exemptAssignees === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAssignees
)} is disabled. No specific assignee can skip the stale process for this $$type`
@ -164,10 +164,10 @@ export class Assignees {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptAssignees
)} is set. ${chalk.cyan(exemptAssignees.length)} assignee${
)} is set. ${LoggerService.cyan(exemptAssignees.length)} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -180,10 +180,10 @@ export class Assignees {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrAssignees
)} is set. ${chalk.cyan(exemptAssignees.length)} assignee${
)} is set. ${LoggerService.cyan(exemptAssignees.length)} assignee${
exemptAssignees.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -201,7 +201,7 @@ export class Assignees {
if (isSameAssignee) {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`@${issueAssignee.login} is assigned on this $$type and is an exempt assignee`
);
}
@ -282,6 +282,9 @@ export class Assignees {
}
private _logSkip(): void {
this._issueLogger.info(chalk.white('└──'), 'Skip the assignees checks');
this._issueLogger.info(
LoggerService.white('└──'),
'Skip the assignees checks'
);
}
}

View File

@ -2,7 +2,6 @@ import * as core from '@actions/core';
import {context, getOctokit} from '@actions/github';
import {GitHub} from '@actions/github/lib/utils';
import {GetResponseTypeFromEndpointMethod} from '@octokit/types';
import chalk from 'chalk';
import {Option} from '../enums/option';
import {getHumanizedDate} from '../functions/dates/get-humanized-date';
import {isDateMoreRecentThan} from '../functions/dates/is-date-more-recent-than';
@ -23,6 +22,7 @@ import {Logger} from './loggers/logger';
import {Milestones} from './milestones';
import {StaleOperations} from './stale-operations';
import {Statistics} from './statistics';
import {LoggerService} from '../services/logger.service';
/***
* Handle processing of issues for staleness/closure.
@ -43,7 +43,7 @@ export class IssuesProcessor {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(
chalk.cyan(consumedOperationsCount),
LoggerService.cyan(consumedOperationsCount),
`operation${
consumedOperationsCount > 1 ? 's' : ''
} consumed for this $$type`
@ -74,13 +74,17 @@ export class IssuesProcessor {
this.client = getOctokit(this.options.repoToken);
this._operations = new StaleOperations(this.options);
this._logger.info(chalk.yellow('Starting the stale action process...'));
this._logger.info(
LoggerService.yellow(`Starting the stale action process...`)
);
if (this.options.debugOnly) {
this._logger.warning(chalk.yellowBright('Executing in debug mode!'));
this._logger.warning(
chalk.yellowBright(
'The debug output will be written but no issues/PRs will be processed.'
LoggerService.yellowBright(`Executing in debug mode!`)
);
this._logger.warning(
LoggerService.yellowBright(
`The debug output will be written but no issues/PRs will be processed.`
)
);
}
@ -97,7 +101,7 @@ export class IssuesProcessor {
if (issues.length <= 0) {
this._logger.info(
chalk.green('No more issues found to process. Exiting...')
LoggerService.green(`No more issues found to process. Exiting...`)
);
this._statistics
?.setRemainingOperations(this._operations.getRemainingOperationsCount())
@ -106,13 +110,13 @@ export class IssuesProcessor {
return this._operations.getRemainingOperationsCount();
} else {
this._logger.info(
chalk.yellow(
`Processing the batch of issues ${chalk.cyan(
`#${page}`
)} containing ${chalk.cyan(issues.length)} issue${
issues.length > 1 ? 's' : ''
}...`
)
`${LoggerService.yellow(
'Processing the batch of issues'
)} ${LoggerService.cyan(`#${page}`)} ${LoggerService.yellow(
'containing'
)} ${LoggerService.cyan(issues.length)} ${LoggerService.yellow(
`issue${issues.length > 1 ? 's' : ''}...`
)}`
);
}
@ -121,7 +125,9 @@ export class IssuesProcessor {
this._statistics?.incrementProcessedItemsCount(issue);
issueLogger.info(
`Found this $$type last updated at: ${chalk.cyan(issue.updated_at)}`
`Found this $$type last updated at: ${LoggerService.cyan(
issue.updated_at
)}`
);
// calculate string based messages for this issue
@ -149,7 +155,7 @@ export class IssuesProcessor {
issueLogger.info(
`The option ${issueLogger.createOptionLink(
Option.OnlyLabels
)} was specified to only process issues and pull requests with all those labels (${chalk.cyan(
)} was specified to only process issues and pull requests with all those labels (${LoggerService.cyan(
onlyLabels.length
)})`
);
@ -162,7 +168,7 @@ export class IssuesProcessor {
if (!hasAllWhitelistedLabels) {
issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
`Skipping this $$type because it doesn't have all the required labels`
);
@ -170,11 +176,11 @@ export class IssuesProcessor {
continue; // Don't process issues without all of the required labels
} else {
issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`All the required labels are present on this $$type`
);
issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
`Continuing the process for this $$type`
);
}
@ -185,13 +191,13 @@ export class IssuesProcessor {
)} was not specified`
);
issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
`Continuing the process for this $$type`
);
}
issueLogger.info(
`Days before $$type stale: ${chalk.cyan(daysBeforeStale)}`
`Days before $$type stale: ${LoggerService.cyan(daysBeforeStale)}`
);
const shouldMarkAsStale: boolean = shouldMarkWhenStale(daysBeforeStale);
@ -218,7 +224,7 @@ export class IssuesProcessor {
issueLogger.info(
`A start date was specified for the ${getHumanizedDate(
startDate
)} (${chalk.cyan(this.options.startDate)})`
)} (${LoggerService.cyan(this.options.startDate)})`
);
// Expecting that GitHub will always set a creation date on the issues and PRs
@ -233,9 +239,9 @@ export class IssuesProcessor {
}
issueLogger.info(
`$$type created the ${getHumanizedDate(createdAt)} (${chalk.cyan(
issue.created_at
)})`
`$$type created the ${getHumanizedDate(
createdAt
)} (${LoggerService.cyan(issue.created_at)})`
);
if (!isDateMoreRecentThan(createdAt, startDate)) {
@ -281,7 +287,7 @@ export class IssuesProcessor {
issueLogger.info(
`The option ${issueLogger.createOptionLink(
Option.AnyOfLabels
)} was specified to only process the issues and pull requests with one of those labels (${chalk.cyan(
)} was specified to only process the issues and pull requests with one of those labels (${LoggerService.cyan(
anyOfLabels.length
)})`
);
@ -294,18 +300,18 @@ export class IssuesProcessor {
if (!hasOneOfWhitelistedLabels) {
issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
`Skipping this $$type because it doesn't have one of the required labels`
);
IssuesProcessor._endIssueProcessing(issue);
continue; // Don't process issues without any of the required labels
} else {
issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`One of the required labels is present on this $$type`
);
issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
`Continuing the process for this $$type`
);
}
@ -316,7 +322,7 @@ export class IssuesProcessor {
)} was not specified`
);
issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
`Continuing the process for this $$type`
);
}
@ -350,14 +356,14 @@ export class IssuesProcessor {
issueLogger.info(
`This $$type should be stale based on the last update date the ${getHumanizedDate(
updatedAtDate
)} (${chalk.cyan(issue.updated_at)})`
)} (${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)
)} (${chalk.cyan(daysBeforeStale)})`
)} (${LoggerService.cyan(daysBeforeStale)})`
);
await this._markStale(issue, staleMessage, staleLabel, skipMessage);
issue.isStale = true; // This issue is now considered stale
@ -366,14 +372,14 @@ export class IssuesProcessor {
issueLogger.info(
`This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(
this._getDaysBeforeStaleUsedOptionName(issue)
)} (${chalk.cyan(daysBeforeStale)})`
)} (${LoggerService.cyan(daysBeforeStale)})`
);
}
} else {
issueLogger.info(
`This $$type should not be stale based on the last update date the ${getHumanizedDate(
updatedAtDate
)} (${chalk.cyan(issue.updated_at)})`
)} (${LoggerService.cyan(issue.updated_at)})`
);
}
}
@ -395,23 +401,25 @@ export class IssuesProcessor {
if (!this._operations.hasRemainingOperations()) {
this._logger.warning(
chalk.yellowBright('No more operations left! Exiting...')
LoggerService.yellowBright(`No more operations left! Exiting...`)
);
this._logger.warning(
chalk.yellowBright(
`If you think that not enough issues were processed you could try to increase the quantity related to the ${this._logger.createOptionLink(
Option.OperationsPerRun
)} option which is currently set to ${chalk.cyan(
this.options.operationsPerRun
)}`
)
`${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.OperationsPerRun
)} ${LoggerService.yellowBright(
'option which is currently set to'
)} ${LoggerService.cyan(this.options.operationsPerRun)}`
);
return 0;
}
this._logger.info(
chalk.green(`Batch ${chalk.cyan(`#${page}`)} processed.`)
`${LoggerService.green('Batch')} ${LoggerService.cyan(
`#${page}`
)} ${LoggerService.green('processed.')}`
);
// Do the next batch
@ -528,7 +536,9 @@ export class IssuesProcessor {
const issueLogger: IssueLogger = new IssueLogger(issue);
const markedStaleOn: string =
(await this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
issueLogger.info(`$$type marked stale on: ${chalk.cyan(markedStaleOn)}`);
issueLogger.info(
`$$type marked stale on: ${LoggerService.cyan(markedStaleOn)}`
);
const issueHasComments: boolean = await this._hasCommentsSince(
issue,
@ -536,7 +546,7 @@ export class IssuesProcessor {
actor
);
issueLogger.info(
`$$type has been commented on: ${chalk.cyan(issueHasComments)}`
`$$type has been commented on: ${LoggerService.cyan(issueHasComments)}`
);
const daysBeforeClose: number = issue.isPullRequest
@ -544,14 +554,16 @@ export class IssuesProcessor {
: this._getDaysBeforeIssueClose();
issueLogger.info(
`Days before $$type close: ${chalk.cyan(daysBeforeClose)}`
`Days before $$type close: ${LoggerService.cyan(daysBeforeClose)}`
);
const issueHasUpdate: boolean = IssuesProcessor._updatedSince(
issue.updated_at,
daysBeforeClose
);
issueLogger.info(`$$type has been updated: ${chalk.cyan(issueHasUpdate)}`);
issueLogger.info(
`$$type has been updated: ${LoggerService.cyan(issueHasUpdate)}`
);
// should we un-stale this issue?
if (this._shouldRemoveStaleWhenUpdated(issue) && issueHasComments) {
@ -569,7 +581,7 @@ export class IssuesProcessor {
if (!issueHasComments && !issueHasUpdate) {
issueLogger.info(
`Closing $$type because it was last updated on! ${chalk.cyan(
`Closing $$type because it was last updated on! ${LoggerService.cyan(
issue.updated_at
)}`
);
@ -600,7 +612,7 @@ export class IssuesProcessor {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(
`Checking for comments on $$type since: ${chalk.cyan(sinceDate)}`
`Checking for comments on $$type since: ${LoggerService.cyan(sinceDate)}`
);
if (!sinceDate) {
@ -615,7 +627,7 @@ export class IssuesProcessor {
);
issueLogger.info(
`Comments not made by actor or another bot: ${chalk.cyan(
`Comments not made by actor or another bot: ${LoggerService.cyan(
filteredComments.length
)}`
);
@ -779,7 +791,7 @@ export class IssuesProcessor {
const branch = pullRequest.head.ref;
issueLogger.info(
`Deleting the branch "${chalk.cyan(branch)}" from closed $$type`
`Deleting the branch "${LoggerService.cyan(branch)}" from closed $$type`
);
try {
@ -792,9 +804,9 @@ export class IssuesProcessor {
});
} catch (error) {
issueLogger.error(
`Error when deleting the branch "${chalk.cyan(branch)}" from $$type: ${
error.message
}`
`Error when deleting the branch "${LoggerService.cyan(
branch
)}" from $$type: ${error.message}`
);
}
}
@ -804,7 +816,7 @@ export class IssuesProcessor {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(
`Removing the label "${chalk.cyan(label)}" from this $$type...`
`Removing the label "${LoggerService.cyan(label)}" from this $$type...`
);
this.removedLabelIssues.push(issue);
@ -821,10 +833,10 @@ export class IssuesProcessor {
issue_number: issue.number,
name: label
});
issueLogger.info(`The label "${chalk.cyan(label)}" was removed`);
issueLogger.info(`The label "${LoggerService.cyan(label)}" was removed`);
} catch (error) {
issueLogger.error(
`Error when removing the label: "${chalk.cyan(error.message)}"`
`Error when removing the label: "${LoggerService.cyan(error.message)}"`
);
}
}
@ -929,7 +941,7 @@ export class IssuesProcessor {
if (isLabeled(issue, closeLabel)) {
issueLogger.info(
`The $$type has a close label "${chalk.cyan(
`The $$type has a close label "${LoggerService.cyan(
closeLabel
)}". Removing the close label...`
);

View File

@ -26,12 +26,17 @@ describe('IssueLogger', (): void => {
});
it('should log a warning with the given message and with the issue number as prefix', (): void => {
expect.assertions(2);
expect.assertions(3);
issueLogger.warning(message);
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith('[#8] dummy-message');
expect(coreWarningSpy).toHaveBeenCalledWith(
expect.stringContaining('[#8]')
);
expect(coreWarningSpy).toHaveBeenCalledWith(
expect.stringContaining('dummy-message')
);
});
});
@ -52,12 +57,15 @@ describe('IssueLogger', (): void => {
});
it('should log an information with the given message and with the issue number as prefix', (): void => {
expect.assertions(2);
expect.assertions(3);
issueLogger.info(message);
expect(coreInfoSpy).toHaveBeenCalledTimes(1);
expect(coreInfoSpy).toHaveBeenCalledWith('[#8] dummy-message');
expect(coreInfoSpy).toHaveBeenCalledWith(expect.stringContaining('[#8]'));
expect(coreInfoSpy).toHaveBeenCalledWith(
expect.stringContaining('dummy-message')
);
});
});
@ -78,17 +86,22 @@ describe('IssueLogger', (): void => {
});
it('should log an error with the given message and with the issue number as prefix', (): void => {
expect.assertions(2);
expect.assertions(3);
issueLogger.error(message);
expect(coreErrorSpy).toHaveBeenCalledTimes(1);
expect(coreErrorSpy).toHaveBeenCalledWith('[#8] dummy-message');
expect(coreErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('[#8]')
);
expect(coreErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('dummy-message')
);
});
});
it('should prefix the message with the issue number', (): void => {
expect.assertions(2);
expect.assertions(3);
message = 'dummy-message';
issue = new Issue(
DefaultProcessorOptions,
@ -102,7 +115,12 @@ describe('IssueLogger', (): void => {
issueLogger.warning(message);
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith('[#123] dummy-message');
expect(coreWarningSpy).toHaveBeenCalledWith(
expect.stringContaining('[#123]')
);
expect(coreWarningSpy).toHaveBeenCalledWith(
expect.stringContaining('dummy-message')
);
});
it.each`
@ -114,7 +132,7 @@ describe('IssueLogger', (): void => {
`(
'should replace the special tokens "$$type" with the corresponding type',
({pull_request, replacement}): void => {
expect.assertions(2);
expect.assertions(3);
message = 'The $$type will stale! $$type will soon be closed!';
issue = new Issue(
DefaultProcessorOptions,
@ -130,7 +148,12 @@ describe('IssueLogger', (): void => {
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith(
`[#8] The ${replacement} will stale! ${replacement} will soon be closed!`
expect.stringContaining(`[#8]`)
);
expect(coreWarningSpy).toHaveBeenCalledWith(
expect.stringContaining(
`The ${replacement} will stale! ${replacement} will soon be closed!`
)
);
}
);
@ -144,7 +167,7 @@ describe('IssueLogger', (): void => {
`(
'should replace the special token "$$type" with the corresponding type with first letter as uppercase',
({pull_request, replacement}): void => {
expect.assertions(2);
expect.assertions(3);
message = '$$type will stale';
issue = new Issue(
DefaultProcessorOptions,
@ -160,7 +183,10 @@ describe('IssueLogger', (): void => {
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith(
`[#8] ${replacement} will stale`
expect.stringContaining(`[#8]`)
);
expect(coreWarningSpy).toHaveBeenCalledWith(
expect.stringContaining(`${replacement} will stale`)
);
}
);

View File

@ -1,6 +1,6 @@
import chalk from 'chalk';
import {Issue} from '../issue';
import {Logger} from './logger';
import {LoggerService} from '../../services/logger.service';
/**
* @description
@ -70,10 +70,10 @@ export class IssueLogger extends Logger {
}
private _getIssuePrefix(): string {
return chalk.red(`[#${this._getIssueNumber()}]`);
return LoggerService.red(`[#${this._getIssueNumber()}]`);
}
private _getPullRequestPrefix(): string {
return chalk.blue(`[#${this._getIssueNumber()}]`);
return LoggerService.blue(`[#${this._getIssueNumber()}]`);
}
}

View File

@ -25,7 +25,9 @@ describe('Logger', (): void => {
logger.warning(message);
expect(coreWarningSpy).toHaveBeenCalledTimes(1);
expect(coreWarningSpy).toHaveBeenCalledWith('dummy-message');
expect(coreWarningSpy).toHaveBeenCalledWith(
expect.stringContaining('dummy-message')
);
});
});
@ -46,7 +48,9 @@ describe('Logger', (): void => {
logger.info(message);
expect(coreInfoSpy).toHaveBeenCalledTimes(1);
expect(coreInfoSpy).toHaveBeenCalledWith('dummy-message');
expect(coreInfoSpy).toHaveBeenCalledWith(
expect.stringContaining('dummy-message')
);
});
});
@ -67,7 +71,9 @@ describe('Logger', (): void => {
logger.error(message);
expect(coreErrorSpy).toHaveBeenCalledTimes(1);
expect(coreErrorSpy).toHaveBeenCalledWith('dummy-message');
expect(coreErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('dummy-message')
);
});
});
});

View File

@ -1,19 +1,19 @@
import * as core from '@actions/core';
import chalk from 'chalk';
import terminalLink from 'terminal-link';
import {Option} from '../../enums/option';
import {LoggerService} from '../../services/logger.service';
export class Logger {
warning(...message: string[]): void {
core.warning(chalk.whiteBright(...message));
core.warning(LoggerService.whiteBright(message.join(' ')));
}
info(...message: string[]): void {
core.info(chalk.whiteBright(...message));
core.info(LoggerService.whiteBright(message.join(' ')));
}
error(...message: string[]): void {
core.error(chalk.whiteBright(...message));
core.error(LoggerService.whiteBright(message.join(' ')));
}
createLink(name: Readonly<string>, link: Readonly<string>): string {
@ -21,7 +21,7 @@ export class Logger {
}
createOptionLink(option: Readonly<Option>): string {
return chalk.magenta(
return LoggerService.magenta(
this.createLink(option, `https://github.com/actions/stale#${option}`)
);
}

View File

@ -1,10 +1,10 @@
import chalk from 'chalk';
import deburr from 'lodash.deburr';
import {Option} from '../enums/option';
import {wordsToList} from '../functions/words-to-list';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {LoggerService} from '../services/logger.service';
type CleanMilestone = string;
@ -33,7 +33,7 @@ export class Milestones {
if (this._shouldExemptAllMilestones()) {
this._issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
'Skipping this $$type because it has a milestone'
);
@ -44,7 +44,7 @@ export class Milestones {
if (exemptMilestones.length === 0) {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`No milestone option was specified to skip the stale process for this $$type`
);
this._logSkip();
@ -53,8 +53,8 @@ export class Milestones {
}
this._issueLogger.info(
chalk.white('├──'),
`Found ${chalk.cyan(exemptMilestones.length)} milestone${
LoggerService.white('├──'),
`Found ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length > 1 ? 's' : ''
} that can exempt stale on this $$type`
);
@ -66,13 +66,13 @@ export class Milestones {
if (!hasExemptMilestone) {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
'No milestone on this $$type can exempt the stale process'
);
this._logSkip();
} else {
this._issueLogger.info(
chalk.white('└──'),
LoggerService.white('└──'),
'Skipping this $$type because it has an exempt milestone'
);
}
@ -89,7 +89,7 @@ export class Milestones {
private _getExemptIssueMilestones(): string[] {
if (this._options.exemptIssueMilestones === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
@ -97,7 +97,7 @@ export class Milestones {
if (this._options.exemptMilestones === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
@ -111,10 +111,10 @@ export class Milestones {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is set. ${chalk.cyan(exemptMilestones.length)} milestone${
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -127,10 +127,10 @@ export class Milestones {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptIssueMilestones
)} is set. ${chalk.cyan(exemptMilestones.length)} milestone${
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -141,7 +141,7 @@ export class Milestones {
private _getExemptPullRequestMilestones(): string[] {
if (this._options.exemptPrMilestones === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
@ -149,7 +149,7 @@ export class Milestones {
if (this._options.exemptMilestones === '') {
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is disabled. No specific milestone can skip the stale process for this $$type`
@ -163,10 +163,10 @@ export class Milestones {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptMilestones
)} is set. ${chalk.cyan(exemptMilestones.length)} milestone${
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -179,10 +179,10 @@ export class Milestones {
);
this._issueLogger.info(
chalk.white('├──'),
LoggerService.white('├──'),
`The option ${this._issueLogger.createOptionLink(
Option.ExemptPrMilestones
)} is set. ${chalk.cyan(exemptMilestones.length)} milestone${
)} is set. ${LoggerService.cyan(exemptMilestones.length)} milestone${
exemptMilestones.length === 1 ? '' : 's'
} can skip the stale process for this $$type`
);
@ -205,8 +205,10 @@ export class Milestones {
if (isSameMilestone) {
this._issueLogger.info(
chalk.white('├──'),
`The milestone "${milestone}" is set on this $$type and is an exempt milestone`
LoggerService.white('├──'),
`The milestone "${LoggerService.cyan(
milestone
)}" is set on this $$type and is an exempt milestone`
);
}
@ -288,6 +290,9 @@ export class Milestones {
}
private _logSkip(): void {
this._issueLogger.info(chalk.white('└──'), 'Skip the milestones checks');
this._issueLogger.info(
LoggerService.white('└──'),
'Skip the milestones checks'
);
}
}

View File

@ -1,6 +1,6 @@
import chalk from 'chalk';
import {Issue} from './issue';
import {Logger} from './loggers/logger';
import {LoggerService} from '../services/logger.service';
interface IGroupValue {
name: string;
@ -163,7 +163,7 @@ export class Statistics {
}
logStats(): Statistics {
this._logger.info(chalk.yellow.bold('Statistics:'));
this._logger.info(LoggerService.yellow(LoggerService.bold(`Statistics:`)));
this._logProcessedIssuesAndPullRequestsCount();
this._logStaleIssuesAndPullRequestsCount();
this._logUndoStaleIssuesAndPullRequestsCount();
@ -440,7 +440,7 @@ export class Statistics {
private _logCount(name: Readonly<string>, count: Readonly<number>): void {
if (count > 0) {
this._logger.info(`${name}:`, chalk.cyan(count));
this._logger.info(`${name}:`, LoggerService.cyan(count));
}
}
@ -498,7 +498,10 @@ export class Statistics {
const prefix = index === onlyValuesSet.length - 1 ? '└──' : '├──';
this._logCount(
`${chalk.white(prefix)} ${value.name.padEnd(longestValue, ' ')}`,
`${LoggerService.white(prefix)} ${value.name.padEnd(
longestValue,
' '
)}`,
value.count
);
}

View File

@ -0,0 +1,52 @@
import styles, {Modifier, ForegroundColor} from 'ansi-styles';
type Message = string | number | boolean;
export class LoggerService {
static whiteBright(message: Readonly<Message>): string {
return this._format(message, 'whiteBright');
}
static yellowBright(message: Readonly<Message>): string {
return this._format(message, 'yellowBright');
}
static magenta(message: Readonly<Message>): string {
return this._format(message, 'magenta');
}
static cyan(message: Readonly<Message>): string {
return this._format(message, 'cyan');
}
static yellow(message: Readonly<Message>): string {
return this._format(message, 'yellow');
}
static white(message: Readonly<Message>): string {
return this._format(message, 'white');
}
static green(message: Readonly<Message>): string {
return this._format(message, 'green');
}
static red(message: Readonly<Message>): string {
return this._format(message, 'red');
}
static blue(message: Readonly<Message>): string {
return this._format(message, 'blue');
}
static bold(message: Readonly<Message>): string {
return this._format(message, 'bold');
}
private static _format(
message: Readonly<Message>,
style: keyof Modifier | keyof ForegroundColor
): string {
return `${styles[style].open}${message}${styles[style].close}`;
}
}