Skip to content

Commit e26304a

Browse files
committed
fix: nest files with timestamp for plugin runners
1 parent 29cf02a commit e26304a

File tree

24 files changed

+216
-109
lines changed

24 files changed

+216
-109
lines changed

packages/core/src/lib/implementation/runner.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import type {
44
RunnerConfig,
55
RunnerFunction,
66
} from '@code-pushup/models';
7-
import { calcDuration, executeProcess, readJsonFile } from '@code-pushup/utils';
7+
import {
8+
calcDuration,
9+
executeProcess,
10+
readJsonFile,
11+
removeDirectoryIfExists,
12+
} from '@code-pushup/utils';
813

914
export type RunnerResult = {
1015
date: string;
@@ -26,7 +31,9 @@ export async function executeRunnerConfig(
2631
});
2732

2833
// read process output from file system and parse it
29-
const outputs = await readJsonFile(path.join(process.cwd(), outputFile));
34+
const outputs = await readJsonFile(outputFile);
35+
// clean up plugin individual runner output directory
36+
await removeDirectoryIfExists(path.dirname(outputFile));
3037

3138
// transform unknownAuditOutputs to auditOutputs
3239
const audits = outputTransform ? await outputTransform(outputs) : outputs;

packages/models/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,11 @@ export {
9999
onProgressSchema,
100100
runnerConfigSchema,
101101
runnerFunctionSchema,
102+
runnerFilesPathsSchema,
102103
type OnProgress,
103104
type RunnerConfig,
104105
type RunnerFunction,
106+
type RunnerFilesPaths,
105107
} from './lib/runner-config.js';
106108
export {
107109
tableAlignmentSchema,

packages/models/src/lib/runner-config.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ export const runnerConfigSchema = z.object(
1515
description: 'Shell command to execute',
1616
}),
1717
args: z.array(z.string({ description: 'Command arguments' })).optional(),
18-
outputFile: filePathSchema.describe('Output path'),
18+
outputFile: filePathSchema.describe('Runner output path'),
1919
outputTransform: outputTransformSchema.optional(),
20+
configFile: filePathSchema.describe('Runner config path').optional(),
2021
},
2122
{
2223
description: 'How to execute runner',
@@ -37,3 +38,10 @@ export const runnerFunctionSchema = z
3738
.returns(z.union([auditOutputsSchema, z.promise(auditOutputsSchema)]));
3839

3940
export type RunnerFunction = z.infer<typeof runnerFunctionSchema>;
41+
42+
export const runnerFilesPathsSchema = z.object({
43+
runnerConfigPath: filePathSchema.describe('Runner config path'),
44+
runnerOutputPath: filePathSchema.describe('Runner output path'),
45+
});
46+
47+
export type RunnerFilesPaths = z.infer<typeof runnerFilesPathsSchema>;

packages/nx-plugin/src/executors/cli/executor.unit.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { logger } from '@nx/devkit';
22
import { execSync } from 'node:child_process';
33
import { afterEach, beforeEach, expect, vi } from 'vitest';
44
import { executorContext } from '@code-pushup/test-nx-utils';
5+
import { MEMFS_VOLUME } from '@code-pushup/test-utils';
56
import runAutorunExecutor from './executor.js';
67

78
vi.mock('node:child_process', async () => {
@@ -39,7 +40,7 @@ describe('runAutorunExecutor', () => {
3940
// eslint-disable-next-line n/no-sync
4041
expect(execSync).toHaveBeenCalledWith(
4142
expect.stringContaining('npx @code-pushup/cli'),
42-
{ cwd: '/test' },
43+
{ cwd: MEMFS_VOLUME },
4344
);
4445
});
4546

packages/plugin-coverage/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@code-pushup/utils": "0.57.0",
3939
"ansis": "^3.3.0",
4040
"parse-lcov": "^1.0.4",
41+
"yargs": "^17.7.2",
4142
"zod": "^3.22.4"
4243
},
4344
"peerDependencies": {
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import process from 'node:process';
2+
import { Parser } from 'yargs/helpers';
13
import { executeRunner } from './lib/runner/index.js';
24

3-
await executeRunner();
5+
const { runnerConfigPath, runnerOutputPath } = Parser(process.argv);
6+
7+
await executeRunner({ runnerConfigPath, runnerOutputPath });
Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1 @@
1-
import path from 'node:path';
2-
import { pluginWorkDir } from '@code-pushup/utils';
3-
4-
export const WORKDIR = pluginWorkDir('coverage');
5-
export const RUNNER_OUTPUT_PATH = path.join(WORKDIR, 'runner-output.json');
6-
export const PLUGIN_CONFIG_PATH = path.join(
7-
process.cwd(),
8-
WORKDIR,
9-
'plugin-config.json',
10-
);
11-
121
export const INVALID_FUNCTION_NAME = '(empty-report)';

packages/plugin-coverage/src/lib/runner/index.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
11
import { bold } from 'ansis';
22
import { writeFile } from 'node:fs/promises';
33
import path from 'node:path';
4-
import type { AuditOutputs, RunnerConfig } from '@code-pushup/models';
4+
import type {
5+
AuditOutputs,
6+
RunnerConfig,
7+
RunnerFilesPaths,
8+
} from '@code-pushup/models';
59
import {
610
ProcessError,
11+
createRunnerFiles,
712
ensureDirectoryExists,
813
executeProcess,
914
filePathToCliArg,
15+
objectToCliArgs,
1016
readJsonFile,
1117
ui,
1218
} from '@code-pushup/utils';
1319
import type { FinalCoveragePluginConfig } from '../config.js';
1420
import { applyMaxScoreAboveThreshold } from '../utils.js';
15-
import { PLUGIN_CONFIG_PATH, RUNNER_OUTPUT_PATH } from './constants.js';
1621
import { lcovResultsToAuditOutputs } from './lcov/lcov-runner.js';
1722

18-
export async function executeRunner(): Promise<void> {
23+
export async function executeRunner({
24+
runnerConfigPath,
25+
runnerOutputPath,
26+
}: RunnerFilesPaths): Promise<void> {
1927
const { reports, coverageToolCommand, coverageTypes } =
20-
await readJsonFile<FinalCoveragePluginConfig>(PLUGIN_CONFIG_PATH);
28+
await readJsonFile<FinalCoveragePluginConfig>(runnerConfigPath);
2129

2230
// Run coverage tool if provided
2331
if (coverageToolCommand != null) {
@@ -41,24 +49,30 @@ export async function executeRunner(): Promise<void> {
4149
// Calculate coverage from LCOV results
4250
const auditOutputs = await lcovResultsToAuditOutputs(reports, coverageTypes);
4351

44-
await ensureDirectoryExists(path.dirname(RUNNER_OUTPUT_PATH));
45-
await writeFile(RUNNER_OUTPUT_PATH, JSON.stringify(auditOutputs));
52+
await ensureDirectoryExists(path.dirname(runnerOutputPath));
53+
await writeFile(runnerOutputPath, JSON.stringify(auditOutputs));
4654
}
4755

4856
export async function createRunnerConfig(
4957
scriptPath: string,
5058
config: FinalCoveragePluginConfig,
5159
): Promise<RunnerConfig> {
5260
// Create JSON config for executeRunner
53-
await ensureDirectoryExists(path.dirname(PLUGIN_CONFIG_PATH));
54-
await writeFile(PLUGIN_CONFIG_PATH, JSON.stringify(config));
61+
const { runnerConfigPath, runnerOutputPath } = await createRunnerFiles(
62+
'coverage',
63+
JSON.stringify(config),
64+
);
5565

5666
const threshold = config.perfectScoreThreshold;
5767

5868
return {
5969
command: 'node',
60-
args: [filePathToCliArg(scriptPath)],
61-
outputFile: RUNNER_OUTPUT_PATH,
70+
args: [
71+
filePathToCliArg(scriptPath),
72+
...objectToCliArgs({ runnerConfigPath, runnerOutputPath }),
73+
],
74+
configFile: runnerConfigPath,
75+
outputFile: runnerOutputPath,
6276
...(threshold != null && {
6377
outputTransform: outputs =>
6478
applyMaxScoreAboveThreshold(outputs as AuditOutputs, threshold),

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

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
1-
import { writeFile } from 'node:fs/promises';
21
import path from 'node:path';
32
import { fileURLToPath } from 'node:url';
4-
import { describe, it } from 'vitest';
3+
import { expect } from 'vitest';
54
import type {
65
AuditOutput,
76
AuditOutputs,
87
RunnerConfig,
98
} from '@code-pushup/models';
10-
import { readJsonFile, removeDirectoryIfExists } from '@code-pushup/utils';
9+
import { createRunnerFiles, readJsonFile } from '@code-pushup/utils';
1110
import type { FinalCoveragePluginConfig } from '../config.js';
12-
import {
13-
PLUGIN_CONFIG_PATH,
14-
RUNNER_OUTPUT_PATH,
15-
WORKDIR,
16-
} from './constants.js';
1711
import { createRunnerConfig, executeRunner } from './index.js';
1812

1913
describe('createRunnerConfig', () => {
@@ -25,26 +19,32 @@ describe('createRunnerConfig', () => {
2519
});
2620
expect(runnerConfig).toStrictEqual<RunnerConfig>({
2721
command: 'node',
28-
args: ['"executeRunner.ts"'],
22+
args: [
23+
'"executeRunner.ts"',
24+
expect.stringContaining('plugin-config.json'),
25+
expect.stringContaining('runner-output.json'),
26+
],
2927
outputTransform: expect.any(Function),
3028
outputFile: expect.stringContaining('runner-output.json'),
29+
configFile: expect.stringContaining('plugin-config.json'),
3130
});
3231
});
3332

3433
it('should provide plugin config to runner in JSON file', async () => {
35-
await removeDirectoryIfExists(WORKDIR);
36-
3734
const pluginConfig: FinalCoveragePluginConfig = {
3835
coverageTypes: ['line'],
3936
reports: ['coverage/lcov.info'],
4037
coverageToolCommand: { command: 'npm', args: ['run', 'test'] },
4138
perfectScoreThreshold: 85,
4239
};
4340

44-
await createRunnerConfig('executeRunner.ts', pluginConfig);
41+
const { configFile } = await createRunnerConfig(
42+
'executeRunner.ts',
43+
pluginConfig,
44+
);
4545

46-
const config =
47-
await readJsonFile<FinalCoveragePluginConfig>(PLUGIN_CONFIG_PATH);
46+
expect(configFile).toMatch(/.*plugin-config\.json$/);
47+
const config = await readJsonFile<FinalCoveragePluginConfig>(configFile!);
4848
expect(config).toStrictEqual(pluginConfig);
4949
});
5050
});
@@ -65,10 +65,15 @@ describe('executeRunner', () => {
6565
coverageTypes: ['line'],
6666
};
6767

68-
await writeFile(PLUGIN_CONFIG_PATH, JSON.stringify(config));
69-
await executeRunner();
68+
const runnerFiles = await createRunnerFiles(
69+
'coverage',
70+
JSON.stringify(config),
71+
);
72+
await executeRunner(runnerFiles);
7073

71-
const results = await readJsonFile<AuditOutputs>(RUNNER_OUTPUT_PATH);
74+
const results = await readJsonFile<AuditOutputs>(
75+
runnerFiles.runnerOutputPath,
76+
);
7277
expect(results).toStrictEqual([
7378
expect.objectContaining({
7479
slug: 'line-coverage',

packages/plugin-eslint/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"dependencies": {
4141
"@code-pushup/utils": "0.57.0",
4242
"@code-pushup/models": "0.57.0",
43+
"yargs": "^17.7.2",
4344
"zod": "^3.22.4"
4445
},
4546
"peerDependencies": {

0 commit comments

Comments
 (0)