Skip to content

Commit 5eeaf54

Browse files
committed
feat(ci): improve code-pushup command logs
1 parent 4b9a2d3 commit 5eeaf54

File tree

12 files changed

+451
-64
lines changed

12 files changed

+451
-64
lines changed

packages/ci/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ Optionally, you can override default options for further customization:
103103
| `nxProjectsFilter` | `string \| string[]` | `'--with-target={task}'` | Arguments passed to [`nx show projects`](https://nx.dev/nx-api/nx/documents/show#projects), only relevant for Nx in [monorepo mode](#monorepo-mode) [^2] |
104104
| `directory` | `string` | `process.cwd()` | Directory in which Code PushUp CLI should run |
105105
| `config` | `string \| null` | `null` [^1] | Path to config file (`--config` option) |
106+
| `silent` | `boolean` | `false` | Hides logs from CLI commands (errors will be printed) |
106107
| `bin` | `string` | `'npx --no-install code-pushup'` | Command for executing Code PushUp CLI |
107108
| `detectNewIssues` | `boolean` | `true` | Toggles if new issues should be detected and returned in `newIssues` property |
108109
| `skipComment` | `boolean` | `false` | Toggles if comparison comment is posted to PR |
Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
1-
import { DEFAULT_PERSIST_FORMAT } from '@code-pushup/models';
2-
import { executeProcess } from '@code-pushup/utils';
31
import type { CommandContext } from '../context.js';
2+
import { executeCliCommand } from '../exec.js';
43

54
export async function runCollect(
6-
{ bin, config, directory }: CommandContext,
7-
{ hasFormats }: { hasFormats: boolean },
5+
context: CommandContext,
6+
options: { hasFormats: boolean },
87
): Promise<void> {
9-
await executeProcess({
10-
command: bin,
11-
args: [
12-
...(config ? [`--config=${config}`] : []),
13-
...(hasFormats
14-
? []
15-
: DEFAULT_PERSIST_FORMAT.map(format => `--persist.format=${format}`)),
16-
],
17-
cwd: directory,
18-
});
8+
await executeCliCommand([], context, options);
199
}
Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,9 @@
1-
import { DEFAULT_PERSIST_FORMAT } from '@code-pushup/models';
2-
import { executeProcess } from '@code-pushup/utils';
31
import type { CommandContext } from '../context.js';
2+
import { executeCliCommand } from '../exec.js';
43

54
export async function runCompare(
6-
{ bin, config, directory }: CommandContext,
7-
{ hasFormats }: { hasFormats: boolean },
5+
context: CommandContext,
6+
options: { hasFormats: boolean },
87
): Promise<void> {
9-
await executeProcess({
10-
command: bin,
11-
args: [
12-
'compare',
13-
...(config ? [`--config=${config}`] : []),
14-
...(hasFormats
15-
? []
16-
: DEFAULT_PERSIST_FORMAT.map(format => `--persist.format=${format}`)),
17-
],
18-
cwd: directory,
19-
});
8+
await executeCliCommand(['compare'], context, options);
209
}

packages/ci/src/lib/cli/commands/merge-diffs.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,25 @@ import {
33
DEFAULT_PERSIST_FILENAME,
44
DEFAULT_PERSIST_OUTPUT_DIR,
55
} from '@code-pushup/models';
6-
import { executeProcess } from '@code-pushup/utils';
76
import type { CommandContext } from '../context.js';
7+
import { executeCliCommand } from '../exec.js';
88

99
export async function runMergeDiffs(
1010
files: string[],
11-
{ bin, config, directory }: CommandContext,
11+
context: CommandContext,
1212
): Promise<string> {
13-
const outputDir = path.join(directory, DEFAULT_PERSIST_OUTPUT_DIR);
13+
const outputDir = path.join(context.directory, DEFAULT_PERSIST_OUTPUT_DIR);
1414
const filename = `merged-${DEFAULT_PERSIST_FILENAME}`;
1515

16-
await executeProcess({
17-
command: bin,
18-
args: [
16+
await executeCliCommand(
17+
[
1918
'merge-diffs',
2019
...files.map(file => `--files=${file}`),
21-
...(config ? [`--config=${config}`] : []),
2220
`--persist.outputDir=${outputDir}`,
2321
`--persist.filename=${filename}`,
2422
],
25-
cwd: directory,
26-
});
23+
context,
24+
);
2725

2826
return path.join(outputDir, `${filename}-diff.md`);
2927
}

packages/ci/src/lib/cli/commands/print-config.ts

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,24 @@
11
import { rm } from 'node:fs/promises';
22
import path from 'node:path';
3-
import {
4-
executeProcess,
5-
readJsonFile,
6-
stringifyError,
7-
} from '@code-pushup/utils';
3+
import { readJsonFile, stringifyError } from '@code-pushup/utils';
84
import type { CommandContext } from '../context.js';
5+
import { executeCliCommand } from '../exec.js';
96

10-
export async function runPrintConfig({
11-
bin,
12-
config,
13-
directory,
14-
project,
15-
}: CommandContext): Promise<unknown> {
7+
export async function runPrintConfig(
8+
context: CommandContext,
9+
): Promise<unknown> {
1610
// unique file name per project so command can be run in parallel
17-
const outputFile = ['code-pushup', 'config', project, 'json']
11+
const outputFile = ['code-pushup', 'config', context.project, 'json']
1812
.filter(Boolean)
1913
.join('.');
2014
const outputPath =
21-
project && directory === process.cwd()
15+
context.project && context.directory === process.cwd()
2216
? // cache-friendly path for Nx projects (assuming {workspaceRoot}/.code-pushup/{projectName})
23-
path.join(process.cwd(), '.code-pushup', project, outputFile)
17+
path.join(process.cwd(), '.code-pushup', context.project, outputFile)
2418
: // absolute path
25-
path.resolve(directory, '.code-pushup', outputFile);
19+
path.resolve(context.directory, '.code-pushup', outputFile);
2620

27-
await executeProcess({
28-
command: bin,
29-
args: [
30-
...(config ? [`--config=${config}`] : []),
31-
'print-config',
32-
`--output=${outputPath}`,
33-
],
34-
cwd: directory,
35-
});
21+
await executeCliCommand(['print-config', `--output=${outputPath}`], context);
3622

3723
try {
3824
const content = await readJsonFile(outputPath);

packages/ci/src/lib/cli/context.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import type { Settings } from '../models.js';
22
import type { ProjectConfig } from '../monorepo/index.js';
33

4-
export type CommandContext = Pick<Settings, 'bin' | 'config' | 'directory'> & {
4+
export type CommandContext = Pick<
5+
Settings,
6+
'bin' | 'config' | 'directory' | 'silent'
7+
> & {
58
project?: string;
69
};
710

811
export function createCommandContext(
9-
{ config, bin, directory }: Settings,
12+
{ config, bin, directory, silent }: Settings,
1013
project: ProjectConfig | null | undefined,
1114
): CommandContext {
1215
return {
1316
bin: project?.bin ?? bin,
1417
directory: project?.directory ?? directory,
18+
silent,
1519
config,
1620
...(project?.name && { project: project.name }),
1721
};

packages/ci/src/lib/cli/context.unit.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ describe('createCommandContext', () => {
1010
config: null,
1111
detectNewIssues: true,
1212
directory: '/test',
13+
silent: false,
1314
monorepo: false,
1415
parallel: false,
1516
nxProjectsFilter: '--with-target={task}',
@@ -24,6 +25,7 @@ describe('createCommandContext', () => {
2425
).toStrictEqual<CommandContext>({
2526
bin: 'npx --no-install code-pushup',
2627
directory: '/test',
28+
silent: false,
2729
config: null,
2830
});
2931
});
@@ -36,6 +38,7 @@ describe('createCommandContext', () => {
3638
config: null,
3739
detectNewIssues: true,
3840
directory: '/test',
41+
silent: false,
3942
monorepo: false,
4043
parallel: false,
4144
nxProjectsFilter: '--with-target={task}',
@@ -54,6 +57,7 @@ describe('createCommandContext', () => {
5457
).toStrictEqual<CommandContext>({
5558
bin: 'yarn code-pushup',
5659
directory: '/test/ui',
60+
silent: false,
5761
config: null,
5862
project: 'ui',
5963
});

packages/ci/src/lib/cli/exec.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { DEFAULT_PERSIST_FORMAT } from '@code-pushup/models';
2+
import {
3+
type ProcessConfig,
4+
type ProcessObserver,
5+
executeProcess,
6+
logger,
7+
serializeCommandWithArgs,
8+
} from '@code-pushup/utils';
9+
import type { CommandContext } from './context.js';
10+
11+
export async function executeCliCommand(
12+
args: string[],
13+
context: CommandContext,
14+
options?: { hasFormats: boolean },
15+
): Promise<void> {
16+
// eslint-disable-next-line functional/no-let
17+
let output = '';
18+
19+
const logRaw = (message: string) => {
20+
if (!context.silent) {
21+
if (!output) {
22+
logger.newline();
23+
}
24+
logger.info(message, { noIndent: true, noLineBreak: true });
25+
}
26+
output += message;
27+
};
28+
29+
const logEnd = () => {
30+
if (!context.silent && output) {
31+
logger.newline();
32+
}
33+
};
34+
35+
const observer: ProcessObserver = {
36+
onStdout: logRaw,
37+
onStderr: logRaw,
38+
onComplete: logEnd,
39+
onError: logEnd,
40+
};
41+
42+
const config: ProcessConfig = {
43+
command: context.bin,
44+
args: combineArgs(args, context, options),
45+
cwd: context.directory,
46+
observer,
47+
silent: true,
48+
};
49+
const bin = serializeCommandWithArgs(config);
50+
51+
await logger.command(bin, async () => {
52+
try {
53+
await executeProcess(config);
54+
} catch (error) {
55+
// ensure output of failed process is always logged for debugging
56+
if (context.silent) {
57+
logger.newline();
58+
logger.info(output, { noIndent: true });
59+
if (!output.endsWith('\n')) {
60+
logger.newline();
61+
}
62+
}
63+
throw error;
64+
}
65+
});
66+
}
67+
68+
function combineArgs(
69+
args: string[],
70+
context: CommandContext,
71+
options: { hasFormats?: boolean } | undefined,
72+
): string[] {
73+
return [
74+
...(context.config ? [`--config=${context.config}`] : []),
75+
...args,
76+
...(options?.hasFormats === false
77+
? DEFAULT_PERSIST_FORMAT.map(format => `--persist.format=${format}`)
78+
: []),
79+
];
80+
}

0 commit comments

Comments
 (0)