From 4fa1b85ccc7aaa7145f2fb14ce9b34147b2d6aa1 Mon Sep 17 00:00:00 2001 From: Prokop Simek Date: Sat, 30 Nov 2019 14:04:09 +0100 Subject: [PATCH 1/6] feat: collect data from practices --- .../DependenciesVersionMajorLevel.ts | 43 ++++++++++--------- src/practices/PracticeBase.ts | 26 +++++++++++ 2 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 src/practices/PracticeBase.ts diff --git a/src/practices/JavaScript/DependenciesVersionMajorLevel.ts b/src/practices/JavaScript/DependenciesVersionMajorLevel.ts index 8b5845adf..8e7038bb7 100644 --- a/src/practices/JavaScript/DependenciesVersionMajorLevel.ts +++ b/src/practices/JavaScript/DependenciesVersionMajorLevel.ts @@ -4,7 +4,7 @@ import { Package } from '../../inspectors/IPackageInspector'; import { PackageInspectorBase, SemverLevel } from '../../inspectors/package/PackageInspectorBase'; import { PracticeEvaluationResult, PracticeImpact, ProgrammingLanguage } from '../../model'; import { DxPractice } from '../DxPracticeDecorator'; -import { IPractice } from '../IPractice'; +import { PracticeBase } from '../PracticeBase'; @DxPractice({ id: 'JavaScript.DependenciesVersionMajorLevel', @@ -14,7 +14,7 @@ import { IPractice } from '../IPractice'; reportOnlyOnce: true, url: 'https://renovatebot.com/', }) -export class DependenciesVersionMajorLevel implements IPractice { +export class DependenciesVersionMajorLevel extends PracticeBase { async isApplicable(ctx: PracticeContext): Promise { return ( ctx.projectComponent.language === ProgrammingLanguage.JavaScript || ctx.projectComponent.language === ProgrammingLanguage.TypeScript @@ -22,22 +22,20 @@ export class DependenciesVersionMajorLevel implements IPractice { } async evaluate(ctx: PracticeContext): Promise { - if (ctx.fileInspector === undefined || ctx.packageInspector === undefined) { + if (!ctx.fileInspector || !ctx.packageInspector) { return PracticeEvaluationResult.unknown; } const pkgs = ctx.packageInspector.packages; - if (pkgs === undefined) { + if (!pkgs) { return PracticeEvaluationResult.unknown; } - const result = await DependenciesVersionMajorLevel.runNcu(pkgs); - const practiceEvaluationResult = DependenciesVersionMajorLevel.isPracticing(result, SemverLevel.major, pkgs); - - return practiceEvaluationResult || PracticeEvaluationResult.practicing; + const result = await this.runNcu(pkgs); + return this.isPracticing(result, SemverLevel.major, pkgs); } - static async runNcu(pkgs: Package[] | undefined) { + async runNcu(pkgs: Package[] | undefined) { const fakePkgJson: { dependencies: { [key: string]: string } } = { dependencies: {} }; pkgs && @@ -45,30 +43,33 @@ export class DependenciesVersionMajorLevel implements IPractice { fakePkgJson.dependencies[p.name] = p.requestedVersion.value; }); - const result = await ncu.run({ + const pkgsToBeUpdated = await ncu.run({ packageData: JSON.stringify(fakePkgJson), }); - return result; + return pkgsToBeUpdated; } - static isPracticing( - result: { [key: string]: string }, - semverVersion: SemverLevel, - pkgs: Package[], - ): PracticeEvaluationResult | undefined { - for (const packageName in result) { - const parsedVersion = PackageInspectorBase.semverToPackageVersion(result[packageName]); + isPracticing(pkgsWithNewVersion: { [key: string]: string }, semverLevel: SemverLevel, pkgs: Package[]): PracticeEvaluationResult { + // packages with Major level to be updated + const pkgsToUpdate: { name: string; newVersion: string; currentVersion: string }[] = []; + + for (const packageName in pkgsWithNewVersion) { + const parsedVersion = PackageInspectorBase.semverToPackageVersion(pkgsWithNewVersion[packageName]); if (parsedVersion) { for (const pkg of pkgs) { if (pkg.name === packageName) { - if (parsedVersion[semverVersion] > pkg.lockfileVersion[semverVersion]) { - return PracticeEvaluationResult.notPracticing; + if (parsedVersion[semverLevel] > pkg.lockfileVersion[semverLevel]) { + pkgsToUpdate.push({ name: pkg.name, newVersion: parsedVersion.value, currentVersion: pkg.lockfileVersion.value }); } } } } } - return undefined; + + this.data.detail = 'any'; + + if (pkgsToUpdate.length > 0) return PracticeEvaluationResult.notPracticing; + return PracticeEvaluationResult.practicing; } } diff --git a/src/practices/PracticeBase.ts b/src/practices/PracticeBase.ts new file mode 100644 index 000000000..0b8c71d13 --- /dev/null +++ b/src/practices/PracticeBase.ts @@ -0,0 +1,26 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ + +import { IPractice } from './IPractice'; +import { ErrorFactory } from '../lib/errors'; +import { PracticeEvaluationResult } from '../model'; +import { PracticeContext } from '../contexts/practice/PracticeContext'; + +export abstract class PracticeBase implements IPractice { + data: T; + + constructor() { + this.data = {}; + } + + async isApplicable(ctx: PracticeContext): Promise { + return true; + } + + async evaluate(ctx: PracticeContext): Promise { + throw ErrorFactory.newInternalError('Method not implemented.'); + } +} + +type PracticeBaseData = { + detail?: string; +}; From 30458ce78eae571eae3b4581ce34b4ac4455ae51 Mon Sep 17 00:00:00 2001 From: Prokop Simek Date: Wed, 4 Dec 2019 09:02:24 +0100 Subject: [PATCH 2/6] feat(CLIReporter): show detailed info (collected data) from practices --- .vscode/settings.json | 3 +- package.json | 2 ++ src/model.ts | 36 +++++++++---------- src/practices/IPractice.ts | 11 +++++- .../DependenciesVersionMajorLevel.ts | 25 +++++++------ .../DependenciesVersionMinorPatchLevel.ts | 16 ++++----- src/practices/PracticeBase.ts | 10 ++---- src/reporters/CLIReporter.ts | 26 ++++++++------ src/reporters/IReporter.ts | 3 +- src/reporters/ReporterData.ts | 17 +++++++++ src/scanner/Scanner.ts | 3 +- yarn.lock | 17 ++++++++- 12 files changed, 108 insertions(+), 61 deletions(-) create mode 100644 src/reporters/ReporterData.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 9bd35b459..ba1817c22 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,5 +27,6 @@ "language": "typescriptreact", "autoFix": true } - ] + ], + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/package.json b/package.json index e3e155c89..d9f3b8167 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@octokit/rest": "16.35.0", "@types/eslint": "6.1.3", "@types/js-yaml": "3.12.1", + "@types/table": "^4.0.7", "axios": "0.19.0", "bitbucket": "1.15.2", "colors": "1.4.0", @@ -51,6 +52,7 @@ "reflect-metadata": "0.1.13", "semver": "6.3.0", "simple-git": "1.126.0", + "table": "^5.4.6", "toposort": "2.0.2", "ts-node": "8.5.2", "tslib": "1.10.0", diff --git a/src/model.ts b/src/model.ts index 505973724..022585de4 100644 --- a/src/model.ts +++ b/src/model.ts @@ -72,24 +72,24 @@ export interface Repository { authString?: string; } -export interface Project { - components: DeprecatedProjectComponent[]; -} - -/** - * @deprecated - */ -export interface DeprecatedProjectComponent { - githubUrl?: string; - path: string; - git?: GitInfo; - language: ProgrammingLanguage; - type: ProjectComponentType; - platform: ProjectComponentPlatform; - framework: ProjectComponentFramework; - packageManagement?: PackageManagement; - testing: TestingInfo; -} +// export interface Project { +// components: DeprecatedProjectComponent[]; +// } + +// /** +// * @deprecated +// */ +// export interface DeprecatedProjectComponent { +// githubUrl?: string; +// path: string; +// git?: GitInfo; +// language: ProgrammingLanguage; +// type: ProjectComponentType; +// platform: ProjectComponentPlatform; +// framework: ProjectComponentFramework; +// packageManagement?: PackageManagement; +// testing: TestingInfo; +// } export interface PracticeMetadata { id: string; diff --git a/src/practices/IPractice.ts b/src/practices/IPractice.ts index 9aa7e557a..e600b2fa9 100644 --- a/src/practices/IPractice.ts +++ b/src/practices/IPractice.ts @@ -1,7 +1,10 @@ import { PracticeEvaluationResult } from '../model'; import { PracticeContext } from '../contexts/practice/PracticeContext'; +import { ReportTable, ReportText } from '../reporters/ReporterData'; + +export interface IPractice { + data?: Partial & PracticeData; -export interface IPractice { /** * Returns true if this practice is applicable for the given project component * @@ -21,3 +24,9 @@ export interface IPractice { */ evaluate(ctx: PracticeContext): Promise; } + +export type PracticeData = { + details?: PracticeDetail[]; +}; + +export type PracticeDetail = ReportTable | ReportText; diff --git a/src/practices/JavaScript/DependenciesVersionMajorLevel.ts b/src/practices/JavaScript/DependenciesVersionMajorLevel.ts index 8e7038bb7..2c6e2b2ba 100644 --- a/src/practices/JavaScript/DependenciesVersionMajorLevel.ts +++ b/src/practices/JavaScript/DependenciesVersionMajorLevel.ts @@ -22,17 +22,17 @@ export class DependenciesVersionMajorLevel extends PracticeBase { } async evaluate(ctx: PracticeContext): Promise { - if (!ctx.fileInspector || !ctx.packageInspector) { + if (!ctx.fileInspector || !ctx.packageInspector || !ctx.packageInspector.packages) { return PracticeEvaluationResult.unknown; } - const pkgs = ctx.packageInspector.packages; - if (!pkgs) { - return PracticeEvaluationResult.unknown; - } const result = await this.runNcu(pkgs); - return this.isPracticing(result, SemverLevel.major, pkgs); + const pkgsToUpdate = this.packagesToBeUpdated(result, SemverLevel.major, pkgs); + this.setData(pkgsToUpdate); + + if (pkgsToUpdate.length > 0) return PracticeEvaluationResult.notPracticing; + return PracticeEvaluationResult.practicing; } async runNcu(pkgs: Package[] | undefined) { @@ -50,9 +50,9 @@ export class DependenciesVersionMajorLevel extends PracticeBase { return pkgsToBeUpdated; } - isPracticing(pkgsWithNewVersion: { [key: string]: string }, semverLevel: SemverLevel, pkgs: Package[]): PracticeEvaluationResult { + packagesToBeUpdated(pkgsWithNewVersion: { [key: string]: string }, semverLevel: SemverLevel, pkgs: Package[]) { // packages with Major level to be updated - const pkgsToUpdate: { name: string; newVersion: string; currentVersion: string }[] = []; + const pkgsToUpdate: PkgToUpdate[] = []; for (const packageName in pkgsWithNewVersion) { const parsedVersion = PackageInspectorBase.semverToPackageVersion(pkgsWithNewVersion[packageName]); @@ -67,9 +67,12 @@ export class DependenciesVersionMajorLevel extends PracticeBase { } } - this.data.detail = 'any'; + return pkgsToUpdate; + } - if (pkgsToUpdate.length > 0) return PracticeEvaluationResult.notPracticing; - return PracticeEvaluationResult.practicing; + setData(pkgsToUpdate: PkgToUpdate[]): void { + this.data.details = [{ headers: ['Name', 'New', 'Current'], data: pkgsToUpdate }]; } } + +export type PkgToUpdate = { name: string; newVersion: string; currentVersion: string }; diff --git a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts index 516b7efb4..09079b094 100644 --- a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts +++ b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts @@ -4,6 +4,7 @@ import { DxPractice } from '../DxPracticeDecorator'; import { IPractice } from '../IPractice'; import { DependenciesVersionMajorLevel } from './DependenciesVersionMajorLevel'; import { SemverLevel } from '../../inspectors/package/PackageInspectorBase'; +import { flatten } from 'lodash'; @DxPractice({ id: 'JavaScript.DependenciesVersionMinorPatchLevel', @@ -21,24 +22,21 @@ export class DependenciesVersionMinorPatchLevel extends DependenciesVersionMajor } async evaluate(ctx: PracticeContext): Promise { - if (ctx.fileInspector === undefined || ctx.packageInspector === undefined) { + if (!ctx.fileInspector || !ctx.packageInspector || !ctx.packageInspector.packages) { return PracticeEvaluationResult.unknown; } const pkgs = ctx.packageInspector.packages; - if (pkgs === undefined) { - return PracticeEvaluationResult.unknown; - } - const result = await DependenciesVersionMajorLevel.runNcu(pkgs); + const result = await this.runNcu(pkgs); - const patchLevel = DependenciesVersionMajorLevel.isPracticing(result, SemverLevel.patch, pkgs); - const minorLevel = DependenciesVersionMajorLevel.isPracticing(result, SemverLevel.minor, pkgs); + const patchLevelPkgs = this.packagesToBeUpdated(result, SemverLevel.patch, pkgs); + const minorLevelPkgs = this.packagesToBeUpdated(result, SemverLevel.minor, pkgs); + this.setData(flatten([patchLevelPkgs, minorLevelPkgs])); - if (patchLevel === PracticeEvaluationResult.notPracticing || minorLevel === PracticeEvaluationResult.notPracticing) { + if (patchLevelPkgs.length > 0 || minorLevelPkgs.length > 0) { return PracticeEvaluationResult.notPracticing; } - return PracticeEvaluationResult.practicing; } } diff --git a/src/practices/PracticeBase.ts b/src/practices/PracticeBase.ts index 0b8c71d13..37d7d35a9 100644 --- a/src/practices/PracticeBase.ts +++ b/src/practices/PracticeBase.ts @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { IPractice } from './IPractice'; +import { IPractice, PracticeData } from './IPractice'; import { ErrorFactory } from '../lib/errors'; import { PracticeEvaluationResult } from '../model'; import { PracticeContext } from '../contexts/practice/PracticeContext'; -export abstract class PracticeBase implements IPractice { - data: T; +export abstract class PracticeBase implements IPractice { + data: Partial & PracticeData; constructor() { this.data = {}; @@ -20,7 +20,3 @@ export abstract class PracticeBase implements IPract throw ErrorFactory.newInternalError('Method not implemented.'); } } - -type PracticeBaseData = { - detail?: string; -}; diff --git a/src/reporters/CLIReporter.ts b/src/reporters/CLIReporter.ts index 198c4cc7a..b2d5892e3 100644 --- a/src/reporters/CLIReporter.ts +++ b/src/reporters/CLIReporter.ts @@ -4,6 +4,7 @@ import { PracticeImpact, PracticeMetadata, PracticeEvaluationResult } from '../m import { IReporter, PracticeWithContextForReporter } from './IReporter'; import { sharedSubpath } from '../detectors/utils'; import { ReporterUtils } from './ReporterUtils'; +import { PracticeDetail } from '../practices/IPractice'; @injectable() export class CLIReporter implements IReporter { @@ -108,8 +109,12 @@ export class CLIReporter implements IReporter { for (const practiceWithContext of practices) { lines.push(this.linesForPractice(practiceWithContext.practice, color)); + if (practiceWithContext.practice.data?.details) { + lines.push(practiceWithContext.practice.data.details.map((d) => this.renderDetail(d, (color = grey))).join(' ')); + } + if (practiceWithContext.practice.impact !== practiceWithContext.overridenImpact) { - lines.push(bold(this.changedImpact(practiceWithContext, (color = grey)))); + lines.push(bold(this.lineForChangedImpact(practiceWithContext, (color = grey)))); } } @@ -127,16 +132,15 @@ export class CLIReporter implements IReporter { return practiceLineTexts.join(' '); } - private changedImpact(practiceWithContext: PracticeWithContextForReporter, color: Color) { - const practiceLineTexts = [ - reset( - color( - ` You changed impact of ${bold(practiceWithContext.practice.name)} from ${underline( - practiceWithContext.practice.impact, - )} to ${underline(practiceWithContext.overridenImpact)}.`, - ), + private lineForChangedImpact(practiceWithContext: PracticeWithContextForReporter, color: Color) { + return reset( + color( + ` Impact changed from ${underline(practiceWithContext.practice.impact)} to ${underline(practiceWithContext.overridenImpact)}.`, ), - ]; - return practiceLineTexts.join(' '); + ); + } + + private renderDetail(detail: PracticeDetail, color: Color) { + return reset(color(`${detail}`)); } } diff --git a/src/reporters/IReporter.ts b/src/reporters/IReporter.ts index 7f5313e05..f89893068 100644 --- a/src/reporters/IReporter.ts +++ b/src/reporters/IReporter.ts @@ -6,6 +6,7 @@ import { PracticeMetadata, PracticeEvaluationResult, } from '../model'; +import { PracticeData } from '../practices/IPractice'; export interface IReporter { report(practicesAndComponents: PracticeWithContextForReporter[]): string | JSONReport; @@ -22,7 +23,7 @@ export interface ComponentReport extends ProjectComponent { export interface PracticeWithContextForReporter { component: ProjectComponent; - practice: PracticeMetadata; + practice: PracticeMetadata & { data?: PracticeData }; overridenImpact: PracticeImpact; evaluation: PracticeEvaluationResult; isOn: boolean; diff --git a/src/reporters/ReporterData.ts b/src/reporters/ReporterData.ts new file mode 100644 index 000000000..39cceea01 --- /dev/null +++ b/src/reporters/ReporterData.ts @@ -0,0 +1,17 @@ +import { table as tableLib, getBorderCharacters, TableUserConfig } from 'table'; + +export class ReporterData { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + static table = (data: any[], userConfig?: TableUserConfig | undefined): string => { + return tableLib(data, { ...{ border: getBorderCharacters('norc') }, ...userConfig }); + }; +} + +export type ReportTable = { + headers: string[]; + data: Record[]; +}; + +export type ReportText = { + text: string; +}; diff --git a/src/scanner/Scanner.ts b/src/scanner/Scanner.ts index efe87e89e..bc806bba8 100644 --- a/src/scanner/Scanner.ts +++ b/src/scanner/Scanner.ts @@ -28,6 +28,7 @@ import { ScannerUtils } from './ScannerUtils'; import _ from 'lodash'; import { sharedSubpath } from '../detectors/utils'; import { cli } from 'cli-ux'; +import { PracticeData } from '../practices/IPractice'; @injectable() export class Scanner { @@ -182,7 +183,7 @@ export class Scanner { return { component: p.componentContext.projectComponent, - practice: p.practice.getMetadata(), + practice: { ...p.practice.getMetadata(), data: p.practice.data }, evaluation: p.evaluation, overridenImpact: (overridenImpact ? overridenImpact : p.practice.getMetadata().impact), isOn: p.isOn, diff --git a/yarn.lock b/yarn.lock index eaf20aec1..51fb9aef3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -866,6 +866,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/table@^4.0.7": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@types/table/-/table-4.0.7.tgz#c21100d37d4924abbbde85414170260d4d7b0316" + integrity sha512-HKtXvBxU8U8evZCSlUi9HbfT/SFW7nSGCoiBEheB06jAhXeW6JbGh8biEAqIFG5rZo9f8xeJVdIn455sddmIcw== + "@types/toposort@2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/toposort/-/toposort-2.0.3.tgz#dc490842b77c3e910c8d727ff0bdb2fb124cb41b" @@ -1027,7 +1032,7 @@ ajv@^6.10.0, ajv@^6.9.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.5.5: +ajv@^6.10.2, ajv@^6.5.5: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== @@ -8593,6 +8598,16 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +table@^5.4.6: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + taketalk@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/taketalk/-/taketalk-1.0.0.tgz#b4d4f0deed206ae7df775b129ea2ca6de52f26dd" From 2db8559f908d4e2a062c46e38c87da939de4e7cb Mon Sep 17 00:00:00 2001 From: Prokop Simek Date: Sun, 8 Dec 2019 12:48:50 +0100 Subject: [PATCH 3/6] feat(CLIReporter): add rich suggestion text to the report --- src/model.ts | 19 -------- .../DependenciesVersionMajorLevel.spec.ts | 6 +-- .../DependenciesVersionMajorLevel.ts | 9 ++-- ...DependenciesVersionMinorPatchLevel.spec.ts | 6 +-- .../DependenciesVersionMinorPatchLevel.ts | 8 ++-- .../JavaScript/DependenciesVersionPractice.ts | 46 ------------------- .../JsGitignoreCorrectlySetPractice.ts | 15 +++++- ...geJsonConfigurationSetCorrectlyPractice.ts | 14 ++++-- src/practices/PracticeBase.ts | 2 + .../TsGitignoreCorrectlySetPractice.ts | 16 ++++++- src/practices/index.ts | 8 ++-- src/reporters/CLIReporter.ts | 21 +++++++-- src/reporters/ReporterData.ts | 14 +++++- 13 files changed, 88 insertions(+), 96 deletions(-) delete mode 100644 src/practices/JavaScript/DependenciesVersionPractice.ts diff --git a/src/model.ts b/src/model.ts index 445c8d30f..765102c3b 100644 --- a/src/model.ts +++ b/src/model.ts @@ -73,25 +73,6 @@ export interface Repository { authString?: string; } -// export interface Project { -// components: DeprecatedProjectComponent[]; -// } - -// /** -// * @deprecated -// */ -// export interface DeprecatedProjectComponent { -// githubUrl?: string; -// path: string; -// git?: GitInfo; -// language: ProgrammingLanguage; -// type: ProjectComponentType; -// platform: ProjectComponentPlatform; -// framework: ProjectComponentFramework; -// packageManagement?: PackageManagement; -// testing: TestingInfo; -// } - export interface PracticeMetadata { id: string; name: string; diff --git a/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts b/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts index f1329478f..a06348ff0 100644 --- a/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts +++ b/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts @@ -1,5 +1,5 @@ import { PracticeEvaluationResult } from '../../model'; -import { DependenciesVersionMajorLevel } from './DependenciesVersionMajorLevel'; +import { DependenciesVersionMajorLevelPractice } from './DependenciesVersionMajorLevel'; import { createTestContainer, TestContainerContext } from '../../inversify.config'; import ncu from 'npm-check-updates'; import { JavaScriptPackageInspector } from '../../inspectors/package/JavaScriptPackageInspector'; @@ -7,7 +7,7 @@ import { mockPackage } from '../../test/helpers/mockPackage'; jest.mock('npm-check-updates'); describe('DependenciesVersionPractice of Major Level', () => { - let practice: DependenciesVersionMajorLevel; + let practice: DependenciesVersionMajorLevelPractice; let containerCtx: TestContainerContext; const mockedNcu = ncu.run; const MockedJSPackageInspector = >(JavaScriptPackageInspector); @@ -15,7 +15,7 @@ describe('DependenciesVersionPractice of Major Level', () => { beforeAll(async () => { containerCtx = createTestContainer(); - containerCtx.container.bind('DependenciesVersionMajorLevel').to(DependenciesVersionMajorLevel); + containerCtx.container.bind('DependenciesVersionMajorLevel').to(DependenciesVersionMajorLevelPractice); practice = containerCtx.container.get('DependenciesVersionMajorLevel'); mockJsPackageInspector = new MockedJSPackageInspector(); }); diff --git a/src/practices/JavaScript/DependenciesVersionMajorLevel.ts b/src/practices/JavaScript/DependenciesVersionMajorLevel.ts index 2c6e2b2ba..33ce18ae2 100644 --- a/src/practices/JavaScript/DependenciesVersionMajorLevel.ts +++ b/src/practices/JavaScript/DependenciesVersionMajorLevel.ts @@ -5,16 +5,17 @@ import { PackageInspectorBase, SemverLevel } from '../../inspectors/package/Pack import { PracticeEvaluationResult, PracticeImpact, ProgrammingLanguage } from '../../model'; import { DxPractice } from '../DxPracticeDecorator'; import { PracticeBase } from '../PracticeBase'; +import { ReportDetailType } from '../../reporters/ReporterData'; @DxPractice({ id: 'JavaScript.DependenciesVersionMajorLevel', name: 'Update Dependencies of Major Level', impact: PracticeImpact.small, - suggestion: 'Keep the dependencies updated to have all possible features. Use, for example, Renovate Bot.', + suggestion: 'Keep the dependencies updated to have all possible features. Use, for example, npm-check-updates.', reportOnlyOnce: true, - url: 'https://renovatebot.com/', + url: 'https://github.com/tjunnone/npm-check-updates', }) -export class DependenciesVersionMajorLevel extends PracticeBase { +export class DependenciesVersionMajorLevelPractice extends PracticeBase { async isApplicable(ctx: PracticeContext): Promise { return ( ctx.projectComponent.language === ProgrammingLanguage.JavaScript || ctx.projectComponent.language === ProgrammingLanguage.TypeScript @@ -71,7 +72,7 @@ export class DependenciesVersionMajorLevel extends PracticeBase { } setData(pkgsToUpdate: PkgToUpdate[]): void { - this.data.details = [{ headers: ['Name', 'New', 'Current'], data: pkgsToUpdate }]; + this.data.details = [{ type: ReportDetailType.table, headers: ['Name', 'New', 'Current'], data: pkgsToUpdate }]; } } diff --git a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts index e361075c1..c71c6b30a 100644 --- a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts +++ b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts @@ -3,11 +3,11 @@ import { mockPackage } from '../../test/helpers/mockPackage'; import { JavaScriptPackageInspector } from '../../inspectors/package/JavaScriptPackageInspector'; import { createTestContainer, TestContainerContext } from '../../inversify.config'; import { PracticeEvaluationResult } from '../../model'; -import { DependenciesVersionMinorPatchLevel } from './DependenciesVersionMinorPatchLevel'; +import { DependenciesVersionMinorPatchLevelPractice } from './DependenciesVersionMinorPatchLevel'; jest.mock('npm-check-updates'); describe('DependenciesVersionPractice of Minor and Patch Level', () => { - let practice: DependenciesVersionMinorPatchLevel; + let practice: DependenciesVersionMinorPatchLevelPractice; let containerCtx: TestContainerContext; const mockedNcu = ncu.run; const MockedJSPackageInspector = >(JavaScriptPackageInspector); @@ -15,7 +15,7 @@ describe('DependenciesVersionPractice of Minor and Patch Level', () => { beforeAll(async () => { containerCtx = createTestContainer(); - containerCtx.container.bind('DependenciesVersionMinorPatchLevel').to(DependenciesVersionMinorPatchLevel); + containerCtx.container.bind('DependenciesVersionMinorPatchLevel').to(DependenciesVersionMinorPatchLevelPractice); practice = containerCtx.container.get('DependenciesVersionMinorPatchLevel'); mockJsPackageInspector = new MockedJSPackageInspector(); }); diff --git a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts index 09079b094..6009f0948 100644 --- a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts +++ b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.ts @@ -2,7 +2,7 @@ import { PracticeContext } from '../../contexts/practice/PracticeContext'; import { PracticeEvaluationResult, PracticeImpact, ProgrammingLanguage } from '../../model'; import { DxPractice } from '../DxPracticeDecorator'; import { IPractice } from '../IPractice'; -import { DependenciesVersionMajorLevel } from './DependenciesVersionMajorLevel'; +import { DependenciesVersionMajorLevelPractice } from './DependenciesVersionMajorLevel'; import { SemverLevel } from '../../inspectors/package/PackageInspectorBase'; import { flatten } from 'lodash'; @@ -10,11 +10,11 @@ import { flatten } from 'lodash'; id: 'JavaScript.DependenciesVersionMinorPatchLevel', name: 'Update Dependencies of Minor and Patch Level', impact: PracticeImpact.high, - suggestion: 'Keep the dependencies updated to eliminate security concerns and compatibility issues. Use, for example, Renovate Bot.', + suggestion: 'Keep the dependencies updated to eliminate security concerns and compatibility issues. Use, for example, npm-check-updates.', reportOnlyOnce: true, - url: 'https://renovatebot.com/', + url: 'https://github.com/tjunnone/npm-check-updates', }) -export class DependenciesVersionMinorPatchLevel extends DependenciesVersionMajorLevel implements IPractice { +export class DependenciesVersionMinorPatchLevelPractice extends DependenciesVersionMajorLevelPractice implements IPractice { async isApplicable(ctx: PracticeContext): Promise { return ( ctx.projectComponent.language === ProgrammingLanguage.JavaScript || ctx.projectComponent.language === ProgrammingLanguage.TypeScript diff --git a/src/practices/JavaScript/DependenciesVersionPractice.ts b/src/practices/JavaScript/DependenciesVersionPractice.ts deleted file mode 100644 index 769cc6f75..000000000 --- a/src/practices/JavaScript/DependenciesVersionPractice.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { PracticeImpact, PracticeEvaluationResult, ProgrammingLanguage } from '../../model'; -import { DxPractice } from '../DxPracticeDecorator'; -import { IPractice } from '../IPractice'; -import { PracticeContext } from '../../contexts/practice/PracticeContext'; -import _ from 'lodash'; -import ncu from 'npm-check-updates'; - -@DxPractice({ - id: 'LanguageIndependent.DependenciesVersion', - name: 'Update Dependencies', - impact: PracticeImpact.high, - suggestion: 'Keep the dependencies updated to eliminate security concerns and compatibility issues. Use, for example, Renovate Bot.', - reportOnlyOnce: true, - url: 'https://renovatebot.com/', -}) -export class DependenciesVersionPractice implements IPractice { - async isApplicable(ctx: PracticeContext): Promise { - return ( - ctx.projectComponent.language === ProgrammingLanguage.JavaScript || ctx.projectComponent.language === ProgrammingLanguage.TypeScript - ); - } - - async evaluate(ctx: PracticeContext): Promise { - if (!ctx.fileInspector || !ctx.packageInspector) { - return PracticeEvaluationResult.unknown; - } - - const pkgs = ctx.packageInspector.packages; - const fakePkgJson: { dependencies: { [key: string]: string } } = { dependencies: {} }; - - pkgs && - pkgs.forEach((p) => { - fakePkgJson.dependencies[p.name] = p.requestedVersion.value; - }); - - const result = await ncu.run({ - packageData: JSON.stringify(fakePkgJson), - }); - - if (_.keys(result).length === 0) { - return PracticeEvaluationResult.practicing; - } - - return PracticeEvaluationResult.notPracticing; - } -} diff --git a/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts b/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts index 99fb0c76d..09d5a35d0 100644 --- a/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts +++ b/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts @@ -2,6 +2,8 @@ import { IPractice } from '../IPractice'; import { PracticeEvaluationResult, PracticeImpact, ProgrammingLanguage } from '../../model'; import { DxPractice } from '../DxPracticeDecorator'; import { PracticeContext } from '../../contexts/practice/PracticeContext'; +import { PracticeBase } from '../PracticeBase'; +import { ReportDetailType } from '../../reporters/ReporterData'; @DxPractice({ id: 'JavaScript.GitignoreCorrectlySet', @@ -12,7 +14,7 @@ import { PracticeContext } from '../../contexts/practice/PracticeContext'; url: 'https://github.com/github/gitignore/blob/master/Node.gitignore', dependsOn: { practicing: ['LanguageIndependent.GitignoreIsPresent'] }, }) -export class JsGitignoreCorrectlySetPractice implements IPractice { +export class JsGitignoreCorrectlySetPractice extends PracticeBase { async isApplicable(ctx: PracticeContext): Promise { return ctx.projectComponent.language === ProgrammingLanguage.JavaScript; } @@ -44,6 +46,17 @@ export class JsGitignoreCorrectlySetPractice implements IPractice { return PracticeEvaluationResult.practicing; } + this.setData(); return PracticeEvaluationResult.notPracticing; } + + private setData() { + this.data.details = [ + { + type: ReportDetailType.text, + text: + 'You should ignore one of lock file (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', + }, + ]; + } } diff --git a/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.ts b/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.ts index e996f3fb5..3e82bd9ae 100644 --- a/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.ts +++ b/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.ts @@ -1,7 +1,8 @@ -import { IPractice } from '../IPractice'; import { PracticeEvaluationResult, PracticeImpact, ProgrammingLanguage } from '../../model'; import { DxPractice } from '../DxPracticeDecorator'; import { PracticeContext } from '../../contexts/practice/PracticeContext'; +import { PracticeBase } from '../PracticeBase'; +import { ReportDetailType } from '../../reporters/ReporterData'; @DxPractice({ id: 'JavaScript.PackageJsonConfigurationSetCorrectly', @@ -13,7 +14,7 @@ import { PracticeContext } from '../../contexts/practice/PracticeContext'; url: 'https://docs.npmjs.com/files/package.json', dependsOn: { practicing: ['Javascript.PackageManagementUsed'] }, }) -export class JsPackageJsonConfigurationSetCorrectlyPractice implements IPractice { +export class JsPackageJsonConfigurationSetCorrectlyPractice extends PracticeBase { async isApplicable(ctx: PracticeContext): Promise { return ( ctx.projectComponent.language === ProgrammingLanguage.JavaScript || ctx.projectComponent.language === ProgrammingLanguage.TypeScript @@ -21,7 +22,7 @@ export class JsPackageJsonConfigurationSetCorrectlyPractice implements IPractice } async evaluate(ctx: PracticeContext): Promise { - if (ctx.fileInspector === undefined) { + if (!ctx.fileInspector) { return PracticeEvaluationResult.unknown; } @@ -49,6 +50,13 @@ export class JsPackageJsonConfigurationSetCorrectlyPractice implements IPractice return PracticeEvaluationResult.practicing; } + this.setData(); return PracticeEvaluationResult.notPracticing; } + + private setData() { + this.data.details = [ + { type: ReportDetailType.text, text: "The package.json doesn't have configured scripts correctly. The most common scripts are build, start, test and lint." } + ]; + } } diff --git a/src/practices/PracticeBase.ts b/src/practices/PracticeBase.ts index 37d7d35a9..68e07ad5a 100644 --- a/src/practices/PracticeBase.ts +++ b/src/practices/PracticeBase.ts @@ -4,7 +4,9 @@ import { IPractice, PracticeData } from './IPractice'; import { ErrorFactory } from '../lib/errors'; import { PracticeEvaluationResult } from '../model'; import { PracticeContext } from '../contexts/practice/PracticeContext'; +import { injectable } from 'inversify'; +@injectable() export abstract class PracticeBase implements IPractice { data: Partial & PracticeData; diff --git a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts index e21ff52db..242686c96 100644 --- a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts +++ b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts @@ -1,7 +1,8 @@ -import { IPractice } from '../IPractice'; import { PracticeEvaluationResult, PracticeImpact, ProgrammingLanguage } from '../../model'; import { DxPractice } from '../DxPracticeDecorator'; import { PracticeContext } from '../../contexts/practice/PracticeContext'; +import { PracticeBase } from '../PracticeBase'; +import { ReportDetailType } from '../../reporters/ReporterData'; @DxPractice({ id: 'TypeScript.GitignoreCorrectlySet', @@ -12,7 +13,7 @@ import { PracticeContext } from '../../contexts/practice/PracticeContext'; url: 'https://github.com/github/gitignore/blob/master/Node.gitignore', dependsOn: { practicing: ['LanguageIndependent.GitignoreIsPresent'] }, }) -export class TsGitignoreCorrectlySetPractice implements IPractice { +export class TsGitignoreCorrectlySetPractice extends PracticeBase { async isApplicable(ctx: PracticeContext): Promise { return ctx.projectComponent.language === ProgrammingLanguage.TypeScript; } @@ -54,6 +55,17 @@ export class TsGitignoreCorrectlySetPractice implements IPractice { return PracticeEvaluationResult.practicing; } + this.setData(); return PracticeEvaluationResult.notPracticing; } + + private setData() { + this.data.details = [ + { + type: ReportDetailType.text, + text: + 'You should ignore one of lock file (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', + }, + ]; + } } diff --git a/src/practices/index.ts b/src/practices/index.ts index 942a979ef..58644be43 100644 --- a/src/practices/index.ts +++ b/src/practices/index.ts @@ -17,11 +17,11 @@ import { EditorConfigIsPresentPractice } from './LanguageIndependent/EditorConfi import { GitignoreIsPresentPractice } from './LanguageIndependent/GitignoreIsPresentPractice'; import { JsGitignoreCorrectlySetPractice } from './JavaScript/JsGitignoreCorrectlySetPractice'; import { JavaGitignoreCorrectlySetPractice } from './Java/JavaGitignoreCorrectlySetPractice'; -import { DependenciesVersionMajorLevel } from './JavaScript/DependenciesVersionMajorLevel'; +import { DependenciesVersionMajorLevelPractice } from './JavaScript/DependenciesVersionMajorLevel'; import { ESLintWithoutErrorsPractice } from './JavaScript/ESLintWithoutErrorsPractice'; import { TsGitignoreCorrectlySetPractice } from './TypeScript/TsGitignoreCorrectlySetPractice'; import { DoesPullRequestsPractice } from './LanguageIndependent/DoesPullRequests'; -import { DependenciesVersionMinorPatchLevel } from './JavaScript/DependenciesVersionMinorPatchLevel'; +import { DependenciesVersionMinorPatchLevelPractice } from './JavaScript/DependenciesVersionMinorPatchLevel'; import { CorrectCommitMessagesPractice } from './LanguageIndependent/CorrectCommitMessagesPractice'; // register practices here @@ -43,8 +43,8 @@ export const practices = [ DeprecatedTSLintPractice, DockerizationUsedPractice, EditorConfigIsPresentPractice, - DependenciesVersionMajorLevel, - DependenciesVersionMinorPatchLevel, + DependenciesVersionMajorLevelPractice, + DependenciesVersionMinorPatchLevelPractice, GitignoreIsPresentPractice, JsGitignoreCorrectlySetPractice, JavaGitignoreCorrectlySetPractice, diff --git a/src/reporters/CLIReporter.ts b/src/reporters/CLIReporter.ts index 6afba0944..236e19a96 100644 --- a/src/reporters/CLIReporter.ts +++ b/src/reporters/CLIReporter.ts @@ -2,10 +2,11 @@ import { blue, bold, Color, green, grey, italic, red, reset, underline, yellow, import { injectable } from 'inversify'; import { PracticeImpact, PracticeMetadata, PracticeEvaluationResult } from '../model'; import { IReporter, PracticeWithContextForReporter } from './IReporter'; -import { sharedSubpath } from '../detectors/utils'; import { ReporterUtils } from './ReporterUtils'; import { PracticeDetail } from '../practices/IPractice'; import { GitServiceUtils } from '../services/git/GitServiceUtils'; +import { ReportDetailType, ReporterData } from './ReporterData'; +import { assertNever } from '../lib/assertNever'; @injectable() export class CLIReporter implements IReporter { @@ -106,11 +107,12 @@ export class CLIReporter implements IReporter { lines.push(this.linesForPractice(practiceWithContext.practice, color)); if (practiceWithContext.practice.data?.details) { - lines.push(practiceWithContext.practice.data.details.map((d) => this.renderDetail(d, (color = grey))).join(' ')); + const linesWithDetail = practiceWithContext.practice.data.details.map((d) => this.renderDetail(d)).join(' '); + lines.push(reset(grey(linesWithDetail))); } if (practiceWithContext.practice.impact !== practiceWithContext.overridenImpact) { - lines.push(bold(this.lineForChangedImpact(practiceWithContext, (color = grey)))); + lines.push(reset(bold(this.lineForChangedImpact(practiceWithContext, grey)))); } } @@ -136,7 +138,16 @@ export class CLIReporter implements IReporter { ); } - private renderDetail(detail: PracticeDetail, color: Color) { - return reset(color(`${detail}`)); + private renderDetail(detail: PracticeDetail) { + switch (detail.type) { + case ReportDetailType.table: + return ReporterData.table(detail.headers, detail.data); + + case ReportDetailType.text: + return detail.text; + + default: + return assertNever(detail); + } } } diff --git a/src/reporters/ReporterData.ts b/src/reporters/ReporterData.ts index 39cceea01..e7c862d2c 100644 --- a/src/reporters/ReporterData.ts +++ b/src/reporters/ReporterData.ts @@ -2,16 +2,26 @@ import { table as tableLib, getBorderCharacters, TableUserConfig } from 'table'; export class ReporterData { // eslint-disable-next-line @typescript-eslint/no-explicit-any - static table = (data: any[], userConfig?: TableUserConfig | undefined): string => { - return tableLib(data, { ...{ border: getBorderCharacters('norc') }, ...userConfig }); + static table = (headers: string[], data: Record[], userConfig?: TableUserConfig | undefined): string => { + const tableData = data.map(Object.values); + + tableData.unshift(headers); + return tableLib(tableData, { ...{ border: getBorderCharacters('norc'), singleLine: true }, ...userConfig }); }; } export type ReportTable = { + type: ReportDetailType.table; headers: string[]; data: Record[]; }; export type ReportText = { + type: ReportDetailType.text; text: string; }; + +export enum ReportDetailType { + table = 'table', + text = 'text', +} From 69e0b3e40521fdf2d54d1b3f87a1dd5eea61ff08 Mon Sep 17 00:00:00 2001 From: Prokop Simek Date: Sun, 8 Dec 2019 13:50:25 +0100 Subject: [PATCH 4/6] chore: add more tests --- src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts | 1 + .../JavaScript/DependenciesVersionMinorPatchLevel.spec.ts | 1 + .../JavaScript/JsGitignoreCorrectlySetPractice.spec.ts | 1 + .../JsPackageJsonConfigurationSetCorrectlyPractice.spec.ts | 1 + .../TypeScript/TsGitignoreCorrectlySetPractice.spec.ts | 1 + src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts | 2 +- 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts b/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts index a06348ff0..523a2a088 100644 --- a/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts +++ b/src/practices/JavaScript/DependenciesVersionMajorLevel.spec.ts @@ -34,6 +34,7 @@ describe('DependenciesVersionPractice of Major Level', () => { const evaluated = await practice.evaluate(containerCtx.practiceContext); expect(evaluated).toEqual(PracticeEvaluationResult.notPracticing); + expect(practice.data.details).not.toBeUndefined(); }); it('practicing if newest package version dependency of major level', async () => { diff --git a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts index c71c6b30a..78c4310e0 100644 --- a/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts +++ b/src/practices/JavaScript/DependenciesVersionMinorPatchLevel.spec.ts @@ -34,6 +34,7 @@ describe('DependenciesVersionPractice of Minor and Patch Level', () => { const evaluated = await practice.evaluate(containerCtx.practiceContext); expect(evaluated).toEqual(PracticeEvaluationResult.notPracticing); + expect(practice.data.details).not.toBeUndefined(); }); it('practicing if newest package version dependency of minor or patch level', async () => { diff --git a/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.spec.ts b/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.spec.ts index 45ddb15f9..cb86af25f 100644 --- a/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.spec.ts +++ b/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.spec.ts @@ -34,6 +34,7 @@ describe('JsGitignoreCorrectlySetPractice', () => { const evaluated = await practice.evaluate(containerCtx.practiceContext); expect(evaluated).toEqual(PracticeEvaluationResult.notPracticing); + expect(practice.data.details).not.toBeUndefined(); }); it('Returns unknown if there is no fileInspector', async () => { diff --git a/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.spec.ts b/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.spec.ts index 67de25a38..0f1c1a473 100644 --- a/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.spec.ts +++ b/src/practices/JavaScript/JsPackageJsonConfigurationSetCorrectlyPractice.spec.ts @@ -32,6 +32,7 @@ describe('JsPackageJsonConfigurationSetCorrectlyPractice', () => { const evaluated = await practice.evaluate(containerCtx.practiceContext); expect(evaluated).toEqual(PracticeEvaluationResult.notPracticing); + expect(practice.data.details).not.toBeUndefined(); }); it('Returns unknown if there are no file inspector', async () => { diff --git a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.spec.ts b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.spec.ts index f4dccca44..b7baf6c82 100644 --- a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.spec.ts +++ b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.spec.ts @@ -34,6 +34,7 @@ describe('TsGitignoreCorrectlySetPractice', () => { const evaluated = await practice.evaluate(containerCtx.practiceContext); expect(evaluated).toEqual(PracticeEvaluationResult.notPracticing); + expect(practice.data.details).not.toBeUndefined(); }); it('Returns unknown if there is no fileInspector', async () => { diff --git a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts index 242686c96..a2fad8996 100644 --- a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts +++ b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts @@ -64,7 +64,7 @@ export class TsGitignoreCorrectlySetPractice extends PracticeBase { { type: ReportDetailType.text, text: - 'You should ignore one of lock file (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', + 'You should ignore one of build folder (build, dist or lib), one of lock file (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', }, ]; } From b883dcad0203b79995550d9d8b676840bdbcab4a Mon Sep 17 00:00:00 2001 From: Prokop Simek Date: Mon, 9 Dec 2019 15:54:04 +0100 Subject: [PATCH 5/6] chore: better wording in a detail text Co-Authored-By: Adela Homolova <53510747+adelkahomolova@users.noreply.github.com> --- src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts b/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts index 09d5a35d0..ecdc7d98d 100644 --- a/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts +++ b/src/practices/JavaScript/JsGitignoreCorrectlySetPractice.ts @@ -55,7 +55,7 @@ export class JsGitignoreCorrectlySetPractice extends PracticeBase { { type: ReportDetailType.text, text: - 'You should ignore one of lock file (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', + 'You should ignore one of the lock files (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', }, ]; } From 506372827392359e73ba40c230e7c12f48fb9ded Mon Sep 17 00:00:00 2001 From: Prokop Simek Date: Mon, 9 Dec 2019 15:54:14 +0100 Subject: [PATCH 6/6] chore: better wording in a detail text Co-Authored-By: Adela Homolova <53510747+adelkahomolova@users.noreply.github.com> --- src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts index a2fad8996..57bd20809 100644 --- a/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts +++ b/src/practices/TypeScript/TsGitignoreCorrectlySetPractice.ts @@ -64,7 +64,7 @@ export class TsGitignoreCorrectlySetPractice extends PracticeBase { { type: ReportDetailType.text, text: - 'You should ignore one of build folder (build, dist or lib), one of lock file (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', + 'You should ignore one of the build folders (build, dist or lib), one of the lock files (package-lock.json or yarn.lock), node_modules folder, coverage folder and log files (*.log)', }, ]; }