Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
cbe02f2
feat(nx-plugin): add support for local code execution
BioPhoton Sep 5, 2025
b556bd8
refactor: revert plugin options
BioPhoton Sep 5, 2025
4bba9cd
test: update e2e tests
BioPhoton Sep 5, 2025
47bc389
refactor: adjust target options
BioPhoton Sep 5, 2025
695acbc
refactor: add int test for env vars
BioPhoton Sep 5, 2025
5d4fd60
refactor: remove dependencies on packages, use latest
BioPhoton Sep 5, 2025
052e18c
refactor: fix missing bin in command
BioPhoton Sep 5, 2025
e6ac40d
refactor: add colored formatting
BioPhoton Sep 5, 2025
311679f
refactor: fix tests for colored formatting
BioPhoton Sep 5, 2025
8f3b7fa
chore: cache nxv-e2e-setup
BioPhoton Sep 5, 2025
e9e4a3a
refactor: wip
BioPhoton Sep 5, 2025
a1d0f9d
refactor: wip 2
BioPhoton Sep 5, 2025
f1dd383
refactor: wip 3
BioPhoton Sep 5, 2025
93d1d40
refactor: fix e2e
BioPhoton Sep 5, 2025
41c900b
refactor: fix unit test
BioPhoton Sep 5, 2025
60183db
refactor: fix lint
BioPhoton Sep 5, 2025
ea73523
refactor: fix lint
BioPhoton Sep 5, 2025
454960b
refactor: fix lint
BioPhoton Sep 5, 2025
b368ac0
refactor: fix lint
BioPhoton Sep 6, 2025
d5e05a4
refactor: adjust command logic
BioPhoton Sep 6, 2025
2041093
refactor: adjust command logic
BioPhoton Sep 6, 2025
bebae7c
refactor: wip
BioPhoton Sep 6, 2025
f947823
refactor: wip
BioPhoton Sep 6, 2025
752a97e
refactor: wip
BioPhoton Sep 6, 2025
4e90518
refactor: wip
BioPhoton Sep 6, 2025
a180d5c
test(nx-plugin): add tests for buildCommandString
BioPhoton Sep 6, 2025
41f9af2
refactor: wip
BioPhoton Sep 6, 2025
9dff7c4
refactor: revert versions change
BioPhoton Sep 6, 2025
0f3ba3a
Update CONTRIBUTING.md
BioPhoton Sep 8, 2025
cefe54d
Update packages/nx-plugin/src/executors/cli/executor.ts
BioPhoton Sep 8, 2025
d9b453f
Update CONTRIBUTING.md
BioPhoton Sep 8, 2025
7b307d0
Update CONTRIBUTING.md
BioPhoton Sep 8, 2025
a2892ba
refactor: move logic into command.ts
BioPhoton Sep 8, 2025
ff74241
refactor: adjust tests
BioPhoton Sep 8, 2025
fc990a6
refactor: fix build
BioPhoton Sep 8, 2025
b1875d3
refactor: adjust models
BioPhoton Sep 8, 2025
371e70b
refactor: adjust comments
BioPhoton Sep 8, 2025
ab3f5ed
refactor: adjust comments
BioPhoton Sep 8, 2025
aa0950a
refactor: remove comments
BioPhoton Sep 8, 2025
1d006f2
refactor: fix e2e
BioPhoton Sep 8, 2025
fe6d69b
refactor: fix int
BioPhoton Sep 8, 2025
57c13c6
refactor: fix int 2
BioPhoton Sep 8, 2025
39c112a
refactor: fix int 3
BioPhoton Sep 8, 2025
c8c04d2
refactor: revert
BioPhoton Sep 9, 2025
24b5d03
Merge remote-tracking branch 'origin/main' into feat/plugin-nx/allow-…
BioPhoton Sep 9, 2025
08e9a68
Merge remote-tracking branch 'origin/main' into feat/plugin-nx/allow-…
BioPhoton Oct 4, 2025
6b075ee
refactor: fix targets
Oct 4, 2025
30872df
refactor: fix e2e for nx-plugin
Oct 4, 2025
4803bf4
refactor: fix e2e for nx-plugin 2
Oct 4, 2025
dc2fbf9
refactor: fix e2e for nx-plugin 3
Oct 4, 2025
82fb217
Merge branch 'main' into feat/plugin-nx/allow-unreleased-code
Oct 23, 2025
734b4a4
refactor: fix e2e 1
Oct 23, 2025
2b2400c
refactor: fix upload params
Oct 23, 2025
a04d56b
refactor: fix unit-test
Oct 23, 2025
e72b2f3
refactor: fix project name
Oct 23, 2025
1f41384
refactor: fix empty options
Oct 23, 2025
c28e77f
refactor: fix
Oct 23, 2025
a4c759b
refactor: fix e2e
Oct 23, 2025
e5c82df
Update packages/nx-plugin/src/plugin/target/executor-target.ts
BioPhoton Oct 23, 2025
60697d7
Update packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts
BioPhoton Oct 23, 2025
340d700
refactor: adjust logic
Oct 23, 2025
28c48dd
Merge remote-tracking branch 'origin/feat/plugin-nx/allow-unreleased-…
Oct 23, 2025
f8c425a
refactor: adjust logic 2
Oct 23, 2025
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
44 changes: 0 additions & 44 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,50 +69,6 @@ You can control the execution of long-running tests over the `INCLUDE_SLOW_TESTS
To change this setup, open (or create) the `.env` file in the root folder.
Edit or add the environment variable there as follows: `INCLUDE_SLOW_TESTS=true`.

### Executing local code

We use the current version of Code PushUp and its plugins, to measure itself and its plugins.

_Execute the latest CLI source_

```jsonc
// project.json
{
"targets": {
"code-pushup": {
"executor": "nx:run-commands",
"options": {
"command": "node packages/cli/src/index.ts",
"args": ["--no-progress", "--verbose"],
"env": {
"NODE_OPTIONS": "--import tsx",
"TSX_TSCONFIG_PATH": "tsconfig.base.json"
}
}
}
}
```

_Setup code-pushup targets with the nx plugin_

```jsonc
// nx.json
{
"plugins": [
{
"plugin": "@code-pushup/nx-plugin",
"options": {
"cliBin": "node ./packages/cli/src/index.ts",
"env": {
"NODE_OPTIONS": "--import=tsx",
"TSX_TSCONFIG_PATH": "tsconfig.base.json",
},
},
},
],
}
```

## Git

Commit messages must follow [conventional commits](https://conventionalcommits.org/) format.
Expand Down
10 changes: 4 additions & 6 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,12 +173,10 @@ describe('nx-plugin', () => {
});

const cleanStdout = removeColorCodes(stdout);
// @TODO create test environment for working plugin. This here misses package-lock.json to execute correctly
expect(cleanStdout).toContain('Executing command:');
expect(cleanStdout).toContain('npx @code-pushup/cli');
expect(cleanStdout).toContain(
'NX Successfully ran target code-pushup for project my-lib',
);
expect(cleanStdout).toContain('nx run my-lib:code-pushup');
expect(cleanStdout).toContain('$ npx @code-pushup/cli ');
expect(cleanStdout).toContain('--dryRun --verbose');
expect(cleanStdout).toContain(`--upload.project=\\"${project}\\"`);
});

it('should consider plugin option cliBin in executor target', async () => {
Expand Down
3 changes: 1 addition & 2 deletions packages/nx-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@
"@nx/devkit": ">=17.0.0",
"ansis": "^3.3.0",
"nx": ">=17.0.0",
"zod": "^4.0.5",
"chalk": "5.3.0"
"zod": "^4.0.5"
},
"files": [
"src",
Expand Down
2 changes: 1 addition & 1 deletion packages/nx-plugin/src/executors/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ Show what will be executed without actually executing it:
| ----------------- | --------- | ------------------------------------------------------------------ |
| **projectPrefix** | `string` | prefix for upload.project on non root projects |
| **dryRun** | `boolean` | To debug the executor, dry run the command without real execution. |
| **cliBin** | `string` | Path to Code PushUp CLI |
| **bin** | `string` | Path to Code PushUp CLI |

For all other options see the [CLI autorun documentation](../../../../cli/README.md#autorun-command).
43 changes: 0 additions & 43 deletions packages/nx-plugin/src/executors/cli/executor.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,47 +53,4 @@ describe('runAutorunExecutor', () => {
},
});
});

it('should execute command with provided bin', async () => {
const bin = 'packages/cli/dist';
const output = await runAutorunExecutor(
{
verbose: true,
bin,
},
executorContext('utils'),
);
expect(output.success).toBe(true);

expect(executeProcessSpy).toHaveBeenCalledTimes(1);
expect(executeProcessSpy).toHaveBeenCalledWith(
expect.objectContaining({
args: expect.arrayContaining([bin]),
}),
);
});

it('should execute command with provided env vars', async () => {
const output = await runAutorunExecutor(
{
verbose: true,
env: {
NODE_OPTIONS: '--import tsx',
TSX_TSCONFIG_PATH: 'tsconfig.base.json',
},
},
executorContext('utils'),
);
expect(output.success).toBe(true);

expect(executeProcessSpy).toHaveBeenCalledTimes(1);
expect(executeProcessSpy).toHaveBeenCalledWith(
expect.objectContaining({
env: {
NODE_OPTIONS: '--import tsx',
TSX_TSCONFIG_PATH: 'tsconfig.base.json',
},
}),
);
});
});
39 changes: 18 additions & 21 deletions packages/nx-plugin/src/executors/cli/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { executeProcess } from '../../internal/execute-process.js';
import {
createCliCommandObject,
createCliCommandString,
formatCommandLog,
objectToCliArgs,
} from '../internal/cli.js';
import { normalizeContext } from '../internal/context.js';
import type { AutorunCommandExecutorOptions } from './schema.js';
Expand All @@ -21,7 +19,7 @@ export default async function runAutorunExecutor(
context: ExecutorContext,
): Promise<ExecutorOutput> {
const normalizedContext = normalizeContext(context);
const { env, bin, ...mergedOptions } = mergeExecutorOptions(
const mergedOptions = mergeExecutorOptions(
context.target?.options,
terminalAndExecutorOptions,
);
Expand All @@ -32,30 +30,29 @@ export default async function runAutorunExecutor(
const { dryRun, verbose, command } = mergedOptions;
const commandString = createCliCommandString({
command,
bin,
args: cliArgumentObject,
});

if (verbose) {
logger.info(`Run CLI executor ${command ?? ''}`);
logger.info(`Command: ${commandString}`);
}

try {
await executeProcess({
...createCliCommandObject({ command, args: cliArgumentObject, bin }),
...(context.cwd ? { cwd: context.cwd } : {}),
env,
dryRun,
});
} catch (error) {
logger.error(error);
return {
success: false,
command: commandString,
error: error instanceof Error ? error : new Error(stringifyError(error)),
};
if (dryRun) {
logger.warn(`DryRun execution of: ${commandString}`);
} else {
try {
await executeProcess({
...createCliCommandObject({ command, args: cliArgumentObject }),
...(context.cwd ? { cwd: context.cwd } : {}),
});
} catch (error) {
logger.error(error);
return {
success: false,
command: commandString,
error: error as Error,
};
}
}

return {
success: true,
command: commandString,
Expand Down
27 changes: 13 additions & 14 deletions packages/nx-plugin/src/executors/cli/executor.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { logger } from '@nx/devkit';
import { afterAll, afterEach, beforeEach, expect, vi } from 'vitest';
import { executorContext } from '@code-pushup/test-nx-utils';
import { MEMFS_VOLUME, removeColorCodes } from '@code-pushup/test-utils';
import { MEMFS_VOLUME } from '@code-pushup/test-utils';
import * as executeProcessModule from '../../internal/execute-process.js';
import runAutorunExecutor from './executor.js';

Expand Down Expand Up @@ -124,25 +124,24 @@ describe('runAutorunExecutor', () => {

expect(output.command).toMatch('--verbose');
expect(loggerWarnSpy).toHaveBeenCalledTimes(0);
expect(loggerInfoSpy).toHaveBeenCalledTimes(1);
expect(loggerInfoSpy).toHaveBeenCalledTimes(2);
expect(loggerInfoSpy).toHaveBeenCalledWith(
expect.stringContaining(`Run CLI executor`),
);
expect(loggerInfoSpy).toHaveBeenCalledWith(
expect.stringContaining('Command: npx @code-pushup/cli'),
);
});

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

expect(output.success).toBe(true);
expect(executeProcessSpy).toHaveBeenCalledWith(
expect.objectContaining({
dryRun: true,
}),
);
expect(loggerInfoSpy).toHaveBeenCalledTimes(0);
expect(loggerWarnSpy).toHaveBeenCalledTimes(0);
expect(loggerWarnSpy).toHaveBeenCalledTimes(1);
expect(loggerWarnSpy).toHaveBeenCalledWith(
expect.stringContaining(
'DryRun execution of: npx @code-pushup/cli --dryRun',
),
);
});
});
7 changes: 0 additions & 7 deletions packages/nx-plugin/src/executors/cli/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@
"type": "string",
"description": "Path to Code PushUp CLI"
},
"env": {
"type": "object",
"description": "Environment variables to set when running the command",
"additionalProperties": {
"type": "string"
}
},
"verbose": {
"type": "boolean",
"description": "Print additional logs"
Expand Down
43 changes: 4 additions & 39 deletions packages/nx-plugin/src/executors/internal/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { logger } from '@nx/devkit';
import chalk from 'chalk';
import type { ProcessConfig } from '../../internal/execute-process.js';

export function createCliCommandString(options?: {
Expand All @@ -13,49 +12,15 @@ export function createCliCommandString(options?: {
)}`;
}

