diff --git a/packages/nx-plugin/src/executors/cli/executor.int.test.ts b/packages/nx-plugin/src/executors/cli/executor.int.test.ts index eaa7f1777..4bde33d79 100644 --- a/packages/nx-plugin/src/executors/cli/executor.int.test.ts +++ b/packages/nx-plugin/src/executors/cli/executor.int.test.ts @@ -1,14 +1,11 @@ -import { afterEach, expect, vi } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { executorContext } from '@code-pushup/test-nx-utils'; import * as executeProcessModule from '../../internal/execute-process.js'; -import runAutorunExecutor from './executor.js'; +import runCliExecutor from './executor.js'; import * as utils from './utils.js'; -describe('runAutorunExecutor', () => { - const parseAutorunExecutorOptionsSpy = vi.spyOn( - utils, - 'parseAutorunExecutorOptions', - ); +describe('runCliExecutor', () => { + const parseCliExecutorOptionsSpy = vi.spyOn(utils, 'parseCliExecutorOptions'); const executeProcessSpy = vi.spyOn(executeProcessModule, 'executeProcess'); beforeEach(() => { @@ -22,22 +19,22 @@ describe('runAutorunExecutor', () => { }); afterEach(() => { - parseAutorunExecutorOptionsSpy.mockReset(); + parseCliExecutorOptionsSpy.mockRestore(); executeProcessSpy.mockReset(); }); it('should normalize context, parse CLI options and execute command', async () => { expect(process.env).not.toHaveProperty('CP_VERBOSE', 'true'); - const output = await runAutorunExecutor( + const output = await runCliExecutor( { verbose: true }, executorContext('utils'), ); expect(output.success).toBe(true); - expect(parseAutorunExecutorOptionsSpy).toHaveBeenCalledTimes(1); + expect(parseCliExecutorOptionsSpy).toHaveBeenCalledTimes(1); //is context normalized - expect(parseAutorunExecutorOptionsSpy).toHaveBeenCalledWith( + expect(parseCliExecutorOptionsSpy).toHaveBeenCalledWith( { verbose: true }, expect.objectContaining({ projectConfig: expect.objectContaining({ name: 'utils' }), @@ -49,7 +46,24 @@ describe('runAutorunExecutor', () => { args: expect.arrayContaining(['@code-pushup/cli']), cwd: process.cwd(), }); + }); - expect(process.env).toHaveProperty('CP_VERBOSE', 'true'); + it('should forward env options to executeProcess', async () => { + const output = await runCliExecutor( + { + verbose: true, + env: { TEST_VALUE: '42' }, + }, + executorContext('utils'), + ); + expect(output.success).toBe(true); + expect(executeProcessSpy).toHaveBeenCalledTimes(1); + expect(executeProcessSpy).toHaveBeenCalledWith( + expect.objectContaining({ + env: expect.objectContaining({ + TEST_VALUE: '42', + }), + }), + ); }); }); diff --git a/packages/nx-plugin/src/executors/cli/executor.ts b/packages/nx-plugin/src/executors/cli/executor.ts index 066119213..9f83f5868 100644 --- a/packages/nx-plugin/src/executors/cli/executor.ts +++ b/packages/nx-plugin/src/executors/cli/executor.ts @@ -1,8 +1,8 @@ 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'; -import { parseAutorunExecutorOptions } from './utils.js'; +import type { CliCommandExecutorOptions } from './schema.js'; +import { parseCliExecutorOptions } from './utils.js'; export type ExecutorOutput = { success: boolean; @@ -11,44 +11,55 @@ export type ExecutorOutput = { }; /* eslint-disable-next-line max-lines-per-function */ -export default async function runAutorunExecutor( - terminalAndExecutorOptions: AutorunCommandExecutorOptions, +export default async function runCliExecutor( + terminalAndExecutorOptions: CliCommandExecutorOptions, context: ExecutorContext, ): Promise { const { objectToCliArgs, formatCommandStatus, logger, stringifyError } = await import('@code-pushup/utils'); const normalizedContext = normalizeContext(context); - const cliArgumentObject = parseAutorunExecutorOptions( - terminalAndExecutorOptions, - normalizedContext, - ); - const { command: cliCommand } = terminalAndExecutorOptions; - const { verbose = false, dryRun, bin, ...restArgs } = cliArgumentObject; + const { + command: cliCommand, + verbose = false, + dryRun, + env: executorEnv, + bin, + ...restArgs + } = parseCliExecutorOptions(terminalAndExecutorOptions, normalizedContext); + logger.setVerbose(verbose); const command = bin ? `node` : 'npx'; - const positionals = [ + const args = [ bin ?? '@code-pushup/cli', ...(cliCommand ? [cliCommand] : []), + ...objectToCliArgs(restArgs), ]; - const args = [...positionals, ...objectToCliArgs(restArgs)]; - const executorEnvVariables = { - ...(verbose && { CP_VERBOSE: 'true' }), - }; const commandString = formatCommandStatus([command, ...args].join(' '), { cwd: context.cwd, - env: executorEnvVariables, + env: { + ...executorEnv, + ...(verbose && { CP_VERBOSE: 'true' }), + }, }); if (dryRun) { logger.warn(`DryRun execution of: ${commandString}`); } else { try { - logger.debug(`With env vars: ${executorEnvVariables}`); + logger.debug(`With env vars: ${executorEnv}`); await executeProcess({ command, args, ...(context.cwd ? { cwd: context.cwd } : {}), + ...(executorEnv && Object.keys(executorEnv).length > 0 + ? { + env: { + ...process.env, + ...executorEnv, + }, + } + : {}), }); } catch (error) { logger.error(stringifyError(error)); diff --git a/packages/nx-plugin/src/executors/cli/executor.unit.test.ts b/packages/nx-plugin/src/executors/cli/executor.unit.test.ts index 4736f8196..120b4bbfd 100644 --- a/packages/nx-plugin/src/executors/cli/executor.unit.test.ts +++ b/packages/nx-plugin/src/executors/cli/executor.unit.test.ts @@ -1,10 +1,19 @@ -import { afterAll, afterEach, beforeEach, expect, vi } from 'vitest'; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + it, + 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'; +import runCliExecutor from './executor.js'; -describe('runAutorunExecutor', () => { +describe('runCliExecutor', () => { const processEnvCP = Object.fromEntries( Object.entries(process.env).filter(([k]) => k.startsWith('CP_')), ); @@ -41,7 +50,7 @@ describe('runAutorunExecutor', () => { }); it('should call executeProcess with return result', async () => { - const output = await runAutorunExecutor({}, executorContext('utils')); + const output = await runCliExecutor({}, executorContext('utils')); expect(output.success).toBe(true); expect(output.command).toMatch('npx @code-pushup/cli'); expect(executeProcessSpy).toHaveBeenCalledWith({ @@ -52,7 +61,7 @@ describe('runAutorunExecutor', () => { }); it('should normalize context', async () => { - const output = await runAutorunExecutor( + const output = await runCliExecutor( {}, { ...executorContext('utils'), @@ -60,7 +69,8 @@ describe('runAutorunExecutor', () => { }, ); expect(output.success).toBe(true); - expect(output.command).toMatch('utils'); + expect(output.command).toMatch('npx @code-pushup/cli'); + expect(output.command).toContain('cwd-form-context'); expect(executeProcessSpy).toHaveBeenCalledWith({ command: 'npx', args: expect.arrayContaining(['@code-pushup/cli']), @@ -69,7 +79,7 @@ describe('runAutorunExecutor', () => { }); it('should process executorOptions', async () => { - const output = await runAutorunExecutor( + const output = await runCliExecutor( { output: 'code-pushup.config.json', persist: { filename: 'REPORT' } }, executorContext('testing-utils'), ); @@ -79,7 +89,7 @@ describe('runAutorunExecutor', () => { }); it('should create command from context and options if no api key is set', async () => { - const output = await runAutorunExecutor( + const output = await runCliExecutor( { persist: { filename: 'REPORT', format: ['md', 'json'] } }, executorContext('core'), ); @@ -91,7 +101,7 @@ describe('runAutorunExecutor', () => { it('should create command from context, options and arguments if api key is set', async () => { vi.stubEnv('CP_API_KEY', 'cp_1234567'); - const output = await runAutorunExecutor( + const output = await runCliExecutor( { persist: { filename: 'REPORT', format: ['md', 'json'] }, upload: { project: 'CLI' }, @@ -107,7 +117,7 @@ describe('runAutorunExecutor', () => { }); it('should set env var information if verbose is set', async () => { - const output = await runAutorunExecutor( + const output = await runCliExecutor( { verbose: true, }, @@ -131,8 +141,8 @@ describe('runAutorunExecutor', () => { expect(logger.warn).toHaveBeenCalledTimes(0); }); - it('should log env var in dryRun information if verbose is set', async () => { - const output = await runAutorunExecutor( + it('should log CP_VERBOSE env var in dryRun information if verbose is set', async () => { + const output = await runCliExecutor( { dryRun: true, verbose: true, @@ -150,7 +160,7 @@ describe('runAutorunExecutor', () => { }); it('should log command if dryRun is set', async () => { - await runAutorunExecutor({ dryRun: true }, executorContext('utils')); + await runCliExecutor({ dryRun: true }, executorContext('utils')); expect(logger.command).toHaveBeenCalledTimes(0); expect(logger.warn).toHaveBeenCalledTimes(1); diff --git a/packages/nx-plugin/src/executors/cli/schema.json b/packages/nx-plugin/src/executors/cli/schema.json index b03736e23..d2cf4a0f5 100644 --- a/packages/nx-plugin/src/executors/cli/schema.json +++ b/packages/nx-plugin/src/executors/cli/schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/schema", - "$id": "AutorunExecutorOptions", + "$id": "CliExecutorOptions", "title": "CodePushup CLI autorun executor", "description": "Executes the @code-pushup/cli autorun command See: https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#autorun-command", "type": "object", @@ -21,6 +21,13 @@ "type": "string", "description": "Path to Code PushUp CLI" }, + "env": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Environment variables added to Code PushUp CLI process" + }, "verbose": { "type": "boolean", "description": "Print additional logs" diff --git a/packages/nx-plugin/src/executors/cli/schema.ts b/packages/nx-plugin/src/executors/cli/schema.ts index 7477a276e..6e37d48e8 100644 --- a/packages/nx-plugin/src/executors/cli/schema.ts +++ b/packages/nx-plugin/src/executors/cli/schema.ts @@ -8,15 +8,15 @@ import type { export type PrintConfigOptions = { output?: string }; export type PrintConfigCommandExecutorOptions = PrintConfigOptions; -export type AutorunCommandExecutorOnlyOptions = ProjectExecutorOnlyOptions & +export type CliCommandExecutorOnlyOptions = ProjectExecutorOnlyOptions & CollectExecutorOnlyOptions & GeneralExecutorOnlyOptions; -export type AutorunCommandExecutorOptions = Partial< +export type CliCommandExecutorOptions = Partial< { upload: Partial; persist: Partial; - } & AutorunCommandExecutorOnlyOptions & + } & CliCommandExecutorOnlyOptions & GlobalExecutorOptions > & PrintConfigOptions; diff --git a/packages/nx-plugin/src/executors/cli/utils.int.test.ts b/packages/nx-plugin/src/executors/cli/utils.int.test.ts index 180f22af1..cecff0afc 100644 --- a/packages/nx-plugin/src/executors/cli/utils.int.test.ts +++ b/packages/nx-plugin/src/executors/cli/utils.int.test.ts @@ -1,10 +1,10 @@ -import { expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import type { UploadConfig } from '@code-pushup/models'; import { normalizedExecutorContext } from '../../../mock/utils/executor.js'; import * as config from '../internal/config.js'; -import { parseAutorunExecutorOptions } from './utils.js'; +import { parseCliExecutorOptions } from './utils.js'; -describe('parseAutorunExecutorOptions', () => { +describe('parseCliExecutorOptions', () => { const persistConfigSpy = vi.spyOn(config, 'persistConfig'); const uploadConfigSpy = vi.spyOn(config, 'uploadConfig'); const globalConfigSpy = vi.spyOn(config, 'globalConfig'); @@ -17,7 +17,7 @@ describe('parseAutorunExecutorOptions', () => { }); it('should call child config functions with options', () => { - parseAutorunExecutorOptions( + parseCliExecutorOptions( { verbose: true, persist: { filename: 'my-name' }, diff --git a/packages/nx-plugin/src/executors/cli/utils.ts b/packages/nx-plugin/src/executors/cli/utils.ts index b91753402..7e7d131b8 100644 --- a/packages/nx-plugin/src/executors/cli/utils.ts +++ b/packages/nx-plugin/src/executors/cli/utils.ts @@ -5,19 +5,21 @@ import { } from '../internal/config.js'; import type { NormalizedExecutorContext } from '../internal/context.js'; import type { - AutorunCommandExecutorOnlyOptions, - AutorunCommandExecutorOptions, + CliCommandExecutorOnlyOptions, + CliCommandExecutorOptions, PrintConfigCommandExecutorOptions, } from './schema.js'; -export function parseAutorunExecutorOnlyOptions( - options: Partial, -): AutorunCommandExecutorOnlyOptions { - const { projectPrefix, dryRun, onlyPlugins } = options; +export function parseCliExecutorOnlyOptions( + options: Partial, +): CliCommandExecutorOnlyOptions { + const { projectPrefix, dryRun, onlyPlugins, env, bin } = options; return { ...(projectPrefix && { projectPrefix }), ...(dryRun != null && { dryRun }), ...(onlyPlugins && { onlyPlugins }), + ...(env && { env }), + ...(bin && { bin }), }; } @@ -30,10 +32,10 @@ export function parsePrintConfigExecutorOptions( }; } -export function parseAutorunExecutorOptions( - options: Partial, +export function parseCliExecutorOptions( + options: Partial, normalizedContext: NormalizedExecutorContext, -): AutorunCommandExecutorOptions { +): CliCommandExecutorOptions { const { projectPrefix, persist, upload, command, output } = options; const needsUploadParams = command === 'upload' || command === 'autorun' || command === undefined; @@ -44,7 +46,7 @@ export function parseAutorunExecutorOptions( const hasApiToken = uploadCfg?.apiKey != null; return { ...parsePrintConfigExecutorOptions(options), - ...parseAutorunExecutorOnlyOptions(options), + ...parseCliExecutorOnlyOptions(options), ...globalConfig(options, normalizedContext), ...(output ? { output } : {}), persist: persistConfig({ projectPrefix, ...persist }, normalizedContext), diff --git a/packages/nx-plugin/src/executors/cli/utils.unit.test.ts b/packages/nx-plugin/src/executors/cli/utils.unit.test.ts index 9a75e744b..83da5cf0e 100644 --- a/packages/nx-plugin/src/executors/cli/utils.unit.test.ts +++ b/packages/nx-plugin/src/executors/cli/utils.unit.test.ts @@ -1,9 +1,9 @@ -import { type MockInstance, expect, vi } from 'vitest'; +import { type MockInstance, describe, expect, it, vi } from 'vitest'; import { osAgnosticPath } from '@code-pushup/test-utils'; import type { Command } from '../internal/types.js'; import { - parseAutorunExecutorOnlyOptions, - parseAutorunExecutorOptions, + parseCliExecutorOnlyOptions, + parseCliExecutorOptions, parsePrintConfigExecutorOptions, } from './utils.js'; @@ -23,45 +23,57 @@ describe('parsePrintConfigExecutorOptions', () => { }); }); -describe('parseAutorunExecutorOnlyOptions', () => { +describe('parseCliExecutorOnlyOptions', () => { it('should provide NO default projectPrefix', () => { - expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( + expect(parseCliExecutorOnlyOptions({})).toStrictEqual( expect.not.objectContaining({ projectPrefix: expect.anything() }), ); }); it('should process given projectPrefix', () => { - expect( - parseAutorunExecutorOnlyOptions({ projectPrefix: 'cli' }), - ).toStrictEqual(expect.objectContaining({ projectPrefix: 'cli' })); + expect(parseCliExecutorOnlyOptions({ projectPrefix: 'cli' })).toStrictEqual( + expect.objectContaining({ projectPrefix: 'cli' }), + ); }); it('should provide NO default dryRun', () => { - expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( + expect(parseCliExecutorOnlyOptions({})).toStrictEqual( expect.not.objectContaining({ dryRun: expect.anything() }), ); }); it('should process given dryRun', () => { - expect(parseAutorunExecutorOnlyOptions({ dryRun: false })).toStrictEqual( + expect(parseCliExecutorOnlyOptions({ dryRun: false })).toStrictEqual( expect.objectContaining({ dryRun: false }), ); }); it('should provide default onlyPlugins', () => { - expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( + expect(parseCliExecutorOnlyOptions({})).toStrictEqual( expect.not.objectContaining({ onlyPlugins: ['json'] }), ); }); it('should process given onlyPlugins', () => { expect( - parseAutorunExecutorOnlyOptions({ onlyPlugins: ['md', 'json'] }), + parseCliExecutorOnlyOptions({ onlyPlugins: ['md', 'json'] }), ).toStrictEqual(expect.objectContaining({ onlyPlugins: ['md', 'json'] })); }); + + it('should log env variables options if given', async () => { + expect( + parseCliExecutorOnlyOptions({ env: { TEST_ENV_VAR: '42' } }), + ).toStrictEqual(expect.objectContaining({ env: { TEST_ENV_VAR: '42' } })); + }); + + it('should process given bin', () => { + expect(parseCliExecutorOnlyOptions({ bin: 'index.js' })).toStrictEqual( + expect.objectContaining({ bin: 'index.js' }), + ); + }); }); -describe('parseAutorunExecutorOptions', () => { +describe('parseCliExecutorOptions', () => { let processEnvSpy: MockInstance<[], NodeJS.ProcessEnv>; beforeAll(() => { @@ -74,7 +86,7 @@ describe('parseAutorunExecutorOptions', () => { it('should leverage other config helper to assemble the executor config', () => { const projectName = 'my-app'; - const executorOptions = parseAutorunExecutorOptions( + const executorOptions = parseCliExecutorOptions( { persist: { filename: 'from-options', @@ -84,7 +96,7 @@ describe('parseAutorunExecutorOptions', () => { projectName, workspaceRoot: 'workspaceRoot', projectConfig: { - name: 'my-app', + name: projectName, root: 'root', }, }, @@ -111,11 +123,33 @@ describe('parseAutorunExecutorOptions', () => { ); }); + it('should include the env options', () => { + const projectName = 'my-app'; + const env = { + NODE_OPTIONS: '--import tsx', + TSX_TSCONFIG_PATH: 'tsconfig.base.json', + }; + + const executorOptions = parseCliExecutorOptions( + { env }, + { + projectName, + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: projectName, + root: 'root', + }, + }, + ); + + expect(executorOptions.env).toStrictEqual(env); + }); + it.each(['upload', 'autorun', undefined])( 'should include upload config for command %s if API key is provided', command => { const projectName = 'my-app'; - const executorOptions = parseAutorunExecutorOptions( + const executorOptions = parseCliExecutorOptions( { command, upload: { @@ -144,7 +178,7 @@ describe('parseAutorunExecutorOptions', () => { 'should not include upload config for command %s', command => { const projectName = 'my-app'; - const executorOptions = parseAutorunExecutorOptions( + const executorOptions = parseCliExecutorOptions( { command, upload: { diff --git a/packages/nx-plugin/src/executors/internal/config.ts b/packages/nx-plugin/src/executors/internal/config.ts index d656cecce..7c285a971 100644 --- a/packages/nx-plugin/src/executors/internal/config.ts +++ b/packages/nx-plugin/src/executors/internal/config.ts @@ -14,8 +14,9 @@ export function globalConfig( ): GlobalExecutorOptions { const { projectConfig } = context; const { root: projectRoot = '' } = projectConfig ?? {}; - const { verbose, config } = options; + const { verbose, config, command } = options; return { + command, verbose: !!verbose, config: config ?? path.join(projectRoot, 'code-pushup.config.ts'), }; diff --git a/packages/nx-plugin/src/executors/internal/config.unit.test.ts b/packages/nx-plugin/src/executors/internal/config.unit.test.ts index 298f12290..cf4077b55 100644 --- a/packages/nx-plugin/src/executors/internal/config.unit.test.ts +++ b/packages/nx-plugin/src/executors/internal/config.unit.test.ts @@ -67,6 +67,20 @@ describe('globalConfig', () => { ).toEqual(expect.objectContaining({ config: 'my.config.ts' })); }); + it('should include the command options', () => { + const { command } = globalConfig( + { command: 'collect' }, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ); + expect(command).toBe('collect'); + }); + it('should work with empty projectConfig', () => { expect( globalConfig( diff --git a/packages/nx-plugin/src/executors/internal/types.ts b/packages/nx-plugin/src/executors/internal/types.ts index cb630cc0a..8894b787e 100644 --- a/packages/nx-plugin/src/executors/internal/types.ts +++ b/packages/nx-plugin/src/executors/internal/types.ts @@ -5,6 +5,8 @@ import type { ProjectConfiguration } from 'nx/src/config/workspace-json-project- */ export type GeneralExecutorOnlyOptions = { dryRun?: boolean; + env?: Record; + bin?: string; }; /** @@ -29,7 +31,6 @@ export type Command = | 'history'; export type GlobalExecutorOptions = { command?: Command; - bin?: string; verbose?: boolean; config?: string; }; diff --git a/packages/nx-plugin/src/generators/configuration/schema.d.ts b/packages/nx-plugin/src/generators/configuration/schema.d.ts index b105270c6..0f0cb7b79 100644 --- a/packages/nx-plugin/src/generators/configuration/schema.d.ts +++ b/packages/nx-plugin/src/generators/configuration/schema.d.ts @@ -2,7 +2,6 @@ import type { DynamicTargetOptions } from '../../internal/types.js'; export type ConfigurationGeneratorOptions = { project: string; - bin?: string; skipTarget?: boolean; skipConfig?: boolean; skipFormat?: boolean; diff --git a/packages/nx-plugin/src/index.ts b/packages/nx-plugin/src/index.ts index 12e2e4825..31beb6920 100644 --- a/packages/nx-plugin/src/index.ts +++ b/packages/nx-plugin/src/index.ts @@ -10,7 +10,7 @@ const plugin = { export default plugin; -export type { AutorunCommandExecutorOptions } from './executors/cli/schema.js'; +export type { CliCommandExecutorOptions } from './executors/cli/schema.js'; export { generateCodePushupConfig } from './generators/configuration/code-pushup-config.js'; export { configurationGenerator } from './generators/configuration/generator.js'; export type { ConfigurationGeneratorOptions } from './generators/configuration/schema.js'; diff --git a/packages/nx-plugin/src/internal/types.ts b/packages/nx-plugin/src/internal/types.ts index bf3a2d047..3a34d86d7 100644 --- a/packages/nx-plugin/src/internal/types.ts +++ b/packages/nx-plugin/src/internal/types.ts @@ -1,4 +1,5 @@ export type DynamicTargetOptions = { targetName?: string; bin?: string; + env?: Record; }; diff --git a/packages/nx-plugin/src/plugin/target/executor-target.ts b/packages/nx-plugin/src/plugin/target/executor-target.ts index d8cfab569..df968154b 100644 --- a/packages/nx-plugin/src/plugin/target/executor-target.ts +++ b/packages/nx-plugin/src/plugin/target/executor-target.ts @@ -5,13 +5,17 @@ import type { ProjectPrefixOptions } from '../types.js'; export function createExecutorTarget(options?: { bin?: string; projectPrefix?: string; -}): TargetConfiguration { - const { bin, projectPrefix } = options ?? {}; + env?: Record; +}): TargetConfiguration< + ProjectPrefixOptions & { env?: Record } +> { + const { bin, projectPrefix, env } = options ?? {}; const executor = `${PACKAGE_NAME}:cli`; - const executorOptions = (bin || projectPrefix) && { + const executorOptions = (bin || projectPrefix || env) && { ...(bin && { bin }), ...(projectPrefix && { projectPrefix }), + ...(env && { env }), }; return { executor, ...(executorOptions && { options: executorOptions }) }; } diff --git a/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts b/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts index 2926d3367..baec99a6d 100644 --- a/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts +++ b/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts @@ -27,4 +27,23 @@ describe('createExecutorTarget', () => { }, }); }); + + it('should use env if provided', () => { + expect( + createExecutorTarget({ + env: { + NODE_OPTIONS: '--import tsx', + TSX_TSCONFIG_PATH: 'tsconfig.base.json', + }, + }), + ).toStrictEqual({ + executor: '@code-pushup/nx-plugin:cli', + options: { + env: { + NODE_OPTIONS: '--import tsx', + TSX_TSCONFIG_PATH: 'tsconfig.base.json', + }, + }, + }); + }); }); diff --git a/packages/nx-plugin/src/plugin/target/targets.ts b/packages/nx-plugin/src/plugin/target/targets.ts index f68b1f903..8037c2e98 100644 --- a/packages/nx-plugin/src/plugin/target/targets.ts +++ b/packages/nx-plugin/src/plugin/target/targets.ts @@ -19,11 +19,12 @@ export async function createTargets(normalizedContext: CreateTargetsOptions) { targetName = CP_TARGET_NAME, bin, projectPrefix, + env, } = normalizedContext.createOptions; const rootFiles = await readdir(normalizedContext.projectRoot); return rootFiles.some(filename => filename.match(CODE_PUSHUP_CONFIG_REGEX)) ? { - [targetName]: createExecutorTarget({ bin, projectPrefix }), + [targetName]: createExecutorTarget({ bin, projectPrefix, env }), } : // if NO code-pushup.config.*.(ts|js|mjs) is present return configuration target {