From 938d72725dc536cb42feb9a0137ea86018925729 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 2 Oct 2023 03:48:01 +0200 Subject: [PATCH 1/4] refactor(models): refactor for move --- package-lock.json | 316 ------------------ packages/cli/package.json | 1 - packages/cli/src/lib/cli.spec.ts | 17 +- packages/cli/src/lib/cli.ts | 6 +- .../src/lib/collect/command-object.spec.ts | 3 +- .../cli/src/lib/collect/command-object.ts | 37 +- .../lib/implementation/base-command-config.ts | 11 - .../lib/implementation/collect-and-persist.ts | 35 ++ .../implementation/config-middleware.spec.ts | 2 +- .../lib/implementation/config-middleware.ts | 36 +- .../cli/src/lib/implementation/helper.mock.ts | 5 + .../cli/src/lib/implementation/load-file.ts | 15 + .../implementation/read-code-pushup-config.ts | 23 ++ packages/cli/src/lib/implementation/utils.ts | 8 +- packages/cli/src/lib/middlewares.ts | 9 +- .../collect/implementation/execute-plugin.ts | 16 +- .../lib/collect/implementation/md/headline.ts | 24 ++ 17 files changed, 143 insertions(+), 421 deletions(-) delete mode 100644 packages/cli/src/lib/implementation/base-command-config.ts create mode 100644 packages/cli/src/lib/implementation/collect-and-persist.ts create mode 100644 packages/cli/src/lib/implementation/helper.mock.ts create mode 100644 packages/cli/src/lib/implementation/load-file.ts create mode 100644 packages/cli/src/lib/implementation/read-code-pushup-config.ts diff --git a/package-lock.json b/package-lock.json index 5bb37f4b4..a09e4a0df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.0", "license": "MIT", "dependencies": { - "@nx/nx-darwin-x64": "*", "bundle-require": "^4.0.1", "chalk": "^5.3.0", "cliui": "^8.0.1", @@ -2374,51 +2373,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.19.4", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.4.tgz", @@ -2434,276 +2388,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "dev": true, diff --git a/packages/cli/package.json b/packages/cli/package.json index ac195f01e..873bb7309 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -8,7 +8,6 @@ "bundle-require": "^4.0.1", "chalk": "^5.3.0", "yargs": "^17.7.2", - "zod": "^3.22.1", "@quality-metrics/models": "^0.0.1", "@quality-metrics/utils": "^0.0.1" } diff --git a/packages/cli/src/lib/cli.spec.ts b/packages/cli/src/lib/cli.spec.ts index c6d9b4d60..d421709b3 100644 --- a/packages/cli/src/lib/cli.spec.ts +++ b/packages/cli/src/lib/cli.spec.ts @@ -1,10 +1,11 @@ import { join } from 'path'; import { describe, expect, it } from 'vitest'; import { yargsCli } from './cli'; -import { CommandBase } from './implementation/base-command-config'; -import { getDirname } from './implementation/utils'; import { middlewares } from './middlewares'; import { yargsGlobalOptionsDefinition } from './options'; +import { CollectOptions } from '@quality-metrics/utils'; +import { GlobalCliArgs } from '@quality-metrics/models'; +import { getDirname } from './implementation/helper.mock'; const __dirname = getDirname(import.meta.url); const withDirName = (path: string) => join(__dirname, path); @@ -16,10 +17,10 @@ const demandCommand: [number, string] = [0, 'no command required']; describe('CLI arguments parsing', () => { it('options should provide correct defaults', async () => { const args: string[] = []; - const parsedArgv: CommandBase = yargsCli(args, { + const parsedArgv = yargsCli(args, { options, demandCommand, - }).argv; + }).argv as unknown as GlobalCliArgs; expect(parsedArgv.configPath).toContain('code-pushup.config.js'); expect(parsedArgv.verbose).toBe(false); expect(parsedArgv.interactive).toBe(true); @@ -33,10 +34,10 @@ describe('CLI arguments parsing', () => { validConfigPath, ]; - const parsedArgv: CommandBase = yargsCli(args, { + const parsedArgv = yargsCli(args, { options, demandCommand, - }).argv; + }).argv as GlobalCliArgs & CollectOptions; expect(parsedArgv.configPath).toContain(validConfigPath); expect(parsedArgv.verbose).toBe(true); expect(parsedArgv.interactive).toBe(false); @@ -44,10 +45,10 @@ describe('CLI arguments parsing', () => { it('middleware should use config correctly', async () => { const args: string[] = ['--configPath', validConfigPath]; - const parsedArgv: CommandBase = await yargsCli(args, { + const parsedArgv = (await yargsCli(args, { demandCommand, middlewares, - }).argv; + }).argv) as unknown as GlobalCliArgs & CollectOptions; expect(parsedArgv.configPath).toContain(validConfigPath); expect(parsedArgv.persist.outputPath).toContain('cli-config-out.json'); }); diff --git a/packages/cli/src/lib/cli.ts b/packages/cli/src/lib/cli.ts index 34695598a..318a09bb0 100644 --- a/packages/cli/src/lib/cli.ts +++ b/packages/cli/src/lib/cli.ts @@ -1,4 +1,4 @@ -import { CoreConfig } from '@quality-metrics/models'; +import { CoreConfig, GlobalCliArgs } from '@quality-metrics/models'; import chalk from 'chalk'; import yargs, { Argv, @@ -30,7 +30,7 @@ export function yargsCli( applyBeforeValidation?: boolean; }[]; }, -): Argv { +): Argv { const { usageMessage, scriptName } = cfg; let { commands, options, middlewares /*demandCommand*/ } = cfg; // demandCommand = Array.isArray(demandCommand) ? demandCommand: [1, 'Minimum 1 command!']; @TODO implement when commands are present @@ -81,5 +81,5 @@ export function yargsCli( }); // return CLI object - return cli as unknown as Argv; + return cli as unknown as Argv; } diff --git a/packages/cli/src/lib/collect/command-object.spec.ts b/packages/cli/src/lib/collect/command-object.spec.ts index aa98da328..c079f647c 100644 --- a/packages/cli/src/lib/collect/command-object.spec.ts +++ b/packages/cli/src/lib/collect/command-object.spec.ts @@ -4,10 +4,11 @@ import { CollectOptions } from '@quality-metrics/utils'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { yargsCli } from '../cli'; -import { getDirname, logErrorBeforeThrow } from '../implementation/utils'; +import { logErrorBeforeThrow } from '../implementation/utils'; import { middlewares } from '../middlewares'; import { yargsGlobalOptionsDefinition } from '../options'; import { yargsCollectCommandObject } from './command-object'; +import { getDirname } from '../implementation/helper.mock'; const command = { ...yargsCollectCommandObject(), diff --git a/packages/cli/src/lib/collect/command-object.ts b/packages/cli/src/lib/collect/command-object.ts index 7d80bc117..24d028e78 100644 --- a/packages/cli/src/lib/collect/command-object.ts +++ b/packages/cli/src/lib/collect/command-object.ts @@ -1,43 +1,10 @@ -import { pluginOutputSchema, Report } from '@quality-metrics/models'; -import { - collect, - CollectOptions, - CollectOutputError, - persistReport, - logPersistedResults, -} from '@quality-metrics/utils'; import { CommandModule } from 'yargs'; -import * as packageJson from '../../../package.json'; +import { collectAndPersistReports } from '../implementation/collect-and-persist'; export function yargsCollectCommandObject() { - const handler = async ( - config: CollectOptions & { format: string }, - ): Promise => { - const collectReport = await collect(config); - const report: Report = { - ...collectReport, - packageName: packageJson.name, - version: packageJson.version, - }; - - const persistResults = await persistReport(report, config); - - logPersistedResults(persistResults); - - // validate report - report.plugins.forEach(plugin => { - try { - // Running checks after persisting helps while debugging as you can check the invalid output after the error - pluginOutputSchema.parse(plugin); - } catch (e) { - throw new CollectOutputError(plugin.slug, e as Error); - } - }); - }; - return { command: 'collect', describe: 'Run Plugins and collect results', - handler: handler as unknown as CommandModule['handler'], + handler: collectAndPersistReports as unknown as CommandModule['handler'], } satisfies CommandModule; } diff --git a/packages/cli/src/lib/implementation/base-command-config.ts b/packages/cli/src/lib/implementation/base-command-config.ts deleted file mode 100644 index 107c7a9f5..000000000 --- a/packages/cli/src/lib/implementation/base-command-config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { - globalCliArgsSchema, - refineCoreConfig, - unrefinedCoreConfigSchema, -} from '@quality-metrics/models'; -import { z } from 'zod'; - -export const commandBaseSchema = refineCoreConfig( - globalCliArgsSchema.merge(unrefinedCoreConfigSchema), -); -export type CommandBase = z.infer; diff --git a/packages/cli/src/lib/implementation/collect-and-persist.ts b/packages/cli/src/lib/implementation/collect-and-persist.ts new file mode 100644 index 000000000..171082965 --- /dev/null +++ b/packages/cli/src/lib/implementation/collect-and-persist.ts @@ -0,0 +1,35 @@ +import { + collect, + CollectOptions, + CollectOutputError, + logPersistedResults, + persistReport, +} from '@quality-metrics/utils'; +import { pluginOutputSchema, Report } from '@quality-metrics/models'; +import * as packageJson from '../../../package.json'; + +// @TODO move into core +export async function collectAndPersistReports( + config: CollectOptions, +): Promise { + const collectReport = await collect(config); + const report: Report = { + ...collectReport, + packageName: packageJson.name, + version: packageJson.version, + }; + + const persistResults = await persistReport(report, config); + + logPersistedResults(persistResults); + + // validate report + report.plugins.forEach(plugin => { + try { + // Running checks after persisting helps while debugging as you can check the invalid output after the error + pluginOutputSchema.parse(plugin); + } catch (e) { + throw new CollectOutputError(plugin.slug, e as Error); + } + }); +} diff --git a/packages/cli/src/lib/implementation/config-middleware.spec.ts b/packages/cli/src/lib/implementation/config-middleware.spec.ts index d8834ecab..a260974d0 100644 --- a/packages/cli/src/lib/implementation/config-middleware.spec.ts +++ b/packages/cli/src/lib/implementation/config-middleware.spec.ts @@ -1,7 +1,7 @@ import { join } from 'path'; import { expect } from 'vitest'; import { configMiddleware, ConfigParseError } from './config-middleware'; -import { getDirname } from './utils'; +import { getDirname } from './helper.mock'; const __dirname = getDirname(import.meta.url); diff --git a/packages/cli/src/lib/implementation/config-middleware.ts b/packages/cli/src/lib/implementation/config-middleware.ts index 228c1d13e..134b721d6 100644 --- a/packages/cli/src/lib/implementation/config-middleware.ts +++ b/packages/cli/src/lib/implementation/config-middleware.ts @@ -1,8 +1,5 @@ -import { bundleRequire } from 'bundle-require'; -import { stat } from 'fs/promises'; - import { GlobalCliArgs, globalCliArgsSchema } from '@quality-metrics/models'; -import { CommandBase, commandBaseSchema } from './base-command-config'; +import { readCodePushupConfig } from './read-code-pushup-config'; export class ConfigParseError extends Error { constructor(configPath: string) { @@ -10,29 +7,12 @@ export class ConfigParseError extends Error { } } -export async function configMiddleware( - processArgs: T, -): Promise { - const globalCfg: GlobalCliArgs = globalCliArgsSchema.parse(processArgs); - const { configPath } = globalCfg; - try { - const stats = await stat(configPath); - if (!stats.isFile) { - throw new ConfigParseError(configPath); - } - } catch (err) { - throw new ConfigParseError(configPath); - } - - const { mod } = await bundleRequire({ - filepath: globalCfg.configPath, - format: 'esm', - }); - const exportedConfig = mod.default || mod; - - return commandBaseSchema.parse({ - ...globalCfg, - ...exportedConfig, +export async function configMiddleware(processArgs: T) { + const globalOptions: GlobalCliArgs = globalCliArgsSchema.parse(processArgs); + const importedRc = await readCodePushupConfig(globalOptions.configPath); + return { + ...importedRc, ...processArgs, - }); + ...globalOptions, + }; } diff --git a/packages/cli/src/lib/implementation/helper.mock.ts b/packages/cli/src/lib/implementation/helper.mock.ts new file mode 100644 index 000000000..00820ec56 --- /dev/null +++ b/packages/cli/src/lib/implementation/helper.mock.ts @@ -0,0 +1,5 @@ +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; + +export const getDirname = (import_meta_url: string) => + dirname(fileURLToPath(import_meta_url)); diff --git a/packages/cli/src/lib/implementation/load-file.ts b/packages/cli/src/lib/implementation/load-file.ts new file mode 100644 index 000000000..ce2571c18 --- /dev/null +++ b/packages/cli/src/lib/implementation/load-file.ts @@ -0,0 +1,15 @@ +import { bundleRequire, Options } from 'bundle-require'; + +// @TODO move into utils +export async function importModule( + options: Options, + parse?: (d: unknown) => T, +) { + parse = parse || (v => v as T); + options = { + format: 'esm', + ...options, + }; + const { mod } = await bundleRequire(options); + return parse(mod.default || mod); +} diff --git a/packages/cli/src/lib/implementation/read-code-pushup-config.ts b/packages/cli/src/lib/implementation/read-code-pushup-config.ts new file mode 100644 index 000000000..310ac3be6 --- /dev/null +++ b/packages/cli/src/lib/implementation/read-code-pushup-config.ts @@ -0,0 +1,23 @@ +import { CoreConfig, coreConfigSchema } from '@quality-metrics/models'; +import { stat } from 'fs/promises'; +import { importModule } from './load-file'; +import { ConfigParseError } from './config-middleware'; + +// @TODO move into core +export async function readCodePushupConfig(filepath: string) { + try { + const stats = await stat(filepath); + if (!stats.isFile) { + throw new ConfigParseError(filepath); + } + } catch (err) { + throw new ConfigParseError(filepath); + } + + return importModule( + { + filepath, + }, + coreConfigSchema.parse, + ); +} diff --git a/packages/cli/src/lib/implementation/utils.ts b/packages/cli/src/lib/implementation/utils.ts index dd6176f67..5e409257c 100644 --- a/packages/cli/src/lib/implementation/utils.ts +++ b/packages/cli/src/lib/implementation/utils.ts @@ -1,10 +1,4 @@ -import { dirname } from 'path'; -import { fileURLToPath } from 'url'; - -export const getDirname = (import_meta_url: string) => - dirname(fileURLToPath(import_meta_url)); - -// log error and flush stdout so that Yargs doesn't supress it +// log error and flush stdout so that Yargs doesn't suppress it // related issue: https://github.com/yargs/yargs/issues/2118 export function logErrorBeforeThrow< // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/cli/src/lib/middlewares.ts b/packages/cli/src/lib/middlewares.ts index 21b2e18f7..19f1e0a2b 100644 --- a/packages/cli/src/lib/middlewares.ts +++ b/packages/cli/src/lib/middlewares.ts @@ -1,7 +1,6 @@ -import { MiddlewareFunction } from 'yargs'; import { configMiddleware } from './implementation/config-middleware'; +import { MiddlewareFunction } from 'yargs'; -export const middlewares: { - middlewareFunction: MiddlewareFunction; - applyBeforeValidation?: boolean; -}[] = [{ middlewareFunction: configMiddleware }]; +export const middlewares = [ + { middlewareFunction: configMiddleware as unknown as MiddlewareFunction }, +]; diff --git a/packages/utils/src/lib/collect/implementation/execute-plugin.ts b/packages/utils/src/lib/collect/implementation/execute-plugin.ts index 610c60a07..cbea4daef 100644 --- a/packages/utils/src/lib/collect/implementation/execute-plugin.ts +++ b/packages/utils/src/lib/collect/implementation/execute-plugin.ts @@ -26,7 +26,7 @@ export class PluginOutputError extends Error { * Execute a plugin. * * @public - * @param cfg - {@link ProcessConfig} object with runner and meta + * @param pluginConfig - {@link ProcessConfig} object with runner and meta * @param observer - process {@link ProcessObserver} * @returns {Promise} - audit outputs from plugin runner * @throws {PluginOutputError} - if plugin runner output is invalid @@ -45,11 +45,12 @@ export class PluginOutputError extends Error { * } */ export async function executePlugin( - cfg: PluginConfig, + pluginConfig: PluginConfig, observer?: ProcessObserver, ): Promise { - const { slug, title, description, docsUrl } = cfg; - const { args, command } = cfg.runner; + const { slug, title, description, docsUrl, version, packageName } = + pluginConfig; + const { args, command } = pluginConfig.runner; const { duration, date } = await executeProcess({ command, @@ -58,13 +59,18 @@ export async function executePlugin( }); try { - const processOutputPath = join(process.cwd(), cfg.runner.outputPath); + const processOutputPath = join( + process.cwd(), + pluginConfig.runner.outputPath, + ); // read process output from file system and parse it const audits = auditOutputsSchema.parse( JSON.parse((await readFile(processOutputPath)).toString()), ); return { + version, + packageName, slug, title, description, diff --git a/packages/utils/src/lib/collect/implementation/md/headline.ts b/packages/utils/src/lib/collect/implementation/md/headline.ts index 217e5ac76..b454333fe 100644 --- a/packages/utils/src/lib/collect/implementation/md/headline.ts +++ b/packages/utils/src/lib/collect/implementation/md/headline.ts @@ -8,3 +8,27 @@ export type Hierarchy = 1 | 2 | 3 | 4 | 5 | 6; export function headline(text: string, hierarchy: Hierarchy = 1): string { return `${new Array(hierarchy).fill('#').join('')} ${text}`; } + +export function h(text: string, hierarchy: Hierarchy = 1): string { + return headline(text, hierarchy); +} + +export function h2(text: string): string { + return headline(text, 2); +} + +export function h3(text: string): string { + return headline(text, 3); +} + +export function h4(text: string): string { + return headline(text, 4); +} + +export function h5(text: string): string { + return headline(text, 5); +} + +export function h6(text: string): string { + return headline(text, 6); +} From 0ec81d5c87c2296e6625d7cbbdb0164c73acecf2 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 2 Oct 2023 03:50:17 +0200 Subject: [PATCH 2/4] refactor(models): add comments for #73 --- packages/cli/src/lib/implementation/collect-and-persist.ts | 2 +- packages/cli/src/lib/implementation/load-file.ts | 2 +- packages/cli/src/lib/implementation/read-code-pushup-config.ts | 2 +- packages/models/src/lib/plugin-config.spec.ts | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/lib/implementation/collect-and-persist.ts b/packages/cli/src/lib/implementation/collect-and-persist.ts index 171082965..4b987a2be 100644 --- a/packages/cli/src/lib/implementation/collect-and-persist.ts +++ b/packages/cli/src/lib/implementation/collect-and-persist.ts @@ -8,7 +8,7 @@ import { import { pluginOutputSchema, Report } from '@quality-metrics/models'; import * as packageJson from '../../../package.json'; -// @TODO move into core +// @TODO [73] move into core export async function collectAndPersistReports( config: CollectOptions, ): Promise { diff --git a/packages/cli/src/lib/implementation/load-file.ts b/packages/cli/src/lib/implementation/load-file.ts index ce2571c18..3f93abad6 100644 --- a/packages/cli/src/lib/implementation/load-file.ts +++ b/packages/cli/src/lib/implementation/load-file.ts @@ -1,6 +1,6 @@ import { bundleRequire, Options } from 'bundle-require'; -// @TODO move into utils +// @TODO [73] move into utils export async function importModule( options: Options, parse?: (d: unknown) => T, diff --git a/packages/cli/src/lib/implementation/read-code-pushup-config.ts b/packages/cli/src/lib/implementation/read-code-pushup-config.ts index 310ac3be6..60fa41483 100644 --- a/packages/cli/src/lib/implementation/read-code-pushup-config.ts +++ b/packages/cli/src/lib/implementation/read-code-pushup-config.ts @@ -3,7 +3,7 @@ import { stat } from 'fs/promises'; import { importModule } from './load-file'; import { ConfigParseError } from './config-middleware'; -// @TODO move into core +// @TODO [73] move into core export async function readCodePushupConfig(filepath: string) { try { const stats = await stat(filepath); diff --git a/packages/models/src/lib/plugin-config.spec.ts b/packages/models/src/lib/plugin-config.spec.ts index cecd47278..4e5237f82 100644 --- a/packages/models/src/lib/plugin-config.spec.ts +++ b/packages/models/src/lib/plugin-config.spec.ts @@ -79,7 +79,6 @@ describe('pluginConfigSchema', () => { it('should throw if a group has duplicate audit refs', () => { const auditSlug = 'no-any'; - // @TODO use pluginConfigSchema instead of auditGroupSchema const cfg = mockGroupConfig({ auditSlug: [auditSlug, auditSlug] }); expect(() => auditGroupSchema.parse(cfg)).toThrow( From f521fbe33d87ad2c95ea9bc7755128044a3ca3c6 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 2 Oct 2023 04:04:53 +0200 Subject: [PATCH 3/4] fix(models): fix tests --- .../src/lib/collect/implementation/execute-process.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/collect/implementation/execute-process.spec.ts b/packages/utils/src/lib/collect/implementation/execute-process.spec.ts index f4f2276a4..7fa54ad5e 100644 --- a/packages/utils/src/lib/collect/implementation/execute-process.spec.ts +++ b/packages/utils/src/lib/collect/implementation/execute-process.spec.ts @@ -40,7 +40,7 @@ describe('executeProcess', () => { expect(observer?.complete).toHaveBeenCalledTimes(1); }); - it('should work with async script `node custom-script.js` that throws an error', async () => { + it('should work with async script `node custom-script.js --arg` that throws an error', async () => { const cfg = mockProcessConfig( getAsyncProcessRunnerConfig({ interval: 10, runs: 1, throwError: true }), ); From de9fd15d28c069712da172c072809197ab122df4 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 2 Oct 2023 11:56:24 +0200 Subject: [PATCH 4/4] feat(utils): fix merge 2 --- package-lock.json | 1 - packages/cli/src/lib/cli.ts | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index e82735aa3..d85de6718 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.0", "license": "MIT", "dependencies": { - "@nx/nx-darwin-x64": "^16.9.1", "bundle-require": "^4.0.1", "chalk": "^5.3.0", "cliui": "^8.0.1", diff --git a/packages/cli/src/lib/cli.ts b/packages/cli/src/lib/cli.ts index 318a09bb0..cc0d34798 100644 --- a/packages/cli/src/lib/cli.ts +++ b/packages/cli/src/lib/cli.ts @@ -1,4 +1,4 @@ -import { CoreConfig, GlobalCliArgs } from '@quality-metrics/models'; +import { CoreConfig, GlobalOptions } from '@quality-metrics/models'; import chalk from 'chalk'; import yargs, { Argv, @@ -30,7 +30,7 @@ export function yargsCli( applyBeforeValidation?: boolean; }[]; }, -): Argv { +): Argv { const { usageMessage, scriptName } = cfg; let { commands, options, middlewares /*demandCommand*/ } = cfg; // demandCommand = Array.isArray(demandCommand) ? demandCommand: [1, 'Minimum 1 command!']; @TODO implement when commands are present @@ -81,5 +81,5 @@ export function yargsCli( }); // return CLI object - return cli as unknown as Argv; + return cli as unknown as Argv; }