Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): support specific project dependency in dependsOn with string syntax #16674

Merged
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
54 changes: 54 additions & 0 deletions packages/nx/src/tasks-runner/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
expandDependencyConfigSyntaxSugar,
getOutputsForTargetAndConfiguration,
transformLegacyOutputs,
validateOutputs,
Expand Down Expand Up @@ -397,4 +398,57 @@ describe('utils', () => {
expect(result).toEqual(['{projectRoot}/dist']);
}
});

describe('expandDependencyConfigSyntaxSugar', () => {
it('should expand syntax for simple target names', () => {
const result = expandDependencyConfigSyntaxSugar('build', {
dependencies: {},
nodes: {},
});
expect(result).toEqual({
target: 'build',
});
});

it('should expand syntax for simple target names targetting dependencies', () => {
const result = expandDependencyConfigSyntaxSugar('^build', {
dependencies: {},
nodes: {},
});
expect(result).toEqual({
target: 'build',
dependencies: true,
});
});

it('should expand syntax for strings like project:target if project is a valid project', () => {
const result = expandDependencyConfigSyntaxSugar('project:build', {
dependencies: {},
nodes: {
project: {
name: 'project',
type: 'app',
data: {
root: 'libs/project',
files: [],
},
},
},
});
expect(result).toEqual({
target: 'build',
projects: ['project'],
});
});

it('should expand syntax for strings like target:with:colons', () => {
const result = expandDependencyConfigSyntaxSugar('target:with:colons', {
dependencies: {},
nodes: {},
});
expect(result).toEqual({
target: 'target:with:colons',
});
});
});
});
51 changes: 34 additions & 17 deletions packages/nx/src/tasks-runner/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { NxJsonConfiguration } from '../config/nx-json';
import { joinPathFragments } from '../utils/path';
import { isRelativePath } from '../utils/fileutils';
import { serializeOverridesIntoCommandLine } from '../utils/serialize-overrides-into-command-line';
import { splitByColons, splitTarget } from '../utils/split-target';

export function getCommandAsString(execCommand: string, task: Task) {
const args = getPrintableCommandArgsForTask(task);
Expand All @@ -26,10 +27,14 @@ export function getDependencyConfigs(
defaultDependencyConfigs: Record<string, (TargetDependencyConfig | string)[]>,
projectGraph: ProjectGraph
): TargetDependencyConfig[] | undefined {
const dependencyConfigs = expandDependencyConfigSyntaxSugar(
const dependencyConfigs = (
projectGraph.nodes[project].data?.targets[target]?.dependsOn ??
defaultDependencyConfigs[target] ??
[]
defaultDependencyConfigs[target] ??
[]
).map((config) =>
typeof config === 'string'
? expandDependencyConfigSyntaxSugar(config, projectGraph)
: config
);
for (const dependencyConfig of dependencyConfigs) {
const specifiers =
Expand Down Expand Up @@ -64,20 +69,32 @@ export function getDependencyConfigs(
return dependencyConfigs;
}

function expandDependencyConfigSyntaxSugar(
deps: (TargetDependencyConfig | string)[]
): TargetDependencyConfig[] {
return deps.map((d) => {
if (typeof d === 'string') {
if (d.startsWith('^')) {
return { dependencies: true, target: d.substring(1) };
} else {
return { target: d };
}
} else {
return d;
}
});
export function expandDependencyConfigSyntaxSugar(
dependencyConfigString: string,
graph: ProjectGraph
): TargetDependencyConfig {
const [dependencies, targetString] = dependencyConfigString.startsWith('^')
? [true, dependencyConfigString.substring(1)]
: [false, dependencyConfigString];

// Support for `project:target` syntax doesn't make sense for
// dependencies, so we only support `target` syntax for dependencies.
if (dependencies) {
return {
target: targetString,
dependencies: true,
};
}

// Support for both `project:target` and `target:with:colons` syntax
const [maybeProject, ...segments] = splitByColons(targetString);
return {
// Only the first segment could be a project. If it is, the rest is a target.
// If its not, then the whole targetString was a target with colons in its name.
target: maybeProject in graph.nodes ? segments.join(':') : targetString,
// If the first segment is a project, then we have a specific project. Otherwise, we don't.
projects: maybeProject in graph.nodes ? [maybeProject] : undefined,
};
}

export function getOutputs(
Expand Down
2 changes: 1 addition & 1 deletion packages/nx/src/utils/split-target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function groupJointSegments(segments: string[], validTargetNames: Set<string>) {
return segments;
}

function splitByColons(s: string) {
export function splitByColons(s: string) {
const parts = [] as string[];
let currentPart = '';
for (let i = 0; i < s.length; ++i) {
Expand Down