Skip to content

Commit aa4d0b3

Browse files
committed
feat(ci): use temporary file for print-config instead of stdout
1 parent a1fde20 commit aa4d0b3

File tree

7 files changed

+71
-41
lines changed

7 files changed

+71
-41
lines changed

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

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { executeProcess, stringifyError } from '@code-pushup/utils';
1+
import { rm } from 'node:fs/promises';
2+
import path from 'node:path';
3+
import {
4+
executeProcess,
5+
generateRandomId,
6+
readJsonFile,
7+
stringifyError,
8+
} from '@code-pushup/utils';
29
import type { CommandContext } from '../context.js';
310

411
export async function runPrintConfig({
@@ -7,27 +14,28 @@ export async function runPrintConfig({
714
directory,
815
silent,
916
}: CommandContext): Promise<unknown> {
17+
// random file name so command can be run in parallel
18+
const outputFile = `code-pushup.${generateRandomId()}.config.json`;
19+
const outputPath = path.join(directory, outputFile);
20+
1021
const { stdout } = await executeProcess({
1122
command: bin,
12-
args: [...(config ? [`--config=${config}`] : []), 'print-config'],
23+
args: [
24+
...(config ? [`--config=${config}`] : []),
25+
'print-config',
26+
`--output=${outputFile}`,
27+
],
1328
cwd: directory,
1429
});
1530
if (!silent) {
1631
console.info(stdout);
1732
}
1833

19-
// workaround for 1st lines like `> nx run utils:code-pushup -- print-config`
20-
const lines = stdout.split(/\r?\n/);
21-
const jsonLines = lines.slice(lines.indexOf('{'), lines.indexOf('}') + 1);
22-
const stdoutSanitized = jsonLines.join('\n');
23-
2434
try {
25-
return JSON.parse(stdoutSanitized) as unknown;
35+
const content = await readJsonFile(outputPath);
36+
await rm(outputPath);
37+
return content;
2638
} catch (error) {
27-
if (silent) {
28-
console.info('Invalid output from print-config:');
29-
console.info(stdout);
30-
}
3139
throw new Error(
3240
`Error parsing output of print-config command - ${stringifyError(error)}`,
3341
);

packages/ci/src/lib/run-monorepo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ async function runProjectsInBulk(
128128
const currProjectReports = await Promise.all(
129129
projects.map(async (project): Promise<ProjectReport> => {
130130
const ctx = createCommandContext(settings, project);
131-
const config = await printPersistConfig(ctx, settings);
131+
const config = await printPersistConfig(ctx);
132132
const reports = persistedFilesFromConfig(config, ctx);
133133
return { project, reports, config, ctx };
134134
}),

packages/ci/src/lib/run-utils.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export async function runOnProject(
6969
logger.info(`Running Code PushUp on monorepo project ${project.name}`);
7070
}
7171

72-
const config = await printPersistConfig(ctx, settings);
72+
const config = await printPersistConfig(ctx);
7373
logger.debug(
7474
`Loaded persist config from print-config command - ${JSON.stringify(config.persist)}`,
7575
);
@@ -267,7 +267,7 @@ export async function checkPrintConfig(
267267
? `Executing print-config for project ${project.name}`
268268
: 'Executing print-config';
269269
try {
270-
const config = await printPersistConfig(ctx, settings);
270+
const config = await printPersistConfig(ctx);
271271
logger.debug(
272272
`${operation} verified code-pushup installed in base branch ${base.ref}`,
273273
);
@@ -283,9 +283,8 @@ export async function checkPrintConfig(
283283

284284
export async function printPersistConfig(
285285
ctx: CommandContext,
286-
settings: Settings,
287286
): Promise<Pick<CoreConfig, 'persist'>> {
288-
const json = await runPrintConfig({ ...ctx, silent: !settings.debug });
287+
const json = await runPrintConfig(ctx);
289288
return parsePersistConfig(json);
290289
}
291290

packages/ci/src/lib/run.integration.test.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,21 @@ describe('runInCI', () => {
115115
break;
116116

117117
case 'print-config':
118-
stdout = await readFile(fixturePaths.config, 'utf8');
118+
let content = await readFile(fixturePaths.config, 'utf8');
119119
if (nxMatch) {
120120
// simulate effect of custom persist.outputDir per Nx project
121-
const config = JSON.parse(stdout) as CoreConfig;
121+
const config = JSON.parse(content) as CoreConfig;
122122
// eslint-disable-next-line functional/immutable-data
123123
config.persist!.outputDir = outputDir;
124-
stdout = JSON.stringify(config, null, 2);
124+
content = JSON.stringify(config, null, 2);
125+
}
126+
const outputFile = args
127+
?.find(arg => arg.startsWith('--output='))
128+
?.split('=')[1];
129+
if (outputFile) {
130+
await writeFile(path.join(cwd as string, outputFile), content);
131+
} else {
132+
stdout = content;
125133
}
126134
break;
127135

@@ -235,7 +243,7 @@ describe('runInCI', () => {
235243
expect(utils.executeProcess).toHaveBeenCalledTimes(2);
236244
expect(utils.executeProcess).toHaveBeenNthCalledWith(1, {
237245
command: options.bin,
238-
args: ['print-config'],
246+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
239247
cwd: workDir,
240248
} satisfies utils.ProcessConfig);
241249
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
@@ -307,7 +315,7 @@ describe('runInCI', () => {
307315
expect(utils.executeProcess).toHaveBeenCalledTimes(5);
308316
expect(utils.executeProcess).toHaveBeenNthCalledWith(1, {
309317
command: options.bin,
310-
args: ['print-config'],
318+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
311319
cwd: workDir,
312320
} satisfies utils.ProcessConfig);
313321
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
@@ -317,7 +325,7 @@ describe('runInCI', () => {
317325
} satisfies utils.ProcessConfig);
318326
expect(utils.executeProcess).toHaveBeenNthCalledWith(3, {
319327
command: options.bin,
320-
args: ['print-config'],
328+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
321329
cwd: workDir,
322330
} satisfies utils.ProcessConfig);
323331
expect(utils.executeProcess).toHaveBeenNthCalledWith(4, {
@@ -383,7 +391,7 @@ describe('runInCI', () => {
383391
expect(utils.executeProcess).toHaveBeenCalledTimes(3);
384392
expect(utils.executeProcess).toHaveBeenNthCalledWith(1, {
385393
command: options.bin,
386-
args: ['print-config'],
394+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
387395
cwd: workDir,
388396
} satisfies utils.ProcessConfig);
389397
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
@@ -577,7 +585,7 @@ describe('runInCI', () => {
577585
).toHaveLength(4); // 1 autorun for all projects, 3 print-configs for each project
578586
expect(utils.executeProcess).toHaveBeenCalledWith({
579587
command: run,
580-
args: ['print-config'],
588+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
581589
cwd: expect.stringContaining(workDir),
582590
} satisfies utils.ProcessConfig);
583591
expect(utils.executeProcess).toHaveBeenCalledWith({
@@ -746,7 +754,7 @@ describe('runInCI', () => {
746754
).toHaveLength(10);
747755
expect(utils.executeProcess).toHaveBeenCalledWith({
748756
command: run,
749-
args: ['print-config'],
757+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
750758
cwd: expect.stringContaining(workDir),
751759
} satisfies utils.ProcessConfig);
752760
expect(utils.executeProcess).toHaveBeenCalledWith({
@@ -922,7 +930,7 @@ describe('runInCI', () => {
922930
).toHaveLength(6); // 3 autoruns and 3 print-configs for each project
923931
expect(utils.executeProcess).toHaveBeenCalledWith({
924932
command: options.bin,
925-
args: ['print-config'],
933+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
926934
cwd: expect.stringContaining(workDir),
927935
} satisfies utils.ProcessConfig);
928936
expect(utils.executeProcess).toHaveBeenCalledWith({
@@ -1077,7 +1085,7 @@ describe('runInCI', () => {
10771085
).toHaveLength(10);
10781086
expect(utils.executeProcess).toHaveBeenCalledWith({
10791087
command: options.bin,
1080-
args: ['print-config'],
1088+
args: ['print-config', expect.stringMatching(/^--output=.*\.json$/)],
10811089
cwd: expect.stringContaining(workDir),
10821090
} satisfies utils.ProcessConfig);
10831091
expect(utils.executeProcess).toHaveBeenCalledWith({

packages/utils/src/index.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
export { exists } from '@code-pushup/models';
2+
export {
3+
camelCaseToKebabCase,
4+
capitalize,
5+
kebabCaseToCamelCase,
6+
toSentenceCase,
7+
toTitleCase,
8+
} from './lib/case-conversions.js';
9+
export { createRunnerFiles } from './lib/create-runner-files.js';
210
export { comparePairs, matchArrayItemsByKey, type Diff } from './lib/diff.js';
311
export { stringifyError } from './lib/errors.js';
412
export {
5-
ProcessError,
613
executeProcess,
14+
ProcessError,
715
type ProcessConfig,
816
type ProcessObserver,
917
type ProcessResult,
@@ -41,8 +49,8 @@ export {
4149
} from './lib/formatting.js';
4250
export {
4351
getCurrentBranchOrTag,
44-
getHashFromTag,
4552
getHashes,
53+
getHashFromTag,
4654
getLatestCommit,
4755
getSemverTags,
4856
type LogResult,
@@ -56,14 +64,15 @@ export {
5664
} from './lib/git/git.js';
5765
export { groupByStatus } from './lib/group-by-status.js';
5866
export {
67+
hasNoNullableProps,
5968
isPromiseFulfilledResult,
6069
isPromiseRejectedResult,
61-
hasNoNullableProps,
6270
} from './lib/guards.js';
6371
export { logMultipleResults } from './lib/log-results.js';
64-
export { link, ui, type CliUi, type Column, isVerbose } from './lib/logging.js';
72+
export { isVerbose, link, ui, type CliUi, type Column } from './lib/logging.js';
6573
export { mergeConfigs } from './lib/merge-configs.js';
6674
export { getProgressBar, type ProgressBar } from './lib/progress.js';
75+
export { generateRandomId } from './lib/random.js';
6776
export {
6877
CODE_PUSHUP_DOMAIN,
6978
CODE_PUSHUP_UNICODE_LOGO,
@@ -95,13 +104,6 @@ export {
95104
formatReportScore,
96105
} from './lib/reports/utils.js';
97106
export { isSemver, normalizeSemver, sortSemvers } from './lib/semver.js';
98-
export {
99-
camelCaseToKebabCase,
100-
kebabCaseToCamelCase,
101-
capitalize,
102-
toSentenceCase,
103-
toTitleCase,
104-
} from './lib/case-conversions.js';
105107
export * from './lib/text-formats/index.js';
106108
export {
107109
countOccurrences,
@@ -121,13 +123,12 @@ export {
121123
type CliArgsObject,
122124
} from './lib/transform.js';
123125
export type {
126+
CamelCaseToKebabCase,
124127
ExcludeNullableProps,
125128
ExtractArray,
126129
ExtractArrays,
127130
ItemOrArray,
128131
Prettify,
129132
WithRequired,
130-
CamelCaseToKebabCase,
131133
} from './lib/types.js';
132134
export { parseSchema, SchemaValidationError } from './lib/zod-validation.js';
133-
export { createRunnerFiles } from './lib/create-runner-files.js';

packages/utils/src/lib/random.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function generateRandomId(): string {
2+
return Math.random().toString().slice(2);
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { generateRandomId } from './random.js';
2+
3+
describe('generateRandomId', () => {
4+
it('should generate different IDs', () => {
5+
expect(generateRandomId()).not.toEqual(generateRandomId());
6+
});
7+
8+
it('should generate integer string', () => {
9+
expect(generateRandomId()).toMatch(/^\d+$/);
10+
});
11+
});

0 commit comments

Comments
 (0)