Skip to content

Commit b5b3bc6

Browse files
authored
fix(cli): adjust persist.format options (#363)
1 parent 6337beb commit b5b3bc6

12 files changed

+120
-27
lines changed

e2e/cli-e2e/tests/print-config.e2e.test.ts

+6-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
PERSIST_FORMAT,
55
PERSIST_OUTPUT_DIR,
66
} from '@code-pushup/models';
7-
import { executeProcess } from '@code-pushup/utils';
7+
import { executeProcess, objectToCliArgs } from '@code-pushup/utils';
88
import { configFile, extensions } from '../mocks/utils';
99

1010
describe('print-config', () => {
@@ -54,7 +54,7 @@ describe('print-config', () => {
5454
120000,
5555
);
5656

57-
it('should load .ts config file and overwrite it with CLI arguments', async ext => {
57+
it('should load .ts config file and overload it with arguments', async () => {
5858
const { code, stderr, stdout } = await executeProcess({
5959
command: 'code-pushup',
6060
args: [
@@ -68,16 +68,11 @@ describe('print-config', () => {
6868
],
6969
});
7070

71-
expect(code).toBe(0);
72-
expect(stderr).toBe('');
73-
expect(JSON.parse(stdout)).toEqual(
71+
expect(JSON.parse(stdout)?.persist).toEqual(
7472
expect.objectContaining({
75-
config: expect.stringContaining(`code-pushup.config.ts`),
76-
persist: {
77-
outputDir: 'my-dir',
78-
format: ['md'],
79-
filename: 'my-report',
80-
},
73+
outputDir: 'my-dir',
74+
format: ['md'],
75+
filename: 'my-report',
8176
}),
8277
);
8378
}, 120000);

examples/plugins/project.json

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
"run-collect": {
3535
"command": "npx dist/packages/cli collect --config=examples/plugins/code-pushup.config.ts --persist.format=md",
3636
"dependsOn": ["^build"]
37+
},
38+
"run-print-config": {
39+
"command": "npx dist/packages/cli print-config --config=examples/plugins/code-pushup.config.ts",
40+
"dependsOn": ["^build"]
3741
}
3842
},
3943
"tags": []

packages/cli/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"@code-pushup/models": "*",
99
"@code-pushup/core": "*",
1010
"yargs": "^17.7.2",
11-
"chalk": "^5.3.0"
11+
"chalk": "^5.3.0",
12+
"@code-pushup/utils": "*"
1213
}
1314
}

packages/cli/src/lib/implementation/config-middleware.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { readCodePushupConfig } from '@code-pushup/core';
22
import {
33
CoreConfig,
4+
Format,
45
PERSIST_FILENAME,
56
PERSIST_FORMAT,
67
PERSIST_OUTPUT_DIR,
@@ -11,6 +12,7 @@ import {
1112
filterPluginsByOnlyPluginsOption,
1213
validateOnlyPluginsOption,
1314
} from './only-plugins-utils';
15+
import { coerceArray } from './utils';
1416

1517
export async function configMiddleware<
1618
T extends Partial<GeneralCliOptions & CoreConfig & OnlyPluginsOptions>,
@@ -44,10 +46,11 @@ export async function configMiddleware<
4446
cliOptions?.persist?.filename ||
4547
importedRc?.persist?.filename ||
4648
PERSIST_FILENAME,
47-
format:
49+
format: coerceArray<Format>(
4850
cliOptions?.persist?.format ||
49-
importedRc?.persist?.format ||
50-
PERSIST_FORMAT,
51+
importedRc?.persist?.format ||
52+
PERSIST_FORMAT,
53+
),
5154
},
5255
plugins: filterPluginsByOnlyPluginsOption(importedRc.plugins, cliOptions),
5356
categories: filterCategoryByOnlyPluginsOption(
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,47 @@
1+
import { join } from 'node:path';
12
import { describe, expect } from 'vitest';
23
import { CoreConfig } from '@code-pushup/models';
34
import { objectToCliArgs } from '@code-pushup/utils';
45
import { yargsCli } from '../yargs-cli';
56
import { yargsCoreConfigOptionsDefinition } from './core-config-options';
67

78
describe('configOptions', () => {
8-
function cli(args: Record<string, unknown>): Promise<CoreConfig> {
9-
return yargsCli(objectToCliArgs(args), {
10-
options: yargsCoreConfigOptionsDefinition(),
11-
}).parseAsync() as unknown as Promise<CoreConfig>;
9+
function argsFromCli(args: Record<string, unknown>): Promise<CoreConfig> {
10+
return yargsCli(
11+
objectToCliArgs({
12+
...args,
13+
config: join('code-pushup.config.ts'),
14+
}),
15+
{
16+
options: yargsCoreConfigOptionsDefinition(),
17+
},
18+
).parseAsync() as unknown as Promise<CoreConfig>;
1219
}
1320

1421
it('should fill defaults', async () => {
15-
const config = await cli({});
22+
const config = await argsFromCli({ config: 'code-pushup.config.ts' });
1623
expect(config).toBeDefined();
1724
// only _ and $0
18-
expect(Object.keys(config)).toHaveLength(2);
25+
expect(Object.keys(config)).toHaveLength(3);
1926
});
27+
28+
it.each([
29+
// defaults
30+
[{}, {}],
31+
// persist.outputDir
32+
[{ 'persist.outputDir': 'my-dir' }, { outputDir: 'my-dir' }],
33+
// persist.filename
34+
[{ 'persist.filename': 'my-report' }, { filename: 'my-report' }],
35+
// persist.format
36+
[{ 'persist.format': 'md' }, { format: ['md'] }],
37+
[{ 'persist.format': ['md', 'json'] }, { format: ['md', 'json'] }],
38+
// [{ 'persist.format': 'md,json' }, { format: ['md', 'json'] }], @TODO comment in when config auto-loading is implemented
39+
])(
40+
'should parse persist options %j correctly as %j',
41+
async (options, result) => {
42+
const args = await argsFromCli(options);
43+
44+
expect(args?.persist).toEqual(expect.objectContaining(result));
45+
},
46+
);
2047
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, expect } from 'vitest';
2+
import { objectToCliArgs } from '@code-pushup/utils';
3+
import { yargsCli } from '../yargs-cli';
4+
import { yargsOnlyPluginsOptionsDefinition } from './only-plugins-options';
5+
6+
describe('onlyPlugin option', () => {
7+
type OnlyPluginsOptions = { onlyPlugins?: string | string[] };
8+
function argsFromCli<T extends OnlyPluginsOptions>(
9+
args: Record<string, unknown>,
10+
) {
11+
return yargsCli<T>(objectToCliArgs(args), {
12+
options: yargsOnlyPluginsOptionsDefinition(),
13+
}).parseAsync() as unknown as Promise<OnlyPluginsOptions>;
14+
}
15+
16+
it('should fill defaults', async () => {
17+
const args = await argsFromCli({});
18+
expect(args).toBeDefined();
19+
// "_" and "$0" are in by default
20+
// camelCase and kebab-case of each option value
21+
expect(Object.keys(args)).toHaveLength(4);
22+
});
23+
24+
it.each([
25+
// defaults
26+
[{}, []],
27+
[{ onlyPlugins: 'lighthouse' }, ['lighthouse']],
28+
[{ onlyPlugins: ['lighthouse', 'eslint'] }, ['lighthouse', 'eslint']],
29+
[{ onlyPlugins: 'lighthouse,eslint' }, ['lighthouse', 'eslint']],
30+
])(
31+
'should parse onlyPlugins options %j correctly as %j correctly',
32+
async (options, result) => {
33+
const parsedArgs = await argsFromCli(options);
34+
expect(parsedArgs?.onlyPlugins).toEqual(result);
35+
},
36+
);
37+
});

packages/cli/src/lib/implementation/only-plugins-options.ts

+9
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,12 @@ export const onlyPluginsOption: Options = {
66
default: [],
77
coerce: (arg: string[]) => arg.flatMap(v => v.split(',')),
88
};
9+
10+
export function yargsOnlyPluginsOptionsDefinition(): Record<
11+
'onlyPlugins',
12+
Options
13+
> {
14+
return {
15+
onlyPlugins: onlyPluginsOption,
16+
};
17+
}

packages/cli/src/lib/implementation/only-plugins-utils.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ export function filterPluginsByOnlyPluginsOption(
1515
// see https://github.com/code-pushup/cli/pull/246#discussion_r1392274281
1616
export function filterCategoryByOnlyPluginsOption(
1717
categories: CoreConfig['categories'],
18-
{ onlyPlugins }: { onlyPlugins?: string[] },
18+
{
19+
onlyPlugins,
20+
verbose = false,
21+
}: { onlyPlugins?: string[]; verbose?: boolean },
1922
): CoreConfig['categories'] {
2023
if (!onlyPlugins?.length) {
2124
return categories;
@@ -25,7 +28,7 @@ export function filterCategoryByOnlyPluginsOption(
2528
category.refs.every(ref => {
2629
const isNotSkipped = onlyPlugins.includes(ref.slug);
2730

28-
if (!isNotSkipped) {
31+
if (!isNotSkipped && verbose) {
2932
console.info(
3033
`${chalk.yellow('⚠')} Category "${
3134
category.title
@@ -42,13 +45,16 @@ export function filterCategoryByOnlyPluginsOption(
4245

4346
export function validateOnlyPluginsOption(
4447
plugins: CoreConfig['plugins'],
45-
{ onlyPlugins }: { onlyPlugins?: string[] },
48+
{
49+
onlyPlugins,
50+
verbose = false,
51+
}: { onlyPlugins?: string[]; verbose?: boolean },
4652
): void {
4753
const missingPlugins = onlyPlugins?.length
4854
? onlyPlugins.filter(plugin => !plugins.some(({ slug }) => slug === plugin))
4955
: [];
5056

51-
if (missingPlugins.length > 0) {
57+
if (missingPlugins.length > 0 && verbose) {
5258
console.warn(
5359
`${chalk.yellow(
5460
'⚠',

packages/cli/src/lib/implementation/only-plugins-utils.unit.test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ describe('filterCategoryByOnlyPluginsOption', () => {
7575
] as CoreConfig['categories'],
7676
{
7777
onlyPlugins: ['plugin1', 'plugin3'],
78+
verbose: true,
7879
},
7980
);
8081
expect(console.info).toHaveBeenCalledWith(
@@ -92,6 +93,7 @@ describe('validateOnlyPluginsOption', () => {
9293
[{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'],
9394
{
9495
onlyPlugins: ['plugin1', 'plugin3', 'plugin4'],
96+
verbose: true,
9597
},
9698
);
9799
expect(console.warn).toHaveBeenCalledWith(
@@ -106,6 +108,7 @@ describe('validateOnlyPluginsOption', () => {
106108
[{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'],
107109
{
108110
onlyPlugins: ['plugin1'],
111+
verbose: true,
109112
},
110113
);
111114
expect(console.warn).not.toHaveBeenCalled();

packages/cli/src/lib/implementation/utils.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { toArray } from '@code-pushup/utils';
2+
13
// log error and flush stdout so that Yargs doesn't suppress it
24
// related issue: https://github.com/yargs/yargs/issues/2118
35
export function logErrorBeforeThrow<
@@ -15,3 +17,9 @@ export function logErrorBeforeThrow<
1517
}
1618
}) as T;
1719
}
20+
21+
export function coerceArray<T extends string>(param: T | T[] = []): T[] {
22+
return [
23+
...new Set(toArray(param).flatMap((f: T) => f.split(',') as T[]) || []),
24+
];
25+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Format } from '../persist-config';
22

33
export const PERSIST_OUTPUT_DIR = '.code-pushup';
4-
export const PERSIST_FORMAT = ['json'] satisfies Format[];
4+
export const PERSIST_FORMAT: Format[] = ['json'];
55
export const PERSIST_FILENAME = 'report';

packages/plugin-eslint/src/lib/runner.integration.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,5 @@ describe('executeRunner', () => {
9393
},
9494
} satisfies Partial<AuditOutput>),
9595
);
96-
});
96+
}, 7000);
9797
});

0 commit comments

Comments
 (0)