Skip to content

Commit

Permalink
feat(core): allow dependsOn to accept a single project dependency (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
AgentEnder authored Apr 10, 2023
1 parent 7989fac commit f2f6e35
Show file tree
Hide file tree
Showing 11 changed files with 488 additions and 123 deletions.
67 changes: 67 additions & 0 deletions docs/shared/reference/project-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ result in `mylib`'s dependencies being built as well.

You can also express the same configuration using:

{% tabs %}
{% tab label="Version < 16" %}

```json
"build": {
"dependsOn": [{ "projects": "dependencies", "target": "build" }]
Expand All @@ -285,8 +288,26 @@ You can also express the same configuration using:
}
```

{% /tab %}
{% tab label="Version 16+" %}

```json
"build": {
"dependsOn": [{ "projects": "{dependencies}", "target": "build" }]
},
"test": {
"dependsOn": [{ "projects": "{self}", "target": "build" }]
}
```

{% /tab %}
{% /tabs %}

With the expanded syntax, you also have a third option available to configure how to handle the params passed to the target. You can either forward them or you can ignore them (default).

{% tabs %}
{% tab label="Version < 16" %}

```json
"build": {
// forward params passed to this target to the dependency targets
Expand All @@ -302,15 +323,61 @@ With the expanded syntax, you also have a third option available to configure ho
}
```

{% /tab %}
{% tab label="Version 16+" %}

```json
"build": {
// forward params passed to this target to the dependency targets
"dependsOn": [{ "projects": "{dependencies}", "target": "build", "params": "forward" }]
},
"test": {
// ignore params passed to this target, won't be forwarded to the dependency targets
"dependsOn": [{ "projects": "{dependencies}", "target": "build", "params": "ignore" }]
}
"lint": {
// ignore params passed to this target, won't be forwarded to the dependency targets
"dependsOn": [{ "projects": "{dependencies}", "target": "build" }]
}
```

{% /tab %}
{% /tabs %}

Obviously this also works when defining a relation for the target of the project itself using `"projects": "self"`:

{% tabs %}
{% tab label="Version < 16" %}

```json
"build": {
// forward params passed to this target to the project target
"dependsOn": [{ "projects": "self", "target": "pre-build", "params": "forward" }]
}
```

{% /tab %}
{% tab label="Version 16+" %}

```json
"build": {
// forward params passed to this target to the project target
"dependsOn": [{ "projects": "{self}", "target": "pre-build", "params": "forward" }]
}
```

{% /tab %}
{% /tabs %}

Additionally, when using the expanded object syntax, you can specify individual projects in version 16 or greater.

```json
"build": {
// Run is-even:pre-build and is-odd:pre-build before this target
"dependsOn": [{ "projects": ["is-even", "is-odd"], "target": "pre-build" }]
}
```

This configuration is usually not needed. Nx comes with reasonable defaults (imported in `nx.json`) which implement the
configuration above.

Expand Down
6 changes: 6 additions & 0 deletions packages/nx/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
"version": "16.0.0-beta.0",
"description": "Remove @nrwl/cli.",
"implementation": "./src/migrations/update-16-0-0/remove-nrwl-cli"
},
"16.0.0-tokens-for-depends-on": {
"cli": "nx",
"version": "16.0.0-beta.0",
"description": "Replace `dependsOn.projects` with {self} or {dependencies} tokens so that it matches the new expected formatting.",
"implementation": "./src/migrations/update-16-0-0/update-depends-on-to-tokens"
}
}
}
16 changes: 13 additions & 3 deletions packages/nx/schemas/nx-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,19 @@
"type": "object",
"properties": {
"projects": {
"type": "string",
"description": "The projects that the targets belong to.",
"enum": ["self", "dependencies"]
"oneOf": [
{
"type": "string",
"description": "{self}, {dependencies}, or a project name."
},
{
"type": "array",
"description": "An array of project specifiers: {self}, {dependencies}, or a project name.",
"items": {
"type": "string"
}
}
]
},
"target": {
"type": "string",
Expand Down
16 changes: 13 additions & 3 deletions packages/nx/schemas/project-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,19 @@
"type": "object",
"properties": {
"projects": {
"type": "string",
"description": "The projects that the targets belong to.",
"enum": ["self", "dependencies"]
"oneOf": [
{
"type": "string",
"description": "{self}, {dependencies}, or a project name."
},
{
"type": "array",
"description": "An array of project specifiers: {self}, {dependencies}, or a project name.",
"items": {
"type": "string"
}
}
]
},
"target": {
"type": "string",
Expand Down
16 changes: 13 additions & 3 deletions packages/nx/schemas/workspace-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,19 @@
"type": "object",
"properties": {
"projects": {
"type": "string",
"description": "The projects that the targets belong to.",
"enum": ["self", "dependencies"]
"oneOf": [
{
"type": "string",
"description": "{self}, {dependencies}, or a project name."
},
{
"type": "array",
"description": "An array of project specifiers: {self}, {dependencies}, or a project name.",
"items": {
"type": "string"
}
}
]
},
"target": {
"type": "string",
Expand Down
11 changes: 7 additions & 4 deletions packages/nx/src/config/workspace-json-project-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,15 @@ export interface ProjectConfiguration {

export interface TargetDependencyConfig {
/**
* This the projects that the targets belong to
* A list of projects that have `target`. Supports project names or two special values:
*
* 'self': This target depends on another target of the same project
* 'deps': This target depends on targets of the projects of it's deps.
* - '{self}': This target depends on another target of the same project
* - '{dependencies}': This target depends on targets of the projects of it's deps.
*
* The special values {self}/{dependencies} should be preferred - they prevent cases where a project
* that needs to be built is missed.
*/
projects: 'self' | 'dependencies';
projects: string[] | string;

/**
* The name of the target
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {
addProjectConfiguration,
getProjects,
readNxJson,
readProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { Tree } from '../../generators/tree';

import update from './update-depends-on-to-tokens';
import { updateJson, writeJson } from 'nx/src/devkit-exports';
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';

describe('update-depends-on-to-tokens', () => {
it('should update nx.json', async () => {
const tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'nx.json', (json) => {
json.targetDefaults = {
build: {
dependsOn: [
{
projects: 'self',
},
],
},
test: {
dependsOn: [
{
projects: 'dependencies',
},
],
},
other: {
dependsOn: ['^deps'],
},
};
return json;
});
await update(tree);
const nxJson = readNxJson(tree);
const build = nxJson.targetDefaults.build.dependsOn[0] as any;
const test = nxJson.targetDefaults.test.dependsOn[0] as any;
expect(build.projects).toEqual('{self}');
expect(test.projects).toEqual('{dependencies}');
expect(nxJson.targetDefaults.other.dependsOn).toEqual(['^deps']);
});

it('should update project configurations', async () => {
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'proj1', {
root: 'proj1',
targets: {
build: {
dependsOn: [
{
projects: 'self',
target: 'build',
},
],
},
test: {
dependsOn: [
{
projects: 'dependencies',
target: 'test',
},
],
},
other: {
dependsOn: ['^deps'],
},
},
});
await update(tree);
const project = readProjectConfiguration(tree, 'proj1');
const build = project.targets.build.dependsOn[0] as any;
const test = project.targets.test.dependsOn[0] as any;
expect(build.projects).toEqual('{self}');
expect(test.projects).toEqual('{dependencies}');
expect(project.targets.other.dependsOn).toEqual(['^deps']);
});

it('should not throw on nulls', async () => {
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'proj1', {
root: 'proj1',
});
addProjectConfiguration(tree, 'proj2', {
root: 'proj2',
targets: {
build: {},
},
});
writeJson(tree, 'nx.json', {});
let promise = update(tree);
await expect(promise).resolves.toBeUndefined();
writeJson(tree, 'nx.json', {
targetDefaults: {
build: {},
},
});
promise = update(tree);
await expect(promise).resolves.toBeUndefined();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
getProjects,
readNxJson,
updateNxJson,
updateProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { Tree } from '../../generators/tree';

export default async function (tree: Tree) {
updateDependsOnInsideNxJson(tree);

const projectsConfigurations = getProjects(tree);
for (const [projectName, projectConfiguration] of projectsConfigurations) {
let projectChanged = false;
for (const [targetName, targetConfiguration] of Object.entries(
projectConfiguration.targets ?? {}
)) {
for (const dependency of targetConfiguration.dependsOn ?? []) {
if (typeof dependency !== 'string') {
if (dependency.projects === 'self') {
dependency.projects = '{self}';
projectChanged = true;
} else if (dependency.projects === 'dependencies') {
dependency.projects = '{dependencies}';
projectChanged = true;
}
}
}
}
if (projectChanged) {
updateProjectConfiguration(tree, projectName, projectConfiguration);
}
}
}
function updateDependsOnInsideNxJson(tree: Tree) {
const nxJson = readNxJson(tree);
let nxJsonChanged = false;
for (const [target, defaults] of Object.entries(
nxJson?.targetDefaults ?? {}
)) {
for (const dependency of defaults.dependsOn ?? []) {
if (typeof dependency !== 'string') {
if (dependency.projects === 'self') {
dependency.projects = '{self}';
nxJsonChanged = true;
} else if (dependency.projects === 'dependencies') {
dependency.projects = '{dependencies}';
nxJsonChanged = true;
}
}
}
}
if (nxJsonChanged) {
updateNxJson(tree, nxJson);
}
}
Loading

1 comment on commit f2f6e35

@vercel
Copy link

@vercel vercel bot commented on f2f6e35 Apr 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-nrwl.vercel.app
nx-five.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx.dev

Please sign in to comment.