Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions e2e/nx-plugin-e2e/tests/executor-cli.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ describe('executor command', () => {
`${project}:code-pushup`,
'collect',
'--persist.filename=terminal-report',
'--verbose',
],
cwd,
});
Expand Down
9 changes: 5 additions & 4 deletions e2e/nx-plugin-e2e/tests/plugin-create-nodes.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,14 @@ describe('nx-plugin', () => {
});

const cleanStdout = removeColorCodes(stdout);

// Nx command
expect(cleanStdout).toContain('nx run my-lib:code-pushup');
expect(cleanStdout).toContain('nx run my-lib:code-pushup --dryRun');
// Run CLI executor
expect(cleanStdout).toContain('Command:');
expect(cleanStdout).toContain('DryRun execution of:');
expect(cleanStdout).toContain('npx @code-pushup/cli');
expect(cleanStdout).toContain('--verbose');
expect(cleanStdout).toContain('--dryRun ');
expect(cleanStdout).not.toContain('--verbose');
expect(cleanStdout).toContain('CP_VERBOSE="true"');
});

it('should consider plugin option bin in executor target', async () => {
Expand Down
3 changes: 3 additions & 0 deletions packages/nx-plugin/src/executors/cli/executor.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import runAutorunExecutor from './executor.js';
import * as utils from './utils.js';

describe('runAutorunExecutor', () => {

Check failure on line 7 in packages/nx-plugin/src/executors/cli/executor.int.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'describe'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
const parseAutorunExecutorOptionsSpy = vi.spyOn(
utils,
'parseAutorunExecutorOptions',
);
const executeProcessSpy = vi.spyOn(executeProcessModule, 'executeProcess');

beforeEach(() => {

Check failure on line 14 in packages/nx-plugin/src/executors/cli/executor.int.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2304: Cannot find name 'beforeEach'.
executeProcessSpy.mockResolvedValue({
bin: 'npx ...',
code: 0,
Expand All @@ -26,7 +26,8 @@
executeProcessSpy.mockReset();
});

it('should normalize context, parse CLI options and execute command', async () => {

Check failure on line 29 in packages/nx-plugin/src/executors/cli/executor.int.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'it'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
expect(process.env).not.toHaveProperty('CP_VERBOSE', 'true');
const output = await runAutorunExecutor(
{ verbose: true },
executorContext('utils'),
Expand All @@ -48,5 +49,7 @@
args: expect.arrayContaining(['@code-pushup/cli']),
cwd: process.cwd(),
});

expect(process.env).toHaveProperty('CP_VERBOSE', 'true');
});
});
31 changes: 15 additions & 16 deletions packages/nx-plugin/src/executors/cli/executor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type ExecutorContext, logger } from '@nx/devkit';
import type { ExecutorContext } from '@nx/devkit';
import { executeProcess } from '../../internal/execute-process.js';
import { normalizeContext } from '../internal/context.js';
import type { AutorunCommandExecutorOptions } from './schema.js';
Expand All @@ -15,44 +15,43 @@ export default async function runAutorunExecutor(
terminalAndExecutorOptions: AutorunCommandExecutorOptions,
context: ExecutorContext,
): Promise<ExecutorOutput> {
const { objectToCliArgs, formatCommandStatus } = await import(
'@code-pushup/utils'
);
const { objectToCliArgs, formatCommandStatus, logger, stringifyError } =
await import('@code-pushup/utils');
const normalizedContext = normalizeContext(context);
const cliArgumentObject = parseAutorunExecutorOptions(
terminalAndExecutorOptions,
normalizedContext,
);
const {
dryRun,
verbose,
command: cliCommand,
bin,
} = terminalAndExecutorOptions;
const { command: cliCommand } = terminalAndExecutorOptions;
const { verbose = false, dryRun, bin, ...restArgs } = cliArgumentObject;
logger.setVerbose(verbose);

const command = bin ? `node` : 'npx';
const positionals = [
bin ?? '@code-pushup/cli',
...(cliCommand ? [cliCommand] : []),
];
const args = [...positionals, ...objectToCliArgs(cliArgumentObject)];
const args = [...positionals, ...objectToCliArgs(restArgs)];
const executorEnvVariables = {
...(verbose && { CP_VERBOSE: 'true' }),
};
const commandString = formatCommandStatus([command, ...args].join(' '), {
cwd: context.cwd,
env: executorEnvVariables,
});
if (verbose) {
logger.info(`Run CLI executor ${command ?? ''}`);
logger.info(`Command: ${commandString}`);
}

if (dryRun) {
logger.warn(`DryRun execution of: ${commandString}`);
} else {
try {
logger.debug(`With env vars: ${executorEnvVariables}`);
await executeProcess({
command,
args,
...(context.cwd ? { cwd: context.cwd } : {}),
});
} catch (error) {
logger.error(error);
logger.error(stringifyError(error));
return {
success: false,
command: commandString,
Expand Down
59 changes: 41 additions & 18 deletions packages/nx-plugin/src/executors/cli/executor.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { logger } from '@nx/devkit';
import { afterAll, afterEach, beforeEach, expect, vi } from 'vitest';
import { executorContext } from '@code-pushup/test-nx-utils';
import { MEMFS_VOLUME } from '@code-pushup/test-utils';
import * as executeProcessModule from '../../internal/execute-process.js';
import runAutorunExecutor from './executor.js';

describe('runAutorunExecutor', () => {

Check failure on line 7 in packages/nx-plugin/src/executors/cli/executor.unit.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'describe'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
const processEnvCP = Object.fromEntries(
Object.entries(process.env).filter(([k]) => k.startsWith('CP_')),
);
const loggerInfoSpy = vi.spyOn(logger, 'info');
const loggerWarnSpy = vi.spyOn(logger, 'warn');
const executeProcessSpy = vi.spyOn(executeProcessModule, 'executeProcess');
let logger: import('@code-pushup/utils').Logger;

beforeAll(() => {

Check failure on line 14 in packages/nx-plugin/src/executors/cli/executor.unit.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2304: Cannot find name 'beforeAll'.
Object.entries(process.env)
.filter(([k]) => k.startsWith('CP_'))
.forEach(([k]) => Reflect.deleteProperty(process.env, k));
Expand All @@ -25,7 +23,9 @@
);
});

beforeEach(() => {
beforeEach(async () => {
const utils = await import('@code-pushup/utils');
logger = utils.logger;
vi.unstubAllEnvs();
executeProcessSpy.mockResolvedValue({
bin: 'npx ...',
Expand All @@ -37,12 +37,10 @@
});

afterEach(() => {
loggerWarnSpy.mockReset();
loggerInfoSpy.mockReset();
executeProcessSpy.mockReset();
});

it('should call executeProcess with return result', async () => {

Check failure on line 43 in packages/nx-plugin/src/executors/cli/executor.unit.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'it'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
const output = await runAutorunExecutor({}, executorContext('utils'));
expect(output.success).toBe(true);
expect(output.command).toMatch('npx @code-pushup/cli');
Expand All @@ -53,7 +51,7 @@
});
});

it('should normalize context', async () => {

Check failure on line 54 in packages/nx-plugin/src/executors/cli/executor.unit.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'it'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
const output = await runAutorunExecutor(
{},
{
Expand All @@ -70,7 +68,7 @@
});
});

it('should process executorOptions', async () => {

Check failure on line 71 in packages/nx-plugin/src/executors/cli/executor.unit.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'it'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
const output = await runAutorunExecutor(
{ output: 'code-pushup.config.json', persist: { filename: 'REPORT' } },
executorContext('testing-utils'),
Expand All @@ -80,7 +78,7 @@
expect(output.command).toContain('--persist.filename="REPORT"');
});

it('should create command from context and options if no api key is set', async () => {

Check failure on line 81 in packages/nx-plugin/src/executors/cli/executor.unit.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'it'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
const output = await runAutorunExecutor(
{ persist: { filename: 'REPORT', format: ['md', 'json'] } },
executorContext('core'),
Expand All @@ -91,7 +89,7 @@
);
});

it('should create command from context, options and arguments if api key is set', async () => {

Check failure on line 92 in packages/nx-plugin/src/executors/cli/executor.unit.test.ts

View workflow job for this annotation

GitHub Actions / Standalone mode

<✓> TypeScript | Semantic errors

TS2582: Cannot find name 'it'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
vi.stubEnv('CP_API_KEY', 'cp_1234567');
const output = await runAutorunExecutor(
{
Expand All @@ -108,30 +106,55 @@
expect(output.command).toMatch('--upload.project="CLI"');
});

it('should log information if verbose is set', async () => {
it('should set env var information if verbose is set', async () => {
const output = await runAutorunExecutor(
{ verbose: true },
{
verbose: true,
},
{ ...executorContext('github-action'), cwd: '<CWD>' },
);

expect(executeProcessSpy).toHaveBeenCalledTimes(1);
expect(executeProcessSpy).toHaveBeenCalledWith({
command: 'npx',
args: expect.arrayContaining(['@code-pushup/cli']),
cwd: '<CWD>',
});

expect(output.command).toMatch('--verbose');
expect(loggerWarnSpy).toHaveBeenCalledTimes(0);
expect(loggerInfoSpy).toHaveBeenCalledTimes(2);
expect(loggerInfoSpy).toHaveBeenCalledWith(
expect.stringContaining(`Run CLI executor`),
expect(process.env).toStrictEqual(
expect.objectContaining({
CP_VERBOSE: 'true',
}),
);
expect(loggerInfoSpy).toHaveBeenCalledWith(
expect.stringContaining('Command:'),

expect(output.command).not.toContain('--verbose');
expect(logger.warn).toHaveBeenCalledTimes(0);
});

it('should log env var in dryRun information if verbose is set', async () => {
const output = await runAutorunExecutor(
{
dryRun: true,
verbose: true,
},
{ ...executorContext('github-action'), cwd: '<CWD>' },
);

expect(executeProcessSpy).toHaveBeenCalledTimes(0);

expect(output.command).not.toContain('--verbose');
expect(logger.warn).toHaveBeenCalledTimes(1);
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining('CP_VERBOSE="true"'),
);
});

it('should log command if dryRun is set', async () => {
await runAutorunExecutor({ dryRun: true }, executorContext('utils'));

expect(loggerInfoSpy).toHaveBeenCalledTimes(0);
expect(loggerWarnSpy).toHaveBeenCalledTimes(1);
expect(loggerWarnSpy).toHaveBeenCalledWith(
expect(logger.command).toHaveBeenCalledTimes(0);
expect(logger.warn).toHaveBeenCalledTimes(1);
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining('DryRun execution of'),
);
});
Expand Down