diff --git a/commands/run/index.js b/commands/run/index.js index 2fefae95c8..68d890c687 100644 --- a/commands/run/index.js +++ b/commands/run/index.js @@ -219,15 +219,10 @@ class RunCommand extends Command { } prepNxOptions() { - const { readNxJson } = require("nx/src/config/configuration"); - const nxJson = readNxJson(); const nxJsonExists = existsSync(path.join(this.project.rootPath, "nx.json")); - const useParallel = this.options.parallel && !nxJsonExists; - const targetDependenciesAreDefined = - Object.keys(nxJson.targetDependencies || nxJson.targetDefaults || {}).length > 0; const targetDependencies = - this.toposort && !useParallel && !targetDependenciesAreDefined + this.toposort && !this.options.parallel && !nxJsonExists ? { [this.script]: [ { @@ -250,7 +245,7 @@ class RunCommand extends Command { * To match lerna's own behavior (via pMap's default concurrency), we set parallel to a very large number if * the flag has been set (we can't use Infinity because that would cause issues with the task runner). */ - parallel: useParallel ? 999 : this.concurrency, + parallel: this.options.parallel && !nxJsonExists ? 999 : this.concurrency, nxBail: this.bail, nxIgnoreCycles: !this.options.rejectCycles, skipNxCache: this.options.skipNxCache, @@ -261,10 +256,24 @@ class RunCommand extends Command { if (nxJsonExists) { this.logger.verbose(this.name, "nx.json was found. Task dependencies will be automatically included."); - if (this.options.parallel || this.options.sort !== undefined || this.options.includeDependencies) { + if (this.options.parallel || this.options.sort !== undefined) { this.logger.warn( this.name, - `"parallel", "sort", "no-sort", and "include-dependencies" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details.` + `"parallel", "sort", and "no-sort" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details.` + ); + } + + if (this.options.includeDependencies) { + this.logger.info( + this.name, + `Using the "include-dependencies" option when nx.json exists will include both task dependencies detected by Nx and project dependencies detected by Lerna. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks#--include-dependencies for details.` + ); + } + + if (this.options.ignore) { + this.logger.info( + this.name, + `Using the "ignore" option when nx.json exists will exclude only tasks that are not determined to be required by Nx. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks#--ignore for details.` ); } } else { diff --git a/e2e/tests/lerna-run/lerna-run-nx-include-dependencies.spec.ts b/e2e/tests/lerna-run/lerna-run-nx-include-dependencies.spec.ts index fc29bcb16e..9cd5a8f03d 100644 --- a/e2e/tests/lerna-run/lerna-run-nx-include-dependencies.spec.ts +++ b/e2e/tests/lerna-run/lerna-run-nx-include-dependencies.spec.ts @@ -89,10 +89,8 @@ describe("lerna-run-nx-include-dependencies", () => { > package-X:print-name --silent - > package-X@0.0.0 print-name > echo test-package-X "--silent" - test-package-X --silent @@ -111,14 +109,45 @@ describe("lerna-run-nx-include-dependencies", () => { }); describe("with nx enabled and with nx.json", () => { - it("should include dependencies by default", async () => { + it("should not include package dependencies by default", async () => { await fixture.addNxToWorkspace(); const output = await fixture.lerna("run print-name --scope package-3 -- --silent"); expect(output.combinedOutput).toMatchInlineSnapshot(` - > Lerna (powered by Nx) Running target print-name for project package-X and 2 task(s) it depends on +> package-X:print-name --silent + +> package-X@0.0.0 print-name +> echo test-package-X "--silent" +test-package-X --silent + + + + > Lerna (powered by Nx) Successfully ran target print-name for project package-X + + +lerna notice cli v999.9.9-e2e.0 +lerna verb rootPath /tmp/lerna-e2e/lerna-run-nx-include-dependencies/lerna-workspace +lerna notice filter including "package-X" +lerna info filter [ 'package-X' ] +lerna verb run nx.json was found. Task dependencies will be automatically included. + +`); + }); + + it("should include package dependencies with --include-dependencies", async () => { + await fixture.addNxToWorkspace(); + + const output = await fixture.lerna("run print-name --scope package-3 --include-dependencies"); + + expect(output.combinedOutput).toMatchInlineSnapshot(` + + > Lerna (powered by Nx) Running target print-name for 3 project(s): + + - package-X + - package-X + - package-X @@ -138,13 +167,77 @@ test-package-X test-package-X -> package-X:print-name --silent +> package-X:print-name > package-X@0.0.0 print-name -> echo test-package-X "--silent" +> echo test-package-X -test-package-X --silent +test-package-X + + + + > Lerna (powered by Nx) Successfully ran target print-name for 3 projects + + +lerna notice cli v999.9.9-e2e.0 +lerna verb rootPath /tmp/lerna-e2e/lerna-run-nx-include-dependencies/lerna-workspace +lerna notice filter including "package-X" +lerna notice filter including dependencies +lerna info filter [ 'package-X' ] +lerna verb run nx.json was found. Task dependencies will be automatically included. +lerna info run Using the "include-dependencies" option when nx.json exists will include both task dependencies detected by Nx and project dependencies detected by Lerna. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks#--include-dependencies for details. + +`); + }); + }); + + describe("with explicit Nx task dependencies", () => { + it("should include dependencies", async () => { + await fixture.addNxToWorkspace(); + + await fixture.updateJson("packages/package-3/package.json", (json) => ({ + ...json, + nx: { + targets: { + "print-name": { + inputs: [], + outputs: [], + dependsOn: ["^print-name"], + }, + }, + }, + })); + + const output = await fixture.lerna("run print-name --scope package-3"); + + expect(output.combinedOutput).toMatchInlineSnapshot(` + + > Lerna (powered by Nx) Running target print-name for project package-X and 2 task(s) it depends on + + + +> package-X:print-name + + +> package-X@0.0.0 print-name +> echo test-package-X + +test-package-X + +> package-X:print-name + + +> package-X@0.0.0 print-name +> echo test-package-X + +test-package-X + +> package-X:print-name + +> package-X@0.0.0 print-name +> echo test-package-X +test-package-X @@ -157,6 +250,68 @@ lerna notice filter including "package-X" lerna info filter [ 'package-X' ] lerna verb run nx.json was found. Task dependencies will be automatically included. +`); + }); + + it("with --ignore should still include dependencies", async () => { + await fixture.addNxToWorkspace(); + + await fixture.updateJson("packages/package-3/package.json", (json) => ({ + ...json, + nx: { + targets: { + "print-name": { + inputs: [], + outputs: [], + dependsOn: ["^print-name"], + }, + }, + }, + })); + + const output = await fixture.lerna("run print-name --scope package-3 --ignore package-1"); + + expect(output.combinedOutput).toMatchInlineSnapshot(` + + > Lerna (powered by Nx) Running target print-name for project package-X and 2 task(s) it depends on + + + +> package-X:print-name + + +> package-X@0.0.0 print-name +> echo test-package-X + +test-package-X + +> package-X:print-name + + +> package-X@0.0.0 print-name +> echo test-package-X + +test-package-X + +> package-X:print-name + +> package-X@0.0.0 print-name +> echo test-package-X +test-package-X + + + + > Lerna (powered by Nx) Successfully ran target print-name for project package-X + + +lerna notice cli v999.9.9-e2e.0 +lerna verb rootPath /tmp/lerna-e2e/lerna-run-nx-include-dependencies/lerna-workspace +lerna notice filter including "package-X" +lerna notice filter excluding "package-X" +lerna info filter [ 'package-X', '!package-X' ] +lerna verb run nx.json was found. Task dependencies will be automatically included. +lerna info run Using the "ignore" option when nx.json exists will exclude only tasks that are not determined to be required by Nx. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks#--ignore for details. + `); }); }); diff --git a/e2e/tests/lerna-run/lerna-run-nx-incompatible-options.spec.ts b/e2e/tests/lerna-run/lerna-run-nx-incompatible-options.spec.ts index f7e462d34c..faed524a89 100644 --- a/e2e/tests/lerna-run/lerna-run-nx-incompatible-options.spec.ts +++ b/e2e/tests/lerna-run/lerna-run-nx-incompatible-options.spec.ts @@ -145,7 +145,7 @@ test-package-X lerna notice cli v999.9.9-e2e.0 -lerna WARN run "parallel", "sort", "no-sort", and "include-dependencies" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details. +lerna WARN run "parallel", "sort", and "no-sort" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details. `); }); @@ -193,7 +193,7 @@ test-package-X lerna notice cli v999.9.9-e2e.0 -lerna WARN run "parallel", "sort", "no-sort", and "include-dependencies" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details. +lerna WARN run "parallel", "sort", and "no-sort" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details. `); }); @@ -241,7 +241,7 @@ test-package-X lerna notice cli v999.9.9-e2e.0 -lerna WARN run "parallel", "sort", "no-sort", and "include-dependencies" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details. +lerna WARN run "parallel", "sort", and "no-sort" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details. `); }); @@ -290,7 +290,7 @@ test-package-X lerna notice cli v999.9.9-e2e.0 lerna notice filter including dependencies -lerna WARN run "parallel", "sort", "no-sort", and "include-dependencies" are ignored when nx.json exists. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks for details. +lerna info run Using the "include-dependencies" option when nx.json exists will include both task dependencies detected by Nx and project dependencies detected by Lerna. See https://lerna.js.org/docs/recipes/using-lerna-powered-by-nx-to-run-tasks#--include-dependencies for details. `); }); diff --git a/e2e/tests/lerna-run/lerna-run.spec.ts b/e2e/tests/lerna-run/lerna-run.spec.ts index b773908ebe..d7903584f5 100644 --- a/e2e/tests/lerna-run/lerna-run.spec.ts +++ b/e2e/tests/lerna-run/lerna-run.spec.ts @@ -396,10 +396,8 @@ lerna notice cli v999.9.9-e2e.0 > package-X:print-name-run-one-only - > package-X@0.0.0 print-name-run-one-only > echo test-package-X-run-one-only - test-package-X-run-one-only @@ -419,10 +417,8 @@ lerna notice cli v999.9.9-e2e.0 > package-X:"print:name:run-one-only" - > package-X@0.0.0 print:name:run-one-only > echo test-package-X-run-one-only-with-colon - test-package-X-run-one-only-with-colon diff --git a/website/docs/lerna-and-nx.md b/website/docs/lerna-and-nx.md index 629921ba52..9b87780d76 100644 --- a/website/docs/lerna-and-nx.md +++ b/website/docs/lerna-and-nx.md @@ -8,7 +8,7 @@ type: explainer Nrwl (the company behind the open source build system Nx) has taken over [stewardship of Lerna](https://dev.to/nrwl/lerna-is-dead-long-live-lerna-3jal). [Nx](https://nx.dev) is a build system developed by ex-Googlers and utilizes many of the techniques used by internal Google tools. Lerna v5 is the first release under this new stewardship, updating outdated packages and starting to do some cleanup on the repository itself. Starting with v5.1+, Lerna comes with the new possibility to integrate Nx and defer a lot of the task scheduling work to it. -The following is a high level overview of what each tool provides. Note that all of the existing Lerna commands will continue to function as they have. Adding Nx or Nx Cloud simply improves what you're already doing. +The following is a high level overview of what each tool provides. Note that all of the existing Lerna commands will continue to function as they have. Adding Nx or Nx Cloud simply improves what you're already doing. ## Lerna @@ -27,7 +27,7 @@ Free and open source - `npm install lerna` - `npx lerna init` ------ +--- ## Nx @@ -50,7 +50,11 @@ Free and open source - Set `"useNx": true` in `lerna.json` - Continue using Lerna as usual ------- +:::note +When Lerna is set to use Nx and detects `nx.json` in the workspace, it will defer to Nx to detect task dependencies. Some options for `lerna run` will behave differently. See [Using Lerna (Powered by Nx) to Run Tasks](./recipes/using-lerna-powered-by-nx-to-run-tasks) for more details. +::: + +--- ## Nx Cloud @@ -63,7 +67,7 @@ Free and open source Free for open source projects -For closed source repositories, the first 500 computation hours per month are free. Most repositories do not exceed this limit. $1 per computation hour after that. +For closed source repositories, the first 500 computation hours per month are free. Most repositories do not exceed this limit. $1 per computation hour after that. ### Set up diff --git a/website/docs/recipes/using-lerna-powered-by-nx-to-run-tasks.md b/website/docs/recipes/using-lerna-powered-by-nx-to-run-tasks.md index fd64e91535..2f685fa42a 100644 --- a/website/docs/recipes/using-lerna-powered-by-nx-to-run-tasks.md +++ b/website/docs/recipes/using-lerna-powered-by-nx-to-run-tasks.md @@ -27,7 +27,11 @@ If you want to limit the concurrency of tasks, you can still use the [concurrenc Lerna by itself does not have knowledge of which tasks depend on others, so it defaults to excluding tasks on dependent projects when using [filter options](https://github.com/lerna/lerna/tree/6cb8ab2d4af7ce25c812e8fb05cd04650105705f/core/filter-options#lernafilter-options) and relies on `--include-dependencies` to manually specify that dependent projects' tasks should be included. -This is no longer a problem when Lerna uses Nx to run tasks. Nx, utilizing its [task graph](https://nx.dev/concepts/mental-model#the-task-graph), will automatically run dependent tasks first when necessary, so `--include-dependencies` is obsolete. +This is no longer a problem when Lerna uses Nx to run tasks. Nx, utilizing its [task graph](https://nx.dev/concepts/mental-model#the-task-graph), will automatically run dependent tasks first when necessary, so `--include-dependencies` is obsolete. However, it can still be used to include project dependencies that Lerna detects but Nx does not deem necessary and would otherwise exclude. + +### `--ignore` + +When used with Nx, `--ignore` will never cause `lerna run` to exclude any tasks that are deemed to be required by the Nx [task graph](https://nx.dev/concepts/mental-model#the-task-graph). :::tip