Skip to content

Commit 314e7ba

Browse files
committed
feat(cli): implement compare command
1 parent 10df94c commit 314e7ba

File tree

6 files changed

+116
-0
lines changed

6 files changed

+116
-0
lines changed

packages/cli/src/lib/commands.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { CommandModule } from 'yargs';
22
import { yargsAutorunCommandObject } from './autorun/autorun-command';
33
import { yargsCollectCommandObject } from './collect/collect-command';
4+
import { yargsCompareCommandObject } from './compare/compare-command';
45
import { yargsConfigCommandObject } from './print-config/print-config-command';
56
import { yargsUploadCommandObject } from './upload/upload-command';
67

@@ -12,5 +13,6 @@ export const commands: CommandModule[] = [
1213
yargsAutorunCommandObject(),
1314
yargsCollectCommandObject(),
1415
yargsUploadCommandObject(),
16+
yargsCompareCommandObject(),
1517
yargsConfigCommandObject(),
1618
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import chalk from 'chalk';
2+
import { join } from 'node:path';
3+
import { CommandModule } from 'yargs';
4+
import { compareReportFiles } from '@code-pushup/core';
5+
import { PersistConfig } from '@code-pushup/models';
6+
import { CLI_NAME } from '../constants';
7+
import type { CompareOptions } from '../implementation/compare.model';
8+
import { yargsCompareOptionsDefinition } from '../implementation/compare.options';
9+
import { ui } from '../implementation/logging';
10+
11+
export function yargsCompareCommandObject() {
12+
const command = 'compare';
13+
return {
14+
command,
15+
describe: 'Compare 2 report files and create a diff file',
16+
builder: yargsCompareOptionsDefinition(),
17+
handler: async (args: unknown) => {
18+
ui().logger.log(chalk.bold(CLI_NAME));
19+
ui().logger.info(chalk.gray(`Run ${command}...`));
20+
21+
const options = args as CompareOptions & {
22+
persist: Required<PersistConfig>;
23+
};
24+
25+
const { before, after, persist } = options;
26+
const outputPath = join(
27+
persist.outputDir,
28+
`${persist.filename}-diff.json`,
29+
);
30+
31+
await compareReportFiles({ before, after }, outputPath);
32+
33+
ui().logger.info(`Reports diff written to ${chalk.bold(outputPath)}`);
34+
},
35+
} satisfies CommandModule;
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { join } from 'node:path';
2+
import { compareReportFiles } from '@code-pushup/core';
3+
import { PERSIST_FILENAME, PERSIST_OUTPUT_DIR } from '@code-pushup/models';
4+
import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants';
5+
import { yargsCli } from '../yargs-cli';
6+
import { yargsCompareCommandObject } from './compare-command';
7+
8+
vi.mock('@code-pushup/core', async () => {
9+
const core: object = await vi.importActual('@code-pushup/core');
10+
const { CORE_CONFIG_MOCK }: typeof import('@code-pushup/test-utils') =
11+
await vi.importActual('@code-pushup/test-utils');
12+
return {
13+
...core,
14+
autoloadRc: vi.fn().mockResolvedValue(CORE_CONFIG_MOCK),
15+
compareReportFiles: vi.fn(),
16+
};
17+
});
18+
19+
describe('compare-command', () => {
20+
it('should parse input paths from command line and output path from persist config', async () => {
21+
await yargsCli(
22+
['compare', '--before=source-report.json', '--after=target-report.json'],
23+
{ ...DEFAULT_CLI_CONFIGURATION, commands: [yargsCompareCommandObject()] },
24+
).parseAsync();
25+
26+
expect(compareReportFiles).toHaveBeenCalledWith<
27+
Parameters<typeof compareReportFiles>
28+
>(
29+
{ before: 'source-report.json', after: 'target-report.json' },
30+
join(PERSIST_OUTPUT_DIR, `${PERSIST_FILENAME}-diff.json`),
31+
);
32+
});
33+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Diff } from '@code-pushup/utils';
2+
3+
export type CompareOptions = Diff<string>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Options } from 'yargs';
2+
import type { CompareOptions } from './compare.model';
3+
4+
export function yargsCompareOptionsDefinition(): Record<
5+
keyof CompareOptions,
6+
Options
7+
> {
8+
return {
9+
before: {
10+
describe: 'Path to source report.json',
11+
type: 'string',
12+
demandOption: true,
13+
},
14+
after: {
15+
describe: 'Path to target report.json',
16+
type: 'string',
17+
demandOption: true,
18+
},
19+
};
20+
}

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

+22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { describe, expect, it } from 'vitest';
22
import { CoreConfig, Format } from '@code-pushup/models';
3+
import { CompareOptions } from './implementation/compare.model';
4+
import { yargsCompareOptionsDefinition } from './implementation/compare.options';
35
import {
46
PersistConfigCliOptions,
57
UploadConfigCliOptions,
@@ -118,4 +120,24 @@ describe('yargsCli', () => {
118120
}),
119121
);
120122
});
123+
124+
it('should parse compare options', async () => {
125+
const parsedArgv = await yargsCli<GeneralCliOptions & CompareOptions>(
126+
['--before=source-report.json', '--after', 'target-report.json'],
127+
{
128+
options: { ...options, ...yargsCompareOptionsDefinition() },
129+
},
130+
).parseAsync();
131+
expect(parsedArgv.before).toBe('source-report.json');
132+
expect(parsedArgv.after).toBe('target-report.json');
133+
});
134+
135+
it('should error if required compare option is missing', () => {
136+
expect(() =>
137+
yargsCli<GeneralCliOptions & CompareOptions>([], {
138+
options: { ...options, ...yargsCompareOptionsDefinition() },
139+
noExitProcess: true,
140+
}).parse(),
141+
).toThrow('Missing required arguments: before, after');
142+
});
121143
});

0 commit comments

Comments
 (0)