From bb5afa3b24e1884c7fad8fda6efa9fd5742036c8 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Aug 2025 23:42:14 +0200 Subject: [PATCH 01/10] feat: add persist.report output to CLI --- e2e/cli-e2e/tests/collect.e2e.test.ts | 24 ++++++++++- packages/ci/src/lib/run-utils.ts | 1 + packages/cli/README.md | 25 ++++++----- .../lib/collect/collect-command.unit.test.ts | 2 +- .../implementation/core-config.middleware.ts | 7 ++++ .../core-config.middleware.unit.test.ts | 10 +++++ .../lib/implementation/core-config.model.ts | 2 +- packages/core/src/lib/collect-and-persist.ts | 41 ++++++++++++------- .../src/lib/collect-and-persist.unit.test.ts | 25 +++++++++++ .../core/src/lib/implementation/persist.ts | 2 +- packages/models/src/index.ts | 1 + packages/models/src/lib/cache-config.ts | 13 ++++++ packages/models/src/lib/core-config.ts | 2 + packages/models/src/lib/persist-config.ts | 1 + packages/utils/src/lib/file-system.ts | 2 +- 15 files changed, 128 insertions(+), 30 deletions(-) create mode 100644 packages/models/src/lib/cache-config.ts diff --git a/e2e/cli-e2e/tests/collect.e2e.test.ts b/e2e/cli-e2e/tests/collect.e2e.test.ts index b29f26471..52ee4087f 100644 --- a/e2e/cli-e2e/tests/collect.e2e.test.ts +++ b/e2e/cli-e2e/tests/collect.e2e.test.ts @@ -7,7 +7,7 @@ import { TEST_OUTPUT_DIR, teardownTestFolder, } from '@code-pushup/test-utils'; -import { executeProcess, readTextFile } from '@code-pushup/utils'; +import { executeProcess, fileExists, readTextFile } from '@code-pushup/utils'; describe('CLI collect', () => { const dummyPluginTitle = 'Dummy Plugin'; @@ -61,6 +61,28 @@ describe('CLI collect', () => { expect(md).toContain(dummyAuditTitle); }); + it('should not create reports if --persist.no-report is given', async () => { + const { code } = await executeProcess({ + command: 'npx', + args: [ + '@code-pushup/cli', + '--no-progress', + 'collect', + '--persist.no-report', + ], + cwd: dummyDir, + }); + + expect(code).toBe(0); + + await expect( + fileExists(path.join(dummyOutputDir, 'report.md')), + ).resolves.toBeFalsy(); + await expect( + fileExists(path.join(dummyOutputDir, 'report.json')), + ).resolves.toBeFalsy(); + }); + it('should print report summary to stdout', async () => { const { code, stdout } = await executeProcess({ command: 'npx', diff --git a/packages/ci/src/lib/run-utils.ts b/packages/ci/src/lib/run-utils.ts index ae41c2532..abbb1dbce 100644 --- a/packages/ci/src/lib/run-utils.ts +++ b/packages/ci/src/lib/run-utils.ts @@ -483,6 +483,7 @@ export function configFromPatterns( outputDir: interpolate(persist.outputDir, variables), filename: interpolate(persist.filename, variables), format: persist.format, + report: persist.report, }, ...(upload && { upload: { diff --git a/packages/cli/README.md b/packages/cli/README.md index 0d09ad1ad..c607e28a8 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -207,17 +207,20 @@ Each example is fully tested to demonstrate best practices for plugin testing as ### Common Command Options -| Option | Type | Default | Description | -| --------------------------- | -------------------- | -------- | --------------------------------------------------------------------------- | -| **`--persist.outputDir`** | `string` | n/a | Directory for the produced reports. | -| **`--persist.filename`** | `string` | `report` | Filename for the produced reports without extension. | -| **`--persist.format`** | `('json' \| 'md')[]` | `json` | Format(s) of the report file. | -| **`--upload.organization`** | `string` | n/a | Organization slug from portal. | -| **`--upload.project`** | `string` | n/a | Project slug from portal. | -| **`--upload.server`** | `string` | n/a | URL to your portal server. | -| **`--upload.apiKey`** | `string` | n/a | API key for the portal server. | -| **`--onlyPlugins`** | `string[]` | `[]` | Only run the specified plugins. Applicable to all commands except `upload`. | -| **`--skipPlugins`** | `string[]` | `[]` | Skip the specified plugins. Applicable to all commands except `upload`. | +| Option | Type | Default | Description | +| --------------------------- | -------------------- | -------- | -------------------------------------------------------------------------------- | +| **`--persist.outputDir`** | `string` | n/a | Directory for the produced reports. | +| **`--persist.filename`** | `string` | `report` | Filename for the produced reports without extension. | +| **`--persist.format`** | `('json' \| 'md')[]` | `json` | Format(s) of the report file. | +| **`--persist.report`** | `boolean` | `true` | Generate the report files for given formats. (useful in combination wit caching) | +| **`--upload.organization`** | `string` | n/a | Organization slug from portal. | +| **`--upload.project`** | `string` | n/a | Project slug from portal. | +| **`--upload.server`** | `string` | n/a | URL to your portal server. | +| **`--upload.apiKey`** | `string` | n/a | API key for the portal server. | +| **`--cache.read`** | `boolean` | `false` | If plugin audit outputs should be read from file system cache. | +| **`--cache.write`** | `boolean` | `false` | If plugin audit outputs should be written to file system cache. | +| **`--onlyPlugins`** | `string[]` | `[]` | Only run the specified plugins. Applicable to all commands except `upload`. | +| **`--skipPlugins`** | `string[]` | `[]` | Skip the specified plugins. Applicable to all commands except `upload`. | > [!NOTE] > All common options, except `--onlyPlugins` and `--skipPlugins`, can be specified in the configuration file as well. diff --git a/packages/cli/src/lib/collect/collect-command.unit.test.ts b/packages/cli/src/lib/collect/collect-command.unit.test.ts index 796fee62b..6765add61 100644 --- a/packages/cli/src/lib/collect/collect-command.unit.test.ts +++ b/packages/cli/src/lib/collect/collect-command.unit.test.ts @@ -37,7 +37,7 @@ describe('collect-command', () => { expect(collectAndPersistReports).toHaveBeenCalledWith( expect.objectContaining({ config: '/test/code-pushup.config.ts', - persist: expect.objectContaining>({ + persist: expect.objectContaining({ filename: DEFAULT_PERSIST_FILENAME, outputDir: DEFAULT_PERSIST_OUTPUT_DIR, format: DEFAULT_PERSIST_FORMAT, diff --git a/packages/cli/src/lib/implementation/core-config.middleware.ts b/packages/cli/src/lib/implementation/core-config.middleware.ts index 0f2891178..735c2fb89 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.ts @@ -23,6 +23,7 @@ export async function coreConfigMiddleware< tsconfig, persist: cliPersist, upload: cliUpload, + cache: cliCache, ...remainingCliOptions } = processArgs; // Search for possible configuration file extensions if path is not given @@ -43,6 +44,11 @@ export async function coreConfigMiddleware< }); return { ...(config != null && { config }), + cache: { + write: false, + read: false, + ...cliCache, + }, persist: { outputDir: cliPersist?.outputDir ?? @@ -53,6 +59,7 @@ export async function coreConfigMiddleware< format: normalizeFormats( cliPersist?.format ?? rcPersist?.format ?? DEFAULT_PERSIST_FORMAT, ), + report: !('no-report' in (cliPersist ?? {})), }, ...(upload != null && { upload }), ...remainingRcConfig, diff --git a/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts b/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts index 134b8f183..9088bdd37 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts @@ -73,4 +73,14 @@ describe('coreConfigMiddleware', () => { 'apps/website/tsconfig.json', ); }); + + it('should forward normalize --persist.report option', async () => { + await coreConfigMiddleware({ + config: 'apps/website/code-pushup.config.ts', + } as GeneralCliOptions & CoreConfigCliOptions & FilterOptions); + expect(readRcByPath).toHaveBeenCalledWith( + 'apps/website/code-pushup.config.ts', + 'apps/website/tsconfig.json', + ); + }); }); diff --git a/packages/cli/src/lib/implementation/core-config.model.ts b/packages/cli/src/lib/implementation/core-config.model.ts index ed011da56..f6675befc 100644 --- a/packages/cli/src/lib/implementation/core-config.model.ts +++ b/packages/cli/src/lib/implementation/core-config.model.ts @@ -19,6 +19,6 @@ export type ConfigCliOptions = { verbose?: string; }; -export type CoreConfigCliOptions = Pick & { +export type CoreConfigCliOptions = Pick & { upload?: Partial>; }; diff --git a/packages/core/src/lib/collect-and-persist.ts b/packages/core/src/lib/collect-and-persist.ts index dfa48ba76..12ddb8ef8 100644 --- a/packages/core/src/lib/collect-and-persist.ts +++ b/packages/core/src/lib/collect-and-persist.ts @@ -8,6 +8,7 @@ import { logStdoutSummary, scoreReport, sortReport, + ui, } from '@code-pushup/utils'; import { collect } from './implementation/collect.js'; import { @@ -18,30 +19,42 @@ import type { GlobalOptions } from './types.js'; export type CollectAndPersistReportsOptions = Pick< CoreConfig, - 'plugins' | 'categories' -> & { persist: Required } & Partial; + 'plugins' | 'categories' | 'cache' +> & { + persist: Required> & + Pick; +} & Partial; export async function collectAndPersistReports( options: CollectAndPersistReportsOptions, ): Promise { - const report = await collect(options); - const sortedScoredReport = sortReport(scoreReport(report)); + const logger = ui().logger; + const reportResult = await collect(options); + const sortedScoredReport = sortReport(scoreReport(reportResult)); - const persistResults = await persistReport( - report, - sortedScoredReport, - options.persist, - ); + const { persist } = options; + const { report: shouldGenerateReport = true, ...persistOptions } = + persist ?? {}; - // terminal output - logStdoutSummary(sortedScoredReport); + if (shouldGenerateReport === true) { + const persistResults = await persistReport( + reportResult, + sortedScoredReport, + persistOptions, + ); - if (isVerbose()) { - logPersistedResults(persistResults); + if (isVerbose()) { + logPersistedResults(persistResults); + } + } else { + logger.info('Skipping saving reports as `persist.report` is false'); } + // terminal output + logStdoutSummary(sortedScoredReport); + // validate report and throw if invalid - report.plugins.forEach(plugin => { + reportResult.plugins.forEach(plugin => { // Running checks after persisting helps while debugging as you can check the invalid output after the error is thrown pluginReportSchema.parse(plugin); }); diff --git a/packages/core/src/lib/collect-and-persist.unit.test.ts b/packages/core/src/lib/collect-and-persist.unit.test.ts index 1ecb5c5fe..00d38c76c 100644 --- a/packages/core/src/lib/collect-and-persist.unit.test.ts +++ b/packages/core/src/lib/collect-and-persist.unit.test.ts @@ -115,6 +115,31 @@ describe('collectAndPersistReports', () => { expect(logPersistedResults).toHaveBeenCalled(); }); + it('should call collect and not persistReport if report options is false in verbose mode', async () => { + const sortedScoredReport = sortReport(scoreReport(MINIMAL_REPORT_MOCK)); + + vi.stubEnv('CP_VERBOSE', 'true'); + + const verboseConfig: CollectAndPersistReportsOptions = { + ...MINIMAL_CONFIG_MOCK, + persist: { + outputDir: 'output', + filename: 'report', + format: ['md'], + report: false, + }, + progress: false, + }; + await collectAndPersistReports(verboseConfig); + + expect(collect).toHaveBeenCalledWith(verboseConfig); + + expect(persistReport).not.toHaveBeenCalled(); + expect(logPersistedResults).not.toHaveBeenCalled(); + + expect(logStdoutSummary).toHaveBeenCalledWith(sortedScoredReport); + }); + it('should print a summary to stdout', async () => { await collectAndPersistReports( MINIMAL_CONFIG_MOCK as CollectAndPersistReportsOptions, diff --git a/packages/core/src/lib/implementation/persist.ts b/packages/core/src/lib/implementation/persist.ts index 915af9459..c55a0103e 100644 --- a/packages/core/src/lib/implementation/persist.ts +++ b/packages/core/src/lib/implementation/persist.ts @@ -25,7 +25,7 @@ export class PersistError extends Error { export async function persistReport( report: Report, sortedScoredReport: ScoredReport, - options: Required, + options: Required>, ): Promise { const { outputDir, filename, format } = options; diff --git a/packages/models/src/index.ts b/packages/models/src/index.ts index 91c22fb10..5050bad26 100644 --- a/packages/models/src/index.ts +++ b/packages/models/src/index.ts @@ -6,6 +6,7 @@ export { sourceFileLocationSchema, type SourceFileLocation, } from './lib/source.js'; +export { cacheConfigSchema, type CacheConfig } from './lib/cache-config.js'; export { auditDetailsSchema, diff --git a/packages/models/src/lib/cache-config.ts b/packages/models/src/lib/cache-config.ts new file mode 100644 index 000000000..96b5cff35 --- /dev/null +++ b/packages/models/src/lib/cache-config.ts @@ -0,0 +1,13 @@ +import { z } from 'zod'; + +export const cacheConfigSchema = z + .object({ + read: z + .boolean() + .describe('Whether to read from cache if available') + .optional(), + write: z.boolean().describe('Whether to write results to cache').optional(), + }) + .describe('Cache configuration for read and write operations'); + +export type CacheConfig = z.infer; diff --git a/packages/models/src/lib/core-config.ts b/packages/models/src/lib/core-config.ts index a4e6469f7..ea54f5745 100644 --- a/packages/models/src/lib/core-config.ts +++ b/packages/models/src/lib/core-config.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { cacheConfigSchema } from './cache-config.js'; import { categoriesSchema } from './category-config.js'; import { createCheck } from './implementation/checks.js'; import { findMissingSlugsInCategoryRefs } from './implementation/utils.js'; @@ -13,6 +14,7 @@ export const unrefinedCoreConfigSchema = z.object({ .describe( 'List of plugins to be used (official, community-provided, or custom)', ), + cache: cacheConfigSchema.optional(), /** portal configuration for persisting results */ persist: persistConfigSchema.optional(), /** portal configuration for uploading results */ diff --git a/packages/models/src/lib/persist-config.ts b/packages/models/src/lib/persist-config.ts index b349343ff..c12e85ed8 100644 --- a/packages/models/src/lib/persist-config.ts +++ b/packages/models/src/lib/persist-config.ts @@ -10,6 +10,7 @@ export const persistConfigSchema = z.object({ .describe('Artifacts file name (without extension)') .optional(), format: z.array(formatSchema).optional(), + report: z.boolean().optional(), }); export type PersistConfig = z.infer; diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index d97982bfe..51d54d671 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -90,7 +90,7 @@ export function createReportPath({ filename, format, suffix, -}: Omit, 'format'> & { +}: Omit, 'format' | 'report'> & { format: Format; suffix?: string; }): string { From 0aba600719c56a679f403b7996d3c830a6872abd Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Aug 2025 23:46:18 +0200 Subject: [PATCH 02/10] fix: revert cache implementation --- packages/cli/README.md | 2 -- packages/core/src/lib/collect-and-persist.ts | 2 +- packages/models/src/index.ts | 1 - packages/models/src/lib/cache-config.ts | 13 ------------- packages/models/src/lib/core-config.ts | 2 -- 5 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 packages/models/src/lib/cache-config.ts diff --git a/packages/cli/README.md b/packages/cli/README.md index c607e28a8..9f48ff35d 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -217,8 +217,6 @@ Each example is fully tested to demonstrate best practices for plugin testing as | **`--upload.project`** | `string` | n/a | Project slug from portal. | | **`--upload.server`** | `string` | n/a | URL to your portal server. | | **`--upload.apiKey`** | `string` | n/a | API key for the portal server. | -| **`--cache.read`** | `boolean` | `false` | If plugin audit outputs should be read from file system cache. | -| **`--cache.write`** | `boolean` | `false` | If plugin audit outputs should be written to file system cache. | | **`--onlyPlugins`** | `string[]` | `[]` | Only run the specified plugins. Applicable to all commands except `upload`. | | **`--skipPlugins`** | `string[]` | `[]` | Skip the specified plugins. Applicable to all commands except `upload`. | diff --git a/packages/core/src/lib/collect-and-persist.ts b/packages/core/src/lib/collect-and-persist.ts index 12ddb8ef8..fd8a211e4 100644 --- a/packages/core/src/lib/collect-and-persist.ts +++ b/packages/core/src/lib/collect-and-persist.ts @@ -19,7 +19,7 @@ import type { GlobalOptions } from './types.js'; export type CollectAndPersistReportsOptions = Pick< CoreConfig, - 'plugins' | 'categories' | 'cache' + 'plugins' | 'categories' > & { persist: Required> & Pick; diff --git a/packages/models/src/index.ts b/packages/models/src/index.ts index 5050bad26..91c22fb10 100644 --- a/packages/models/src/index.ts +++ b/packages/models/src/index.ts @@ -6,7 +6,6 @@ export { sourceFileLocationSchema, type SourceFileLocation, } from './lib/source.js'; -export { cacheConfigSchema, type CacheConfig } from './lib/cache-config.js'; export { auditDetailsSchema, diff --git a/packages/models/src/lib/cache-config.ts b/packages/models/src/lib/cache-config.ts deleted file mode 100644 index 96b5cff35..000000000 --- a/packages/models/src/lib/cache-config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod'; - -export const cacheConfigSchema = z - .object({ - read: z - .boolean() - .describe('Whether to read from cache if available') - .optional(), - write: z.boolean().describe('Whether to write results to cache').optional(), - }) - .describe('Cache configuration for read and write operations'); - -export type CacheConfig = z.infer; diff --git a/packages/models/src/lib/core-config.ts b/packages/models/src/lib/core-config.ts index ea54f5745..a4e6469f7 100644 --- a/packages/models/src/lib/core-config.ts +++ b/packages/models/src/lib/core-config.ts @@ -1,5 +1,4 @@ import { z } from 'zod'; -import { cacheConfigSchema } from './cache-config.js'; import { categoriesSchema } from './category-config.js'; import { createCheck } from './implementation/checks.js'; import { findMissingSlugsInCategoryRefs } from './implementation/utils.js'; @@ -14,7 +13,6 @@ export const unrefinedCoreConfigSchema = z.object({ .describe( 'List of plugins to be used (official, community-provided, or custom)', ), - cache: cacheConfigSchema.optional(), /** portal configuration for persisting results */ persist: persistConfigSchema.optional(), /** portal configuration for uploading results */ From c1714fb3e27348c5b0223ea60e2a5a1977701b47 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Aug 2025 01:02:37 +0200 Subject: [PATCH 03/10] test: adjust middleware tests --- .../cli/src/lib/compare/compare-command.unit.test.ts | 9 ++++++++- .../cli/src/lib/implementation/core-config.int.test.ts | 5 +++++ .../src/lib/implementation/core-config.middleware.ts | 6 ------ .../implementation/core-config.middleware.unit.test.ts | 10 ---------- .../cli/src/lib/implementation/core-config.model.ts | 2 +- .../lib/merge-diffs/merge-diffs-command.unit.test.ts | 1 + 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/cli/src/lib/compare/compare-command.unit.test.ts b/packages/cli/src/lib/compare/compare-command.unit.test.ts index b2279fd80..95a82c714 100644 --- a/packages/cli/src/lib/compare/compare-command.unit.test.ts +++ b/packages/cli/src/lib/compare/compare-command.unit.test.ts @@ -41,12 +41,19 @@ describe('compare-command', () => { outputDir: DEFAULT_PERSIST_OUTPUT_DIR, filename: DEFAULT_PERSIST_FILENAME, format: DEFAULT_PERSIST_FORMAT, + report: true, + }, + upload: { + apiKey: 'dummy-api-key', + organization: 'code-pushup', + project: 'cli', + server: 'https://example.com/api', }, - upload: expect.any(Object), }, { before: 'source-report.json', after: 'target-report.json', + label: undefined, }, ); }); diff --git a/packages/cli/src/lib/implementation/core-config.int.test.ts b/packages/cli/src/lib/implementation/core-config.int.test.ts index 5cca9ee80..5068117e3 100644 --- a/packages/cli/src/lib/implementation/core-config.int.test.ts +++ b/packages/cli/src/lib/implementation/core-config.int.test.ts @@ -64,6 +64,7 @@ describe('parsing values from CLI and middleware', () => { filename: DEFAULT_PERSIST_FILENAME, format: DEFAULT_PERSIST_FORMAT, outputDir: DEFAULT_PERSIST_OUTPUT_DIR, + report: true, }); }); @@ -85,6 +86,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'cli-filename', format: ['md'], outputDir: 'cli-outputDir', + report: true, }); }); @@ -101,6 +103,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'rc-filename', format: ['json', 'md'], outputDir: 'rc-outputDir', + report: true, }); }); @@ -122,6 +125,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'cli-filename', format: ['md'], outputDir: 'cli-outputDir', + report: true, }); }); @@ -141,6 +145,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'rc-filename', format: DEFAULT_PERSIST_FORMAT, outputDir: 'cli-outputdir', + report: true, }); }); diff --git a/packages/cli/src/lib/implementation/core-config.middleware.ts b/packages/cli/src/lib/implementation/core-config.middleware.ts index 735c2fb89..86bb9746d 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.ts @@ -23,7 +23,6 @@ export async function coreConfigMiddleware< tsconfig, persist: cliPersist, upload: cliUpload, - cache: cliCache, ...remainingCliOptions } = processArgs; // Search for possible configuration file extensions if path is not given @@ -44,11 +43,6 @@ export async function coreConfigMiddleware< }); return { ...(config != null && { config }), - cache: { - write: false, - read: false, - ...cliCache, - }, persist: { outputDir: cliPersist?.outputDir ?? diff --git a/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts b/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts index 9088bdd37..134b8f183 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts @@ -73,14 +73,4 @@ describe('coreConfigMiddleware', () => { 'apps/website/tsconfig.json', ); }); - - it('should forward normalize --persist.report option', async () => { - await coreConfigMiddleware({ - config: 'apps/website/code-pushup.config.ts', - } as GeneralCliOptions & CoreConfigCliOptions & FilterOptions); - expect(readRcByPath).toHaveBeenCalledWith( - 'apps/website/code-pushup.config.ts', - 'apps/website/tsconfig.json', - ); - }); }); diff --git a/packages/cli/src/lib/implementation/core-config.model.ts b/packages/cli/src/lib/implementation/core-config.model.ts index f6675befc..ed011da56 100644 --- a/packages/cli/src/lib/implementation/core-config.model.ts +++ b/packages/cli/src/lib/implementation/core-config.model.ts @@ -19,6 +19,6 @@ export type ConfigCliOptions = { verbose?: string; }; -export type CoreConfigCliOptions = Pick & { +export type CoreConfigCliOptions = Pick & { upload?: Partial>; }; diff --git a/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts b/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts index aca98fb91..0f36b24ab 100644 --- a/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts +++ b/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts @@ -47,6 +47,7 @@ describe('merge-diffs-command', () => { outputDir: DEFAULT_PERSIST_OUTPUT_DIR, filename: DEFAULT_PERSIST_FILENAME, format: DEFAULT_PERSIST_FORMAT, + report: true, }, ); }); From e5658983a63e030e30dd84b587497ed7db2d2cb1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Aug 2025 01:23:18 +0200 Subject: [PATCH 04/10] test: adjust unit test --- packages/cli/src/lib/compare/compare-command.unit.test.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/cli/src/lib/compare/compare-command.unit.test.ts b/packages/cli/src/lib/compare/compare-command.unit.test.ts index 95a82c714..a90dd01e4 100644 --- a/packages/cli/src/lib/compare/compare-command.unit.test.ts +++ b/packages/cli/src/lib/compare/compare-command.unit.test.ts @@ -43,17 +43,11 @@ describe('compare-command', () => { format: DEFAULT_PERSIST_FORMAT, report: true, }, - upload: { - apiKey: 'dummy-api-key', - organization: 'code-pushup', - project: 'cli', - server: 'https://example.com/api', - }, + upload: expect.any(Object), }, { before: 'source-report.json', after: 'target-report.json', - label: undefined, }, ); }); From 023fbf6b0396eb0d17d006adcfe94cf6f1ee8ffb Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Aug 2025 02:08:24 +0200 Subject: [PATCH 05/10] feat: add CLI options for persist.report --- e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap | 2 ++ packages/cli/src/lib/implementation/core-config.model.ts | 1 + packages/cli/src/lib/implementation/core-config.options.ts | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap b/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap index beb76af1f..7ec1ed363 100644 --- a/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap +++ b/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap @@ -43,6 +43,8 @@ Persist Options: [string] --persist.format Format of the report output. e.g. \`md\`, \`json\` [array] + --persist.report Generate the report files for given formats. (useful + in combination with caching) [boolean] Upload Options: --upload.organization Organization slug from portal diff --git a/packages/cli/src/lib/implementation/core-config.model.ts b/packages/cli/src/lib/implementation/core-config.model.ts index ed011da56..7442797f1 100644 --- a/packages/cli/src/lib/implementation/core-config.model.ts +++ b/packages/cli/src/lib/implementation/core-config.model.ts @@ -4,6 +4,7 @@ export type PersistConfigCliOptions = { 'persist.outputDir'?: string; 'persist.filename'?: string; 'persist.format'?: Format; + 'persist.report'?: boolean; }; export type UploadConfigCliOptions = { diff --git a/packages/cli/src/lib/implementation/core-config.options.ts b/packages/cli/src/lib/implementation/core-config.options.ts index 79d62346a..71bbd202c 100644 --- a/packages/cli/src/lib/implementation/core-config.options.ts +++ b/packages/cli/src/lib/implementation/core-config.options.ts @@ -31,6 +31,11 @@ export function yargsPersistConfigOptionsDefinition(): Record< describe: 'Format of the report output. e.g. `md`, `json`', type: 'array', }, + 'persist.report': { + describe: + 'Generate the report files for given formats. (useful in combination with caching)', + type: 'boolean', + }, }; } From 44257f4095c30514df8cb9607a90a9ebc48b6462 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Aug 2025 02:40:34 +0200 Subject: [PATCH 06/10] feat: add normalize helper for normalization --- .../implementation/core-config.middleware.ts | 17 +++++++++- .../core-config.middleware.unit.test.ts | 31 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/lib/implementation/core-config.middleware.ts b/packages/cli/src/lib/implementation/core-config.middleware.ts index 86bb9746d..3273acce9 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.ts @@ -53,7 +53,11 @@ export async function coreConfigMiddleware< format: normalizeFormats( cliPersist?.format ?? rcPersist?.format ?? DEFAULT_PERSIST_FORMAT, ), - report: !('no-report' in (cliPersist ?? {})), + report: normalizeBooleanWithNegation( + 'report', + cliPersist as Record, + rcPersist as Record, + ), }, ...(upload != null && { upload }), ...remainingRcConfig, @@ -61,5 +65,16 @@ export async function coreConfigMiddleware< }; } +export const normalizeBooleanWithNegation = ( + propertyName: T, + cliOptions?: Record, + rcOptions?: Record, +): boolean => + propertyName in (cliOptions ?? {}) + ? (cliOptions?.[propertyName] as boolean) + : `no-${propertyName}` in (cliOptions ?? {}) + ? false + : ((rcOptions?.[propertyName] as boolean) ?? true); + export const normalizeFormats = (formats?: string[]): Format[] => (formats ?? []).flatMap(format => format.split(',') as Format[]); diff --git a/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts b/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts index 134b8f183..8c27e3abd 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.unit.test.ts @@ -2,6 +2,7 @@ import { describe, expect, vi } from 'vitest'; import { autoloadRc, readRcByPath } from '@code-pushup/core'; import { coreConfigMiddleware, + normalizeBooleanWithNegation, normalizeFormats, } from './core-config.middleware.js'; import type { CoreConfigCliOptions } from './core-config.model.js'; @@ -19,6 +20,36 @@ vi.mock('@code-pushup/core', async () => { }; }); +describe('normalizeBooleanWithNegation', () => { + it('should return true when CLI property is true', () => { + expect(normalizeBooleanWithNegation('report', { report: true }, {})).toBe( + true, + ); + }); + + it('should return false when CLI property is false', () => { + expect(normalizeBooleanWithNegation('report', { report: false }, {})).toBe( + false, + ); + }); + + it('should return false when no-property exists in CLI persist', () => { + expect( + normalizeBooleanWithNegation('report', { 'no-report': true }, {}), + ).toBe(false); + }); + + it('should fallback to RC persist when no CLI property', () => { + expect(normalizeBooleanWithNegation('report', {}, { report: false })).toBe( + false, + ); + }); + + it('should return default true when no property anywhere', () => { + expect(normalizeBooleanWithNegation('report', {}, {})).toBe(true); + }); +}); + describe('normalizeFormats', () => { it('should forward valid formats', () => { expect(normalizeFormats(['json', 'md'])).toEqual(['json', 'md']); From 957c86518ec8ccbe73cb159b75c4dcefdbc54e08 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 11 Aug 2025 21:14:21 +0200 Subject: [PATCH 07/10] fix: adjust report logic --- e2e/cli-e2e/tests/collect.e2e.test.ts | 4 ++-- packages/ci/src/lib/run-utils.ts | 2 +- packages/cli/README.md | 24 +++++++++---------- .../lib/compare/compare-command.unit.test.ts | 2 +- .../implementation/core-config.int.test.ts | 10 ++++---- .../implementation/core-config.middleware.ts | 6 +---- .../lib/implementation/core-config.model.ts | 2 +- .../lib/implementation/core-config.options.ts | 4 ++-- .../merge-diffs-command.unit.test.ts | 2 +- packages/core/src/lib/collect-and-persist.ts | 11 ++++----- .../src/lib/collect-and-persist.unit.test.ts | 4 ++-- .../core/src/lib/implementation/persist.ts | 2 +- packages/models/src/lib/persist-config.ts | 2 +- packages/utils/src/lib/file-system.ts | 2 +- 14 files changed, 36 insertions(+), 41 deletions(-) diff --git a/e2e/cli-e2e/tests/collect.e2e.test.ts b/e2e/cli-e2e/tests/collect.e2e.test.ts index 52ee4087f..f1f76ddfc 100644 --- a/e2e/cli-e2e/tests/collect.e2e.test.ts +++ b/e2e/cli-e2e/tests/collect.e2e.test.ts @@ -61,14 +61,14 @@ describe('CLI collect', () => { expect(md).toContain(dummyAuditTitle); }); - it('should not create reports if --persist.no-report is given', async () => { + it('should not create reports if --persist.skipReports is given', async () => { const { code } = await executeProcess({ command: 'npx', args: [ '@code-pushup/cli', '--no-progress', 'collect', - '--persist.no-report', + '--persist.skipReports', ], cwd: dummyDir, }); diff --git a/packages/ci/src/lib/run-utils.ts b/packages/ci/src/lib/run-utils.ts index abbb1dbce..6aceb13c6 100644 --- a/packages/ci/src/lib/run-utils.ts +++ b/packages/ci/src/lib/run-utils.ts @@ -483,7 +483,7 @@ export function configFromPatterns( outputDir: interpolate(persist.outputDir, variables), filename: interpolate(persist.filename, variables), format: persist.format, - report: persist.report, + skipReports: persist.skipReports, }, ...(upload && { upload: { diff --git a/packages/cli/README.md b/packages/cli/README.md index 9f48ff35d..14a598d53 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -207,18 +207,18 @@ Each example is fully tested to demonstrate best practices for plugin testing as ### Common Command Options -| Option | Type | Default | Description | -| --------------------------- | -------------------- | -------- | -------------------------------------------------------------------------------- | -| **`--persist.outputDir`** | `string` | n/a | Directory for the produced reports. | -| **`--persist.filename`** | `string` | `report` | Filename for the produced reports without extension. | -| **`--persist.format`** | `('json' \| 'md')[]` | `json` | Format(s) of the report file. | -| **`--persist.report`** | `boolean` | `true` | Generate the report files for given formats. (useful in combination wit caching) | -| **`--upload.organization`** | `string` | n/a | Organization slug from portal. | -| **`--upload.project`** | `string` | n/a | Project slug from portal. | -| **`--upload.server`** | `string` | n/a | URL to your portal server. | -| **`--upload.apiKey`** | `string` | n/a | API key for the portal server. | -| **`--onlyPlugins`** | `string[]` | `[]` | Only run the specified plugins. Applicable to all commands except `upload`. | -| **`--skipPlugins`** | `string[]` | `[]` | Skip the specified plugins. Applicable to all commands except `upload`. | +| Option | Type | Default | Description | +| --------------------------- | -------------------- | -------- | --------------------------------------------------------------------------- | +| **`--persist.outputDir`** | `string` | n/a | Directory for the produced reports. | +| **`--persist.filename`** | `string` | `report` | Filename for the produced reports without extension. | +| **`--persist.format`** | `('json' \| 'md')[]` | `json` | Format(s) of the report file. | +| **`--persist.skipReports`** | `boolean` | `false` | Skip generating report files. (useful in combination wit caching) | +| **`--upload.organization`** | `string` | n/a | Organization slug from portal. | +| **`--upload.project`** | `string` | n/a | Project slug from portal. | +| **`--upload.server`** | `string` | n/a | URL to your portal server. | +| **`--upload.apiKey`** | `string` | n/a | API key for the portal server. | +| **`--onlyPlugins`** | `string[]` | `[]` | Only run the specified plugins. Applicable to all commands except `upload`. | +| **`--skipPlugins`** | `string[]` | `[]` | Skip the specified plugins. Applicable to all commands except `upload`. | > [!NOTE] > All common options, except `--onlyPlugins` and `--skipPlugins`, can be specified in the configuration file as well. diff --git a/packages/cli/src/lib/compare/compare-command.unit.test.ts b/packages/cli/src/lib/compare/compare-command.unit.test.ts index a90dd01e4..69d78cfc7 100644 --- a/packages/cli/src/lib/compare/compare-command.unit.test.ts +++ b/packages/cli/src/lib/compare/compare-command.unit.test.ts @@ -41,7 +41,7 @@ describe('compare-command', () => { outputDir: DEFAULT_PERSIST_OUTPUT_DIR, filename: DEFAULT_PERSIST_FILENAME, format: DEFAULT_PERSIST_FORMAT, - report: true, + skipReports: false, }, upload: expect.any(Object), }, diff --git a/packages/cli/src/lib/implementation/core-config.int.test.ts b/packages/cli/src/lib/implementation/core-config.int.test.ts index 5068117e3..0e9e57616 100644 --- a/packages/cli/src/lib/implementation/core-config.int.test.ts +++ b/packages/cli/src/lib/implementation/core-config.int.test.ts @@ -64,7 +64,7 @@ describe('parsing values from CLI and middleware', () => { filename: DEFAULT_PERSIST_FILENAME, format: DEFAULT_PERSIST_FORMAT, outputDir: DEFAULT_PERSIST_OUTPUT_DIR, - report: true, + skipReports: false, }); }); @@ -86,7 +86,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'cli-filename', format: ['md'], outputDir: 'cli-outputDir', - report: true, + skipReports: false, }); }); @@ -103,7 +103,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'rc-filename', format: ['json', 'md'], outputDir: 'rc-outputDir', - report: true, + skipReports: false, }); }); @@ -125,7 +125,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'cli-filename', format: ['md'], outputDir: 'cli-outputDir', - report: true, + skipReports: false, }); }); @@ -145,7 +145,7 @@ describe('parsing values from CLI and middleware', () => { filename: 'rc-filename', format: DEFAULT_PERSIST_FORMAT, outputDir: 'cli-outputdir', - report: true, + skipReports: false, }); }); diff --git a/packages/cli/src/lib/implementation/core-config.middleware.ts b/packages/cli/src/lib/implementation/core-config.middleware.ts index 3273acce9..383c93745 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.ts @@ -53,11 +53,7 @@ export async function coreConfigMiddleware< format: normalizeFormats( cliPersist?.format ?? rcPersist?.format ?? DEFAULT_PERSIST_FORMAT, ), - report: normalizeBooleanWithNegation( - 'report', - cliPersist as Record, - rcPersist as Record, - ), + skipReports: cliPersist?.skipReports ?? rcPersist?.skipReports ?? false, }, ...(upload != null && { upload }), ...remainingRcConfig, diff --git a/packages/cli/src/lib/implementation/core-config.model.ts b/packages/cli/src/lib/implementation/core-config.model.ts index 7442797f1..a5f668bb5 100644 --- a/packages/cli/src/lib/implementation/core-config.model.ts +++ b/packages/cli/src/lib/implementation/core-config.model.ts @@ -4,7 +4,7 @@ export type PersistConfigCliOptions = { 'persist.outputDir'?: string; 'persist.filename'?: string; 'persist.format'?: Format; - 'persist.report'?: boolean; + 'persist.skipReports'?: boolean; }; export type UploadConfigCliOptions = { diff --git a/packages/cli/src/lib/implementation/core-config.options.ts b/packages/cli/src/lib/implementation/core-config.options.ts index 71bbd202c..bc97e98c7 100644 --- a/packages/cli/src/lib/implementation/core-config.options.ts +++ b/packages/cli/src/lib/implementation/core-config.options.ts @@ -31,9 +31,9 @@ export function yargsPersistConfigOptionsDefinition(): Record< describe: 'Format of the report output. e.g. `md`, `json`', type: 'array', }, - 'persist.report': { + 'persist.skipReports': { describe: - 'Generate the report files for given formats. (useful in combination with caching)', + 'Skip generating report files. (useful in combination with caching)', type: 'boolean', }, }; diff --git a/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts b/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts index 0f36b24ab..3313004c4 100644 --- a/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts +++ b/packages/cli/src/lib/merge-diffs/merge-diffs-command.unit.test.ts @@ -47,7 +47,7 @@ describe('merge-diffs-command', () => { outputDir: DEFAULT_PERSIST_OUTPUT_DIR, filename: DEFAULT_PERSIST_FILENAME, format: DEFAULT_PERSIST_FORMAT, - report: true, + skipReports: false, }, ); }); diff --git a/packages/core/src/lib/collect-and-persist.ts b/packages/core/src/lib/collect-and-persist.ts index fd8a211e4..4d0e2c55f 100644 --- a/packages/core/src/lib/collect-and-persist.ts +++ b/packages/core/src/lib/collect-and-persist.ts @@ -21,8 +21,8 @@ export type CollectAndPersistReportsOptions = Pick< CoreConfig, 'plugins' | 'categories' > & { - persist: Required> & - Pick; + persist: Required> & + Pick; } & Partial; export async function collectAndPersistReports( @@ -33,10 +33,9 @@ export async function collectAndPersistReports( const sortedScoredReport = sortReport(scoreReport(reportResult)); const { persist } = options; - const { report: shouldGenerateReport = true, ...persistOptions } = - persist ?? {}; + const { skipReports = false, ...persistOptions } = persist ?? {}; - if (shouldGenerateReport === true) { + if (skipReports !== true) { const persistResults = await persistReport( reportResult, sortedScoredReport, @@ -47,7 +46,7 @@ export async function collectAndPersistReports( logPersistedResults(persistResults); } } else { - logger.info('Skipping saving reports as `persist.report` is false'); + logger.info('Skipping saving reports as `persist.skipReports` is true'); } // terminal output diff --git a/packages/core/src/lib/collect-and-persist.unit.test.ts b/packages/core/src/lib/collect-and-persist.unit.test.ts index 00d38c76c..9cdeacd8c 100644 --- a/packages/core/src/lib/collect-and-persist.unit.test.ts +++ b/packages/core/src/lib/collect-and-persist.unit.test.ts @@ -115,7 +115,7 @@ describe('collectAndPersistReports', () => { expect(logPersistedResults).toHaveBeenCalled(); }); - it('should call collect and not persistReport if report options is false in verbose mode', async () => { + it('should call collect and not persistReport if skipReports options is true in verbose mode', async () => { const sortedScoredReport = sortReport(scoreReport(MINIMAL_REPORT_MOCK)); vi.stubEnv('CP_VERBOSE', 'true'); @@ -126,7 +126,7 @@ describe('collectAndPersistReports', () => { outputDir: 'output', filename: 'report', format: ['md'], - report: false, + skipReports: true, }, progress: false, }; diff --git a/packages/core/src/lib/implementation/persist.ts b/packages/core/src/lib/implementation/persist.ts index c55a0103e..069b16c69 100644 --- a/packages/core/src/lib/implementation/persist.ts +++ b/packages/core/src/lib/implementation/persist.ts @@ -25,7 +25,7 @@ export class PersistError extends Error { export async function persistReport( report: Report, sortedScoredReport: ScoredReport, - options: Required>, + options: Required>, ): Promise { const { outputDir, filename, format } = options; diff --git a/packages/models/src/lib/persist-config.ts b/packages/models/src/lib/persist-config.ts index c12e85ed8..81cc80c0b 100644 --- a/packages/models/src/lib/persist-config.ts +++ b/packages/models/src/lib/persist-config.ts @@ -10,7 +10,7 @@ export const persistConfigSchema = z.object({ .describe('Artifacts file name (without extension)') .optional(), format: z.array(formatSchema).optional(), - report: z.boolean().optional(), + skipReports: z.boolean().optional(), }); export type PersistConfig = z.infer; diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index 51d54d671..268eed737 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -90,7 +90,7 @@ export function createReportPath({ filename, format, suffix, -}: Omit, 'format' | 'report'> & { +}: Pick, 'filename' | 'outputDir'> & { format: Format; suffix?: string; }): string { From 246c7805264615a5c81d1f057fcab0a20a954f1b Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Mon, 11 Aug 2025 21:19:10 +0200 Subject: [PATCH 08/10] Update packages/cli/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- packages/cli/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/README.md b/packages/cli/README.md index 14a598d53..1cb2d119d 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -212,7 +212,7 @@ Each example is fully tested to demonstrate best practices for plugin testing as | **`--persist.outputDir`** | `string` | n/a | Directory for the produced reports. | | **`--persist.filename`** | `string` | `report` | Filename for the produced reports without extension. | | **`--persist.format`** | `('json' \| 'md')[]` | `json` | Format(s) of the report file. | -| **`--persist.skipReports`** | `boolean` | `false` | Skip generating report files. (useful in combination wit caching) | +| **`--persist.skipReports`** | `boolean` | `false` | Skip generating report files. (useful in combination with caching) | | **`--upload.organization`** | `string` | n/a | Organization slug from portal. | | **`--upload.project`** | `string` | n/a | Project slug from portal. | | **`--upload.server`** | `string` | n/a | URL to your portal server. | From ed35b650b34ec2d43d1d0994f3a662704e6e12f8 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 11 Aug 2025 22:08:30 +0200 Subject: [PATCH 09/10] fix: adjust middleware --- packages/cli/README.md | 2 +- .../implementation/core-config.middleware.ts | 31 ++++++++++++------- packages/core/src/lib/collect-and-persist.ts | 6 ++-- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/packages/cli/README.md b/packages/cli/README.md index 1cb2d119d..7bb2e8f90 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -212,7 +212,7 @@ Each example is fully tested to demonstrate best practices for plugin testing as | **`--persist.outputDir`** | `string` | n/a | Directory for the produced reports. | | **`--persist.filename`** | `string` | `report` | Filename for the produced reports without extension. | | **`--persist.format`** | `('json' \| 'md')[]` | `json` | Format(s) of the report file. | -| **`--persist.skipReports`** | `boolean` | `false` | Skip generating report files. (useful in combination with caching) | +| **`--persist.skipReports`** | `boolean` | `false` | Skip generating report files. (useful in combination with caching) | | **`--upload.organization`** | `string` | n/a | Organization slug from portal. | | **`--upload.project`** | `string` | n/a | Project slug from portal. | | **`--upload.server`** | `string` | n/a | URL to your portal server. | diff --git a/packages/cli/src/lib/implementation/core-config.middleware.ts b/packages/cli/src/lib/implementation/core-config.middleware.ts index 383c93745..f21ecf474 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.ts @@ -15,6 +15,24 @@ export type CoreConfigMiddlewareOptions = GeneralCliOptions & CoreConfigCliOptions & FilterOptions; +function buildPersistConfig( + cliPersist: CoreConfigCliOptions['persist'], + rcPersist: CoreConfig['persist'], +): Required { + return { + outputDir: + cliPersist?.outputDir ?? + rcPersist?.outputDir ?? + DEFAULT_PERSIST_OUTPUT_DIR, + filename: + cliPersist?.filename ?? rcPersist?.filename ?? DEFAULT_PERSIST_FILENAME, + format: normalizeFormats( + cliPersist?.format ?? rcPersist?.format ?? DEFAULT_PERSIST_FORMAT, + ), + skipReports: cliPersist?.skipReports ?? rcPersist?.skipReports ?? false, + }; +} + export async function coreConfigMiddleware< T extends CoreConfigMiddlewareOptions, >(processArgs: T): Promise { @@ -43,18 +61,7 @@ export async function coreConfigMiddleware< }); return { ...(config != null && { config }), - persist: { - outputDir: - cliPersist?.outputDir ?? - rcPersist?.outputDir ?? - DEFAULT_PERSIST_OUTPUT_DIR, - filename: - cliPersist?.filename ?? rcPersist?.filename ?? DEFAULT_PERSIST_FILENAME, - format: normalizeFormats( - cliPersist?.format ?? rcPersist?.format ?? DEFAULT_PERSIST_FORMAT, - ), - skipReports: cliPersist?.skipReports ?? rcPersist?.skipReports ?? false, - }, + persist: buildPersistConfig(cliPersist, rcPersist), ...(upload != null && { upload }), ...remainingRcConfig, ...remainingCliOptions, diff --git a/packages/core/src/lib/collect-and-persist.ts b/packages/core/src/lib/collect-and-persist.ts index 4d0e2c55f..8445050d0 100644 --- a/packages/core/src/lib/collect-and-persist.ts +++ b/packages/core/src/lib/collect-and-persist.ts @@ -35,7 +35,9 @@ export async function collectAndPersistReports( const { persist } = options; const { skipReports = false, ...persistOptions } = persist ?? {}; - if (skipReports !== true) { + if (skipReports === true) { + logger.info('Skipping saving reports as `persist.skipReports` is true'); + } else { const persistResults = await persistReport( reportResult, sortedScoredReport, @@ -45,8 +47,6 @@ export async function collectAndPersistReports( if (isVerbose()) { logPersistedResults(persistResults); } - } else { - logger.info('Skipping saving reports as `persist.skipReports` is true'); } // terminal output From 62775ca6311379eeeb3a330b6442e6b139210eae Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 11 Aug 2025 22:21:37 +0200 Subject: [PATCH 10/10] test: update snapshots --- e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap b/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap index 7ec1ed363..90368b081 100644 --- a/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap +++ b/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap @@ -37,14 +37,14 @@ Global Options: [array] [default: []] Persist Options: - --persist.outputDir Directory for the produced reports + --persist.outputDir Directory for the produced reports [string] - --persist.filename Filename for the produced reports. + --persist.filename Filename for the produced reports. [string] - --persist.format Format of the report output. e.g. \`md\`, \`json\` + --persist.format Format of the report output. e.g. \`md\`, \`json\` [array] - --persist.report Generate the report files for given formats. (useful - in combination with caching) [boolean] + --persist.skipReports Skip generating report files. (useful in combinatio + n with caching) [boolean] Upload Options: --upload.organization Organization slug from portal