From 884bafeb07911c637d04916065e0a931840e70d2 Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Thu, 10 Oct 2024 16:48:19 -0700 Subject: [PATCH] fix(core): allow configuration in inflix --- e2e/nx/src/run.test.ts | 3 +- .../nx/src/command-line/run/run-one.spec.ts | 137 ++++++++++++++++++ packages/nx/src/command-line/run/run-one.ts | 8 +- .../nx/src/tasks-runner/create-task-graph.ts | 8 +- packages/nx/src/utils/split-target.spec.ts | 72 +++++---- 5 files changed, 198 insertions(+), 30 deletions(-) create mode 100644 packages/nx/src/command-line/run/run-one.spec.ts diff --git a/e2e/nx/src/run.test.ts b/e2e/nx/src/run.test.ts index 6792fd43abeb0..95b357a535d3a 100644 --- a/e2e/nx/src/run.test.ts +++ b/e2e/nx/src/run.test.ts @@ -161,7 +161,7 @@ describe('Nx Running Tests', () => { } expect(runCLI(`echo:fail ${mylib}`, { silenceError: true })).toContain( - `Cannot find configuration for task ${mylib}:echo:fail` + `Cannot find configuration for task ${mylib}:echo` ); updateJson(`libs/${mylib}/project.json`, (c) => original); @@ -346,6 +346,7 @@ describe('Nx Running Tests', () => { runCLI(`generate @nx/web:app apps/${myapp}`); runCLI(`build ${myapp}`); + runCLI(`build:production ${myapp}`); }, 10000); it('should support project name positional arg non-consecutive to target', () => { diff --git a/packages/nx/src/command-line/run/run-one.spec.ts b/packages/nx/src/command-line/run/run-one.spec.ts new file mode 100644 index 0000000000000..b22cb3be74c33 --- /dev/null +++ b/packages/nx/src/command-line/run/run-one.spec.ts @@ -0,0 +1,137 @@ +import type { ProjectGraph } from '../../config/project-graph'; +import { parseRunOneOptions } from './run-one'; + +describe('parseRunOneOptions', () => { + const projectGraph: ProjectGraph = { + nodes: { + project: { + name: 'project', + data: { + root: '', + targets: { + target: { + configurations: { + dev: {}, + }, + }, + 'target:target': { + configurations: { + dev: {}, + }, + }, + 'hello:world': {}, + }, + }, + type: 'app', + }, + }, + dependencies: {}, + }; + + it('should split format project:target:configuration', () => { + expect( + parseRunOneOptions( + '', + { + 'project:target:configuration': 'project:target:configuration', + }, + projectGraph, + {} + ) + ).toEqual({ + configuration: 'configuration', + parsedArgs: {}, + project: 'project', + target: 'target', + }); + + expect( + parseRunOneOptions( + '', + { + 'project:target:configuration': 'project:target', + }, + projectGraph, + {} + ) + ).toEqual({ + parsedArgs: {}, + project: 'project', + target: 'target', + }); + }); + + it('should split format target:configuration for default project', () => { + expect( + parseRunOneOptions( + '', + { + 'project:target:configuration': 'target', + }, + projectGraph, + { defaultProject: 'project' } + ) + ).toEqual({ + parsedArgs: {}, + project: 'project', + target: 'target', + }); + }); + + it('should parse options with project and target specified', () => { + expect( + parseRunOneOptions( + '', + { + project: 'project', + target: 'target', + }, + projectGraph, + { defaultProject: 'project' } + ) + ).toEqual({ + parsedArgs: { + target: 'target', + }, + project: 'project', + target: 'target', + }); + + expect( + parseRunOneOptions( + '', + { + project: 'project', + target: 'target:configuration', + }, + projectGraph, + { defaultProject: 'project' } + ) + ).toEqual({ + parsedArgs: { + target: 'target:configuration', + }, + project: 'project', + target: 'target', + configuration: 'configuration', + }); + + expect( + parseRunOneOptions( + '', + { + project: 'project', + target: 'target:target', + }, + projectGraph, + { defaultProject: 'project' } + ) + ).toEqual({ + parsedArgs: { + target: 'target:target', + }, + project: 'project', + target: 'target:target', + }); + }); +}); diff --git a/packages/nx/src/command-line/run/run-one.ts b/packages/nx/src/command-line/run/run-one.ts index 4f17d76f44ff8..ff58285b6c8bd 100644 --- a/packages/nx/src/command-line/run/run-one.ts +++ b/packages/nx/src/command-line/run/run-one.ts @@ -115,7 +115,7 @@ const targetAliases = { t: 'test', }; -function parseRunOneOptions( +export function parseRunOneOptions( cwd: string, parsedArgs: { [k: string]: any }, projectGraph: ProjectGraph, @@ -143,6 +143,12 @@ function parseRunOneOptions( target = project; project = defaultProjectName; } + } else if (parsedArgs.project && parsedArgs.target?.indexOf(':') > -1) { + // infix case + [project, target, configuration] = splitTarget( + `${parsedArgs.project}:${parsedArgs.target}`, + projectGraph + ); } else { target = parsedArgs.target ?? parsedArgs['project:target:configuration']; } diff --git a/packages/nx/src/tasks-runner/create-task-graph.ts b/packages/nx/src/tasks-runner/create-task-graph.ts index 62d3b695e12ad..59e631e1f346a 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.ts @@ -315,13 +315,17 @@ export class ProcessTasks { ): Task { if (!project.data.targets[target]) { throw new Error( - `Cannot find configuration for task ${project.name}:${target}` + `Cannot find configuration for task ${project.name}:${target}${ + resolvedConfiguration ? ':' + resolvedConfiguration : '' + }` ); } if (!project.data.targets[target].executor) { throw new Error( - `Target "${project.name}:${target}" does not have an executor configured` + `Target "${project.name}:${target}${ + resolvedConfiguration ? ':' + resolvedConfiguration : '' + }" does not have an executor configured` ); } diff --git a/packages/nx/src/utils/split-target.spec.ts b/packages/nx/src/utils/split-target.spec.ts index cf79e6fb5e849..d766c8e3cc78a 100644 --- a/packages/nx/src/utils/split-target.spec.ts +++ b/packages/nx/src/utils/split-target.spec.ts @@ -1,64 +1,84 @@ -import { ProjectGraph } from '../config/project-graph'; -import { ProjectGraphBuilder } from '../project-graph/project-graph-builder'; +import type { ProjectGraph } from '../config/project-graph'; import { splitTarget } from './split-target'; let projectGraph: ProjectGraph; describe('splitTarget', () => { beforeAll(() => { - let builder = new ProjectGraphBuilder(); - builder.addNode({ - name: 'project', - data: { - root: '', - targets: { - target: {}, - 'target:target': {}, + projectGraph = { + nodes: { + project: { + name: 'project', + data: { + root: '', + targets: { + target: {}, + 'target:target': {}, + }, + }, + type: 'app', }, }, - type: 'app', - }); - - projectGraph = builder.getUpdatedProjectGraph(); + dependencies: {}, + }; }); it('should support only project', () => { expect(splitTarget('project', projectGraph)).toEqual(['project']); + expect(splitTarget('random', projectGraph)).toEqual(['random']); // return the project name as is }); - it('should project:target', () => { + it('should split format project:target', () => { expect(splitTarget('project:target', projectGraph)).toEqual([ 'project', 'target', ]); + + expect(splitTarget('project:random', projectGraph)).toEqual([ + 'project', + 'random', + ]); // return the target name as is }); - it('should project:target:configuration', () => { + it('should split format project:target:configuration', () => { expect(splitTarget('project:target:configuration', projectGraph)).toEqual([ 'project', 'target', 'configuration', ]); + + expect(splitTarget('project:random:configuration', projectGraph)).toEqual([ + 'project', + 'random', + 'configuration', + ]); // return the target name as is + + expect(splitTarget('project:random:random', projectGraph)).toEqual([ + 'project', + 'random', + 'random', + ]); // return the target and configuration name as is }); - it('should targets that contain colons when present in the graph', () => { + it('should identify targets that contain colons when present in the graph', () => { expect( splitTarget('project:target:target:configuration', projectGraph) ).toEqual(['project', 'target:target', 'configuration']); + + expect(splitTarget('project:target:target', projectGraph)).toEqual([ + 'project', + 'target:target', + ]); }); - it('should targets that contain colons when not present in the graph but surrounded by quotes', () => { + it('should identify targets that contain colons when not present in the graph but surrounded by quotes', () => { expect( splitTarget('project:"other:other":configuration', projectGraph) ).toEqual(['project', 'other:other', 'configuration']); - }); - it('should targets that contain colons when not provided graph but surrounded by quotes', () => { - expect( - splitTarget('project:"other:other":configuration', { - nodes: {}, - dependencies: {}, - } as ProjectGraph) - ).toEqual(['project', 'other:other', 'configuration']); + expect(splitTarget('project:"other:other"', projectGraph)).toEqual([ + 'project', + 'other:other', + ]); }); });