@lerna/publish
Version:
Publish packages in the current project
316 lines (315 loc) • 12.4 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var import_core = require("@lerna/core");
var import_fs_extra = require("fs-extra");
var import_p_map = __toESM(require("p-map"));
var import_path = __toESM(require("path"));
var import_perf_hooks = require("perf_hooks");
module.exports = function factory(argv) {
return new RunCommand(argv);
};
class RunCommand extends import_core.Command {
script;
args;
npmClient;
bail;
prefix;
get requiresGit() {
return false;
}
initialize() {
const { script, npmClient = "npm" } = this.options;
this.script = script;
this.args = this.options["--"] || [];
this.npmClient = npmClient;
if (!this.script) {
throw new import_core.ValidationError("ENOSCRIPT", "You must specify a lifecycle script to run");
}
if (this.argv.npmClient && this.options.useNx !== false) {
throw new import_core.ValidationError(
"run",
"The legacy task runner option `--npm-client` is not currently supported. Please open an issue on https://github.com/lerna/lerna if you require this feature."
);
}
if (Array.isArray(this.script) && this.options.useNx === false) {
throw new import_core.ValidationError(
"run",
"The legacy task runner does not support running multiple scripts concurrently. Please update to the latest version of lerna and ensure you do not have useNx set to false in your lerna.json."
);
}
this.bail = this.options.bail !== false;
this.prefix = this.options.prefix !== false;
let chain = Promise.resolve();
chain = chain.then(() => (0, import_core.getFilteredPackages)(this.packageGraph, this.execOpts, this.options));
chain = chain.then((filteredPackages) => {
this.packagesWithScript = script === "env" ? filteredPackages : filteredPackages.filter((pkg) => {
if (Array.isArray(this.script)) {
return this.script.some((scriptName) => pkg.scripts && pkg.scripts[scriptName]);
}
return pkg.scripts && pkg.scripts[script];
});
});
return chain.then(() => {
this.count = this.packagesWithScript.length;
this.packagePlural = this.count === 1 ? "package" : "packages";
this.joinedCommand = [this.npmClient, "run", this.script].concat(this.args).join(" ");
if (!this.count) {
this.logger.success("run", `No packages found with the lifecycle script '${script}'`);
return false;
}
});
}
execute() {
if (this.options.useNx === false) {
this.logger.info(
"",
"Executing command in %d %s: %j",
this.count,
this.packagePlural,
this.joinedCommand
);
}
let chain = Promise.resolve();
const getElapsed = (0, import_core.timer)();
if (this.options.useNx !== false) {
chain = chain.then(() => this.runScriptsUsingNx());
} else if (this.options.parallel) {
chain = chain.then(() => this.runScriptInPackagesParallel());
} else if (this.toposort) {
chain = chain.then(() => this.runScriptInPackagesTopological());
} else {
chain = chain.then(() => this.runScriptInPackagesLexical());
}
if (this.bail) {
chain = chain.catch((err) => {
process.exitCode = err.exitCode;
throw err;
});
} else {
chain = chain.then((results) => {
if (results.some((result) => result.failed)) {
const codes = results.filter((result) => result.failed).map((result) => result.exitCode);
const exitCode = Math.max(...codes, 1);
this.logger.error("", "Received non-zero exit code %d during execution", exitCode);
process.exitCode = exitCode;
}
});
}
return chain.then(() => {
this.logger.success(
"run",
"Ran npm script '%s' in %d %s in %ss:",
this.script,
this.count,
this.packagePlural,
(getElapsed() / 1e3).toFixed(1)
);
this.logger.success("", this.packagesWithScript.map((pkg) => `- ${pkg.name}`).join("\n"));
});
}
getOpts(pkg) {
return {
args: this.args,
npmClient: this.npmClient,
prefix: this.prefix,
reject: this.bail,
pkg
};
}
getRunner() {
return this.options.stream ? (pkg) => this.runScriptInPackageStreaming(pkg) : (pkg) => this.runScriptInPackageCapturing(pkg);
}
runScriptInPackagesTopological() {
let profiler;
let runner;
if (this.options.profile) {
profiler = new import_core.Profiler({
concurrency: this.concurrency,
log: this.logger,
outputDirectory: this.options.profileLocation
});
const callback = this.getRunner();
runner = (pkg) => profiler.run(() => callback(pkg), pkg.name);
} else {
runner = this.getRunner();
}
let chain = (0, import_core.runTopologically)(this.packagesWithScript, runner, {
concurrency: this.concurrency,
rejectCycles: this.options.rejectCycles
});
if (profiler) {
chain = chain.then((results) => profiler.output().then(() => results));
}
return chain;
}
addQuotesAroundScriptNameIfItHasAColon(scriptName) {
if (scriptName.includes(":")) {
return `"${scriptName}"`;
} else {
return scriptName;
}
}
async runScriptsUsingNx() {
if (this.options.ci) {
process.env.CI = "true";
}
if (this.options.profile) {
const absolutePath = (0, import_core.generateProfileOutputPath)(this.options.profileLocation);
process.env.NX_PROFILE = import_path.default.relative(this.project.rootPath, absolutePath);
}
import_perf_hooks.performance.mark("init-local");
this.configureNxOutput();
const { targetDependencies, options, extraOptions } = await this.prepNxOptions();
if (this.packagesWithScript.length === 1) {
const { runOne } = require("nx/src/command-line/run-one");
const fullQualifiedTarget = this.packagesWithScript.map((p) => p.name)[0] + ":" + this.addQuotesAroundScriptNameIfItHasAColon(this.script);
return runOne(
process.cwd(),
{
"project:target:configuration": fullQualifiedTarget,
...options
},
targetDependencies,
extraOptions
);
} else {
const { runMany } = require("nx/src/command-line/run-many");
const projects = this.packagesWithScript.map((p) => p.name).join(",");
return runMany(
{
projects,
targets: Array.isArray(this.script) ? this.script : [this.script],
...options
},
targetDependencies,
extraOptions
);
}
}
async prepNxOptions() {
const nxJsonExists = (0, import_fs_extra.existsSync)(import_path.default.join(this.project.rootPath, "nx.json"));
const { readNxJson } = require("nx/src/config/configuration");
const nxJson = readNxJson();
const targetDependenciesAreDefined = Object.keys(nxJson.targetDependencies || nxJson.targetDefaults || {}).length > 0;
const hasProjectSpecificNxConfiguration = this.packagesWithScript.some((p) => !!p.get("nx"));
const hasCustomizedNxConfiguration = nxJsonExists && targetDependenciesAreDefined || hasProjectSpecificNxConfiguration;
const mimicLernaDefaultBehavior = !hasCustomizedNxConfiguration;
const targetDependencies = this.toposort && !this.options.parallel && mimicLernaDefaultBehavior ? {
[this.script]: [
{
projects: "dependencies",
target: this.script
}
]
} : {};
if (this.options.prefix === false && !this.options.stream) {
this.logger.warn(this.name, `"no-prefix" is ignored when not using streaming output.`);
}
const outputStyle = this.options.stream ? this.prefix ? "stream" : "stream-without-prefixes" : "dynamic";
const options = {
outputStyle,
/**
* 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: this.options.parallel && mimicLernaDefaultBehavior ? 999 : this.concurrency,
nxBail: this.bail,
nxIgnoreCycles: !this.options.rejectCycles,
skipNxCache: this.options.skipNxCache,
verbose: this.options.verbose,
__overrides__: this.args.map((t) => t.toString())
};
if (hasCustomizedNxConfiguration) {
this.logger.verbose(
this.name,
"Nx target configuration was found. Task dependencies will be automatically included."
);
if (this.options.parallel || this.options.sort !== void 0) {
this.logger.warn(
this.name,
`"parallel", "sort", and "no-sort" are ignored when Nx targets are configured. See https://lerna.js.org/docs/lerna6-obsolete-options for details.`
);
}
if (this.options.includeDependencies) {
this.logger.info(
this.name,
`Using the "include-dependencies" option when Nx targets are configured will include both task dependencies detected by Nx and project dependencies detected by Lerna. See https://lerna.js.org/docs/lerna6-obsolete-options#--include-dependencies for details.`
);
}
if (this.options.ignore) {
this.logger.info(
this.name,
`Using the "ignore" option when Nx targets are configured will exclude only tasks that are not determined to be required by Nx. See https://lerna.js.org/docs/lerna6-obsolete-options#--ignore for details.`
);
}
} else {
this.logger.verbose(
this.name,
"Nx target configuration was not found. Task dependencies will not be automatically included."
);
}
const extraOptions = {
excludeTaskDependencies: mimicLernaDefaultBehavior,
loadDotEnvFiles: this.options.loadEnvFiles ?? true
};
return { targetDependencies, options, extraOptions };
}
runScriptInPackagesParallel() {
return (0, import_p_map.default)(this.packagesWithScript, (pkg) => this.runScriptInPackageStreaming(pkg));
}
runScriptInPackagesLexical() {
return (0, import_p_map.default)(this.packagesWithScript, this.getRunner(), { concurrency: this.concurrency });
}
runScriptInPackageStreaming(pkg) {
return (0, import_core.npmRunScriptStreaming)(this.script, this.getOpts(pkg));
}
runScriptInPackageCapturing(pkg) {
const getElapsed = (0, import_core.timer)();
return (0, import_core.npmRunScript)(this.script, this.getOpts(pkg)).then((result) => {
this.logger.info(
"run",
"Ran npm script '%s' in '%s' in %ss:",
this.script,
pkg.name,
(getElapsed() / 1e3).toFixed(1)
);
(0, import_core.output)(result.stdout);
return result;
});
}
configureNxOutput() {
try {
const nxOutput = require("nx/src/utils/output");
nxOutput.output.cliName = "Lerna (powered by Nx)";
nxOutput.output.formatCommand = (taskId) => taskId;
return nxOutput;
} catch (err) {
this.logger.error(
"\n",
"There was a critical error when configuring the task runner, please report this on https://github.com/lerna/lerna"
);
throw err;
}
}
}
module.exports.RunCommand = RunCommand;