export function formatCommandLog({
command,
args = [],
env,
}: {
command: string;
args: string[];
env?: Record<string, string>;
}): string {
const logElements: string[] = [];
if (env) {
const envVars = Object.entries(env).map(
([key, value]) =>
`${chalk.green(key)}="${chalk.blueBright(value.replaceAll('"', ''))}"`,
);
// eslint-disable-next-line functional/immutable-data
logElements.push(...envVars);
}
// eslint-disable-next-line functional/immutable-data
logElements.push(chalk.cyan(command));
if (args.length > 0) {
// eslint-disable-next-line functional/immutable-data
logElements.push(chalk.dim.gray(args.join(' ')));
}
return logElements.join(' ');
}

export function createCliCommandObject(options?: {
args?: Record<string, unknown>;
command?: 'autorun' | 'collect' | 'upload' | 'print-config' | string;
command?: string;
bin?: string;
}): ProcessConfig {
const { bin = 'npx @code-pushup/cli', command, args } = options ?? {};
const binArr = bin.split(' ');

// If bin contains spaces, use the first part as command and rest as args
// If bin is a single path, default to 'npx' and use the bin as first arg
const finalCommand = binArr.length > 1 ? (binArr[0] ?? 'npx') : 'npx';
const binArgs = binArr.length > 1 ? binArr.slice(1) : [bin];

const { bin = '@code-pushup/cli', command, args } = options ?? {};
return {
command: finalCommand,
args: [...binArgs, ...objectToCliArgs({ _: command ?? [], ...args })],
command: 'npx',
args: [bin, ...objectToCliArgs({ _: command ?? [], ...args })],
observer: {
onError: error => {
logger.error(error.message);
Expand Down
Loading
Loading