Skip to content

Commit e409e9e

Browse files
authored
Merge branch 'master' into feat/add-time-to-post-hook
2 parents 7573182 + 65fab5b commit e409e9e

File tree

5 files changed

+125
-30
lines changed

5 files changed

+125
-30
lines changed

packages/nx/src/command-line/run/run-one.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ const targetAliases = {
147147
t: 'test',
148148
};
149149

150+
const PROJECT_TARGET_CONFIG = 'project:target:configuration';
151+
150152
export function parseRunOneOptions(
151153
cwd: string,
152154
parsedArgs: { [k: string]: any },
@@ -164,29 +166,28 @@ export function parseRunOneOptions(
164166
let target;
165167
let configuration;
166168

167-
if (parsedArgs['project:target:configuration']?.indexOf(':') > -1) {
169+
if (parsedArgs[PROJECT_TARGET_CONFIG]?.lastIndexOf(':') > 0) {
168170
// run case
169171
[project, target, configuration] = splitTarget(
170-
parsedArgs['project:target:configuration'],
172+
parsedArgs[PROJECT_TARGET_CONFIG],
171173
projectGraph
172174
);
173-
// this is to account for "nx npmsript:dev"
175+
// this is to account for "nx npmscript:dev"
174176
if (project && !target && defaultProjectName) {
175177
target = project;
176178
project = defaultProjectName;
177179
}
178180
} else if (parsedArgs.target) {
179181
target = parsedArgs.target;
180-
} else if (parsedArgs['project:target:configuration']) {
182+
} else if (parsedArgs[PROJECT_TARGET_CONFIG]) {
181183
// If project:target:configuration exists but has no colon, check if it's a project with run target
182184
if (
183-
projectGraph.nodes[parsedArgs['project:target:configuration']]?.data
184-
?.targets?.run
185+
projectGraph.nodes[parsedArgs[PROJECT_TARGET_CONFIG]]?.data?.targets?.run
185186
) {
186187
target = 'run';
187-
project = parsedArgs['project:target:configuration'];
188+
project = parsedArgs[PROJECT_TARGET_CONFIG];
188189
} else {
189-
target = parsedArgs['project:target:configuration'];
190+
target = parsedArgs[PROJECT_TARGET_CONFIG];
190191
}
191192
}
192193
if (parsedArgs.project) {
@@ -210,7 +211,7 @@ export function parseRunOneOptions(
210211

211212
const res = { project, target, configuration, parsedArgs };
212213
delete parsedArgs['c'];
213-
delete parsedArgs['project:target:configuration'];
214+
delete parsedArgs[PROJECT_TARGET_CONFIG];
214215
delete parsedArgs['configuration'];
215216
delete parsedArgs['prod'];
216217
delete parsedArgs['project'];

packages/nx/src/tasks-runner/utils.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@ describe('utils', () => {
478478
type: 'app',
479479
data: {
480480
root: 'libs/project',
481+
targets: {
482+
build: {},
483+
},
481484
},
482485
},
483486
},

packages/nx/src/tasks-runner/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { findMatchingProjects } from '../utils/find-matching-projects';
2222
import { isGlobPattern } from '../utils/globs';
2323
import { joinPathFragments } from '../utils/path';
2424
import { serializeOverridesIntoCommandLine } from '../utils/serialize-overrides-into-command-line';
25-
import { splitByColons } from '../utils/split-target';
25+
import { splitTarget } from '../utils/split-target';
2626
import { workspaceRoot } from '../utils/workspace-root';
2727
import { isTuiEnabled } from './is-tui-enabled';
2828

@@ -167,7 +167,9 @@ export function readProjectAndTargetFromTargetString(
167167
projects: Record<string, ProjectGraphProjectNode>
168168
): { projects?: string[]; target: string } {
169169
// Support for both `project:target` and `target:with:colons` syntax
170-
const [maybeProject, ...segments] = splitByColons(targetString);
170+
const [maybeProject, ...segments] = splitTarget(targetString, {
171+
nodes: projects,
172+
} as ProjectGraph);
171173

172174
if (!segments.length) {
173175
// if no additional segments are provided, then the string references

packages/nx/src/utils/split-target.spec.ts

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,59 @@ describe('splitTarget', () => {
1818
},
1919
type: 'app',
2020
});
21+
builder.addNode({
22+
name: ':utils:common',
23+
data: {
24+
root: '',
25+
targets: {
26+
target: {
27+
configurations: {
28+
prod: {},
29+
dev: {},
30+
},
31+
},
32+
'target:with:colon': {},
33+
},
34+
},
35+
type: 'app',
36+
});
37+
builder.addNode({
38+
name: ':utils:common:test',
39+
data: {
40+
root: '',
41+
targets: {
42+
prod: {},
43+
},
44+
},
45+
type: 'app',
46+
});
2147

2248
projectGraph = builder.getUpdatedProjectGraph();
2349
});
2450

2551
it('should support only project', () => {
2652
expect(splitTarget('project', projectGraph)).toEqual(['project']);
53+
expect(splitTarget(':utils:common', projectGraph)).toEqual([
54+
':utils:common',
55+
]);
2756
});
2857

29-
it('should project:target', () => {
58+
it('should split project:target', () => {
3059
expect(splitTarget('project:target', projectGraph)).toEqual([
3160
'project',
3261
'target',
3362
]);
3463
});
3564

36-
it('should project:target:configuration', () => {
65+
it('should split project:target:configuration', () => {
3766
expect(splitTarget('project:target:configuration', projectGraph)).toEqual([
3867
'project',
3968
'target',
4069
'configuration',
4170
]);
4271
});
4372

44-
it('should targets that contain colons when present in the graph', () => {
73+
it('should support targets that contain colons when present in the graph', () => {
4574
expect(
4675
splitTarget('project:target:target:configuration', projectGraph)
4776
).toEqual(['project', 'target:target', 'configuration']);
@@ -53,12 +82,24 @@ describe('splitTarget', () => {
5382
).toEqual(['project', 'other:other', 'configuration']);
5483
});
5584

56-
it('should targets that contain colons when not provided graph but surrounded by quotes', () => {
85+
it('should support projects with colons in the name', () => {
86+
expect(splitTarget(':utils:common:target', projectGraph)).toEqual([
87+
':utils:common',
88+
'target',
89+
]);
90+
});
91+
92+
it('should support projects and targets with colons in the name', () => {
5793
expect(
58-
splitTarget('project:"other:other":configuration', {
59-
nodes: {},
60-
dependencies: {},
61-
} as ProjectGraph)
62-
).toEqual(['project', 'other:other', 'configuration']);
94+
splitTarget(':utils:common:target:with:colon', projectGraph)
95+
).toEqual([':utils:common', 'target:with:colon']);
96+
});
97+
98+
it('should support projects with colons in the name and configuration', () => {
99+
expect(splitTarget(':utils:common:target:dev', projectGraph)).toEqual([
100+
':utils:common',
101+
'target',
102+
'dev',
103+
]);
63104
});
64105
});

packages/nx/src/utils/split-target.ts

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,68 @@
11
import { ProjectGraph } from '../config/project-graph';
22

3+
function findMatchingSegments(
4+
s: string,
5+
projectGraph: ProjectGraph
6+
): [string, string?, string?] | undefined {
7+
const projectNames = Object.keys(projectGraph.nodes);
8+
// return project if matching
9+
if (projectNames.includes(s)) {
10+
return [s];
11+
}
12+
if (!s.includes(':')) {
13+
return;
14+
}
15+
for (const projectName of projectNames) {
16+
for (const [targetName, targetConfig] of Object.entries(
17+
projectGraph.nodes[projectName].data.targets || {}
18+
)) {
19+
if (s === `${projectName}:${targetName}`) {
20+
return [projectName, targetName];
21+
}
22+
if (targetConfig.configurations) {
23+
for (const configurationName of Object.keys(
24+
targetConfig.configurations
25+
)) {
26+
if (s === `${projectName}:${targetName}:${configurationName}`) {
27+
return [projectName, targetName, configurationName];
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
335
export function splitTarget(
436
s: string,
537
projectGraph: ProjectGraph
638
): [project: string, target?: string, configuration?: string] {
7-
let [project, ...segments] = splitByColons(s);
8-
const validTargets = projectGraph.nodes[project]
9-
? projectGraph.nodes[project].data.targets
10-
: {};
11-
const validTargetNames = new Set(Object.keys(validTargets ?? {}));
39+
const matchingSegments = findMatchingSegments(s, projectGraph);
40+
if (matchingSegments) {
41+
return matchingSegments;
42+
}
43+
if (s.indexOf(':') > 0) {
44+
let [project, ...segments] = splitByColons(s);
45+
// if only configuration cannot be matched, try to match project and target
46+
const configuration = segments[segments.length - 1];
47+
const rest = s.slice(0, -(configuration.length + 1));
48+
const matchingSegments = findMatchingSegments(rest, projectGraph);
49+
if (matchingSegments && matchingSegments.length === 2) {
50+
return [...(matchingSegments as [string, string]), configuration];
51+
}
52+
// no project-target pair found, do the naive matching
53+
const validTargets = projectGraph.nodes[project]
54+
? projectGraph.nodes[project].data.targets
55+
: {};
56+
const validTargetNames = new Set(Object.keys(validTargets ?? {}));
1257

13-
return [project, ...groupJointSegments(segments, validTargetNames)] as [
14-
string,
15-
string?,
16-
string?
17-
];
58+
return [project, ...groupJointSegments(segments, validTargetNames)] as [
59+
string,
60+
string?,
61+
string?
62+
];
63+
}
64+
// we don't know what to do with the string, return as is
65+
return [s];
1866
}
1967

2068
function groupJointSegments(segments: string[], validTargetNames: Set<string>) {

0 commit comments

Comments
 (0)