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: add experimental support to run tasks via Nx #3139

Merged
merged 1 commit into from
May 25, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 28 additions & 3 deletions commands/run/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ $ lerna run build
$ lerna run --parallel watch
```

Run an [npm script](https://docs.npmjs.com/misc/scripts) in each package that contains that script. A double-dash (`--`) is necessary to pass dashed arguments to the script execution.
Run an [npm script](https://docs.npmjs.com/misc/scripts) in each package that contains that script. A double-dash (`--`)
is necessary to pass dashed arguments to the script execution.

## Options

Expand Down Expand Up @@ -57,7 +58,9 @@ $ lerna run watch --stream

### `--parallel`

Similar to `--stream`, but completely disregards concurrency and topological sorting, running a given command or script immediately in all matching packages with prefixed streaming output. This is the preferred flag for long-running processes such as `npm run watch` run over many packages.
Similar to `--stream`, but completely disregards concurrency and topological sorting, running a given command or script
vsavkin marked this conversation as resolved.
Show resolved Hide resolved
immediately in all matching packages with prefixed streaming output. This is the preferred flag for long-running
processes such as `npm run watch` run over many packages.

```sh
$ lerna run watch --parallel
Expand Down Expand Up @@ -101,8 +104,30 @@ $ lerna run build --profile

### `--profile-location <location>`

You can provide a custom location for the performance profile output. The path provided will be resolved relative to the current working directory.
You can provide a custom location for the performance profile output. The path provided will be resolved relative to the
current working directory.

```sh
$ lerna run build --profile --profile-location=logs/profile/
```

### `useNx` (experimental)

Enables integration with [Nx](https://nx.dev). Setting `"useNx": true` in `lerna.json` will tell Lerna to delegate
running tasks to Nx instead of using `p-map` and `p-queue`. This only works if Nx is installed and `nx.json` is present.
vsavkin marked this conversation as resolved.
Show resolved Hide resolved

Example of `nx.json`:

```json
{
"extends": "nx/presets/npm.json",
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build"]
}
}
}
}
```
4 changes: 4 additions & 0 deletions commands/run/__tests__/__fixtures__/powered-by-nx/lerna.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"version": "1.0.0",
"useNx": true
}
10 changes: 10 additions & 0 deletions commands/run/__tests__/__fixtures__/powered-by-nx/nx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"useDaemonProcess": false
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "powered-by-nx"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "package-1",
"version": "1.0.0",
"scripts": {
"fail": "exit 1",
"my-script": "echo package-1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "package-2",
"version": "1.0.0",
"scripts": {
"fail": "exit 1"
},
"dependencies": {
"package-1": "^1.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "package-3",
"version": "1.0.0",
"scripts": {
"my-script": "echo package-3"
},
"devDependencies": {
"package-2": "^1.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "package-4",
"version": "1.0.0",
"dependencies": {
"package-1": "^0.0.0"
}
}
44 changes: 44 additions & 0 deletions commands/run/__tests__/run-command.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,48 @@ describe("RunCommand", () => {
await expect(command).rejects.toThrow("Dependency cycles detected, you should fix these!");
});
});

// this is a temporary set of tests, which will be replaced by verdacio-driven tests
// once the required setup is fully set up
describe("in a repo powered by Nx", () => {
let testDir;
let collectedOutput = "";

beforeAll(async () => {
testDir = await initFixture("powered-by-nx");
process.env.NX_WORKSPACE_ROOT_PATH = testDir;
// eslint-disable-next-line global-require
const nxOutput = require("nx/src/utils/output");
nxOutput.output.writeToStdOut = (v) => {
collectedOutput = `${collectedOutput}\n${v}`;
};
jest.spyOn(process, "exit").mockImplementation((code) => {
if (code !== 0) {
throw new Error();
}
});
});

it("runs a script in packages", async () => {
collectedOutput = "";
await lernaRun(testDir)("my-script");
expect(collectedOutput).toContain("package-1");
expect(collectedOutput).toContain("package-3");
expect(collectedOutput).toContain("Successfully ran target");
});

it("runs a script only in scoped packages", async () => {
collectedOutput = "";
await lernaRun(testDir)("my-script", "--scope", "package-1");
expect(collectedOutput).toContain("package-1");
expect(collectedOutput).not.toContain("package-3");
});

it("does not run a script in ignored packages", async () => {
collectedOutput = "";
await lernaRun(testDir)("my-script", "--ignore", "package-@(2|3|4)");
expect(collectedOutput).toContain("package-1");
expect(collectedOutput).not.toContain("package-3");
});
});
});
41 changes: 33 additions & 8 deletions commands/run/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const { timer } = require("@lerna/timer");
const { runTopologically } = require("@lerna/run-topologically");
const { ValidationError } = require("@lerna/validation-error");
const { getFilteredPackages } = require("@lerna/filter-options");
const { performance } = require("perf_hooks");

module.exports = factory;

Expand Down Expand Up @@ -62,18 +63,22 @@ class RunCommand extends Command {
}

execute() {
this.logger.info(
"",
"Executing command in %d %s: %j",
this.count,
this.packagePlural,
this.joinedCommand
);
if (!this.options.useNx) {
this.logger.info(
"",
"Executing command in %d %s: %j",
this.count,
this.packagePlural,
this.joinedCommand
);
}

let chain = Promise.resolve();
const getElapsed = timer();

if (this.options.parallel) {
if (this.options.useNx) {
chain = chain.then(() => this.runScriptsUsingNx());
} else if (this.options.parallel) {
chain = chain.then(() => this.runScriptInPackagesParallel());
} else if (this.toposort) {
chain = chain.then(() => this.runScriptInPackagesTopological());
Expand Down Expand Up @@ -163,6 +168,26 @@ class RunCommand extends Command {
return chain;
}

runScriptsUsingNx() {
performance.mark("init-local");
// eslint-disable-next-line global-require,import/no-extraneous-dependencies,node/no-extraneous-require
const nxOutput = require("nx/src/utils/output");
nxOutput.output.cliName = "Lerna (powered by Nx)";
nxOutput.output.formatCommand = (message) => message.replace(":", " ");
if (this.options.ci) {
process.env.CI = "true";
}
// eslint-disable-next-line global-require,import/no-extraneous-dependencies,node/no-extraneous-require
const { runMany } = require("nx/src/command-line/run-many");
return runMany({
projects: this.packagesWithScript.map((p) => p.name).join(","),
target: this.script,
outputStyle: this.options.stream ? "stream" : "static",
parallel: this.options.concurrency,
_: this.args,
});
}

runScriptInPackagesParallel() {
return pMap(this.packagesWithScript, (pkg) => this.runScriptInPackageStreaming(pkg));
}
Expand Down