Skip to content

Commit 074c50f

Browse files
committed
feat(cli): scaffold merge-diffs command and test argument parsing
1 parent e5036f1 commit 074c50f

File tree

10 files changed

+178
-0
lines changed

10 files changed

+178
-0
lines changed

e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Commands:
1414
code-pushup compare Compare 2 report files and create a diff file
1515
1616
code-pushup print-config Print config
17+
code-pushup merge-diffs Combine many report diffs into single report-diff.md
18+
1719
1820
Global Options:
1921
--progress Show progress bar in stdout.

packages/cli/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,17 @@ Description:
285285
Print the resolved configuration.
286286

287287
Refer to the [Common Command Options](#common-command-options) for the list of available options.
288+
289+
### `merge-diffs` command
290+
291+
Usage:
292+
`code-pushup merge-diffs --files PATH_1 PATH_2 ... [options]`
293+
294+
Description:
295+
Combine multiple report diffs into a single `report-diff.md`.
296+
297+
In addition to the [Common Command Options](#common-command-options), the following options are recognized by the `merge-diffs` command:
298+
299+
| Option | Required | Type | Description |
300+
| ------------- | :------: | ---------- | --------------------------------- |
301+
| **`--files`** | yes | `string[]` | List of `report-diff.json` paths. |

packages/cli/src/lib/commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { yargsAutorunCommandObject } from './autorun/autorun-command';
33
import { yargsCollectCommandObject } from './collect/collect-command';
44
import { yargsCompareCommandObject } from './compare/compare-command';
55
import { yargsHistoryCommandObject } from './history/history-command';
6+
import { yargsMergeDiffsCommandObject } from './merge-diffs/merge-diffs-command';
67
import { yargsConfigCommandObject } from './print-config/print-config-command';
78
import { yargsUploadCommandObject } from './upload/upload-command';
89

@@ -17,4 +18,5 @@ export const commands: CommandModule[] = [
1718
yargsHistoryCommandObject(),
1819
yargsCompareCommandObject(),
1920
yargsConfigCommandObject(),
21+
yargsMergeDiffsCommandObject(),
2022
];
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type MergeDiffsOptions = {
2+
files: string[];
3+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Options } from 'yargs';
2+
import type { MergeDiffsOptions } from './merge-diffs.model';
3+
4+
export function yargsMergeDiffsOptionsDefinition(): Record<
5+
keyof MergeDiffsOptions,
6+
Options
7+
> {
8+
return {
9+
files: {
10+
describe: 'List of report-diff.json paths',
11+
type: 'array',
12+
demandOption: true,
13+
},
14+
};
15+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { bold, gray } from 'ansis';
2+
import { CommandModule } from 'yargs';
3+
import { mergeDiffs } from '@code-pushup/core';
4+
import { PersistConfig } from '@code-pushup/models';
5+
import { ui } from '@code-pushup/utils';
6+
import { CLI_NAME } from '../constants';
7+
import { MergeDiffsOptions } from '../implementation/merge-diffs.model';
8+
import { yargsMergeDiffsOptionsDefinition } from '../implementation/merge-diffs.options';
9+
10+
export function yargsMergeDiffsCommandObject() {
11+
const command = 'merge-diffs';
12+
return {
13+
command,
14+
describe: 'Combine many report diffs into single report-diff.md',
15+
builder: yargsMergeDiffsOptionsDefinition(),
16+
handler: async (args: unknown) => {
17+
ui().logger.log(bold(CLI_NAME));
18+
ui().logger.info(gray(`Run ${command}...`));
19+
20+
const options = args as MergeDiffsOptions & {
21+
persist: Required<PersistConfig>;
22+
};
23+
const { files, persist } = options;
24+
25+
const outputPath = await mergeDiffs(files, persist);
26+
27+
ui().logger.info(`Reports diff written to ${bold(outputPath)}`);
28+
},
29+
} satisfies CommandModule;
30+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { bold } from 'ansis';
2+
import { mergeDiffs } from '@code-pushup/core';
3+
import {
4+
DEFAULT_PERSIST_FILENAME,
5+
DEFAULT_PERSIST_FORMAT,
6+
DEFAULT_PERSIST_OUTPUT_DIR,
7+
} from '@code-pushup/models';
8+
import { getLogMessages } from '@code-pushup/test-utils';
9+
import { ui } from '@code-pushup/utils';
10+
import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants';
11+
import { yargsCli } from '../yargs-cli';
12+
import { yargsMergeDiffsCommandObject } from './merge-diffs-command';
13+
14+
vi.mock('@code-pushup/core', async () => {
15+
const core: object = await vi.importActual('@code-pushup/core');
16+
const { CORE_CONFIG_MOCK }: typeof import('@code-pushup/test-utils') =
17+
await vi.importActual('@code-pushup/test-utils');
18+
return {
19+
...core,
20+
autoloadRc: vi.fn().mockResolvedValue(CORE_CONFIG_MOCK),
21+
mergeDiffs: vi.fn().mockResolvedValue('.code-pushup/report-diff.md'),
22+
};
23+
});
24+
25+
describe('merge-diffs-command', () => {
26+
it('should parse input paths from command line and output path from persist config', async () => {
27+
await yargsCli(
28+
[
29+
'merge-diffs',
30+
'--files',
31+
'frontoffice/report-diff.json',
32+
'backoffice/report-diff.json',
33+
'api/report-diff.json',
34+
],
35+
{
36+
...DEFAULT_CLI_CONFIGURATION,
37+
commands: [yargsMergeDiffsCommandObject()],
38+
},
39+
).parseAsync();
40+
41+
expect(mergeDiffs).toHaveBeenCalledWith<Parameters<typeof mergeDiffs>>(
42+
[
43+
'frontoffice/report-diff.json',
44+
'backoffice/report-diff.json',
45+
'api/report-diff.json',
46+
],
47+
{
48+
outputDir: DEFAULT_PERSIST_OUTPUT_DIR,
49+
filename: DEFAULT_PERSIST_FILENAME,
50+
format: DEFAULT_PERSIST_FORMAT,
51+
},
52+
);
53+
});
54+
55+
it('should log output path to stdout', async () => {
56+
await yargsCli(
57+
[
58+
'merge-diffs',
59+
'--files=frontoffice/report-diff.json',
60+
'--files=backoffice/report-diff.json',
61+
],
62+
{
63+
...DEFAULT_CLI_CONFIGURATION,
64+
commands: [yargsMergeDiffsCommandObject()],
65+
},
66+
).parseAsync();
67+
68+
expect(getLogMessages(ui().logger).at(-1)).toContain(
69+
`Reports diff written to ${bold('.code-pushup/report-diff.md')}`,
70+
);
71+
});
72+
});

packages/cli/src/lib/yargs-cli.integration.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
UploadConfigCliOptions,
99
} from './implementation/core-config.model';
1010
import { GeneralCliOptions } from './implementation/global.model';
11+
import { MergeDiffsOptions } from './implementation/merge-diffs.model';
12+
import { yargsMergeDiffsOptionsDefinition } from './implementation/merge-diffs.options';
1113
import { OnlyPluginsOptions } from './implementation/only-plugins.model';
1214
import { yargsOnlyPluginsOptionsDefinition } from './implementation/only-plugins.options';
1315
import { SkipPluginsOptions } from './implementation/skip-plugins.model';
@@ -175,6 +177,30 @@ describe('yargsCli', () => {
175177
).toThrow('Missing required arguments: before, after');
176178
});
177179

180+
it('should parse merge-diffs options', async () => {
181+
const parsedArgv = await yargsCli<GeneralCliOptions & MergeDiffsOptions>(
182+
[
183+
'--files',
184+
'.code-pushup/frontend/report-diff.json',
185+
'.code-pushup/backend/report-diff.json',
186+
],
187+
{ options: { ...options, ...yargsMergeDiffsOptionsDefinition() } },
188+
).parseAsync();
189+
expect(parsedArgv.files).toEqual([
190+
'.code-pushup/frontend/report-diff.json',
191+
'.code-pushup/backend/report-diff.json',
192+
]);
193+
});
194+
195+
it('should error if required merge-diffs option is missing', () => {
196+
expect(() =>
197+
yargsCli<GeneralCliOptions & CompareOptions>([], {
198+
options: { ...options, ...yargsMergeDiffsOptionsDefinition() },
199+
noExitProcess: true,
200+
}).parse(),
201+
).toThrow('Missing required argument: files');
202+
});
203+
178204
it('should provide default arguments for history command', async () => {
179205
const result = await yargsCli(['history'], {
180206
options: { ...options, ...yargsHistoryOptionsDefinition() },

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ export {
2323
} from './lib/implementation/read-rc-file';
2424
export { GlobalOptions } from './lib/types';
2525
export { UploadOptions, upload } from './lib/upload';
26+
export { mergeDiffs } from './lib/merge-diffs';

packages/core/src/lib/merge-diffs.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { PersistConfig, reportsDiffSchema } from '@code-pushup/models';
2+
import { readJsonFile } from '@code-pushup/utils';
3+
4+
export async function mergeDiffs(
5+
files: string[],
6+
persistConfig: Required<PersistConfig>,
7+
): Promise<string> {
8+
const diffs = await Promise.all(
9+
files.map(file => readJsonFile(file).then(reportsDiffSchema.parseAsync)),
10+
);
11+
// TODO: implement
12+
return '<path>';
13+
}

0 commit comments

Comments
 (0)