UNPKG

8.73 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.RunCommand = exports.factory = void 0;
7const core_1 = require("@lerna-lite/core");
8const exec_run_common_1 = require("@lerna-lite/exec-run-common");
9const p_map_1 = __importDefault(require("p-map"));
10const lib_1 = require("./lib");
11function factory(argv) {
12 return new RunCommand(argv);
13}
14exports.factory = factory;
15class RunCommand extends core_1.Command {
16 constructor(argv) {
17 super(argv);
18 /** command name */
19 this.name = 'run';
20 this.args = [];
21 this.bail = false;
22 this.prefix = false;
23 this.npmClient = 'npm';
24 this.packagesWithScript = [];
25 this.script = '';
26 }
27 get requiresGit() {
28 return false;
29 }
30 initialize() {
31 const { script, npmClient = 'npm' } = this.options;
32 this.script = script;
33 this.args = this.options['--'] || [];
34 this.npmClient = npmClient;
35 if (!script) {
36 throw new core_1.ValidationError('ENOSCRIPT', 'You must specify a lifecycle script to run');
37 }
38 // inverted boolean options
39 this.bail = this.options.bail !== false;
40 this.prefix = this.options.prefix !== false;
41 let chain = Promise.resolve();
42 if (!this.options.log) {
43 this.options.log = this.logger;
44 }
45 chain = chain.then(() => (0, exec_run_common_1.getFilteredPackages)(this.packageGraph, this.execOpts, this.options));
46 chain = chain.then((filteredPackages) => {
47 this.packagesWithScript =
48 script === 'env'
49 ? filteredPackages
50 : filteredPackages.filter((pkg) => pkg.scripts && pkg.scripts[script]);
51 });
52 return chain.then(() => {
53 this.count = this.packagesWithScript.length;
54 this.packagePlural = this.count === 1 ? 'package' : 'packages';
55 this.joinedCommand = [this.npmClient, 'run', this.script].concat(this.args).join(' ');
56 if (!this.count) {
57 this.logger.info('run', `No packages found with the lifecycle script "${script}"`);
58 // still exits zero, aka 'ok'
59 return false;
60 }
61 });
62 }
63 execute() {
64 this.logger.info('', 'Executing command in %d %s: %j', this.count, this.packagePlural, this.joinedCommand);
65 let chain = Promise.resolve();
66 const getElapsed = (0, lib_1.timer)();
67 if (this.options.parallel) {
68 this.logger.verbose('Parallel', this.joinedCommand);
69 chain = chain.then(() => this.runScriptInPackagesParallel());
70 }
71 else if (this.toposort) {
72 this.logger.verbose('Topological', this.joinedCommand);
73 chain = chain.then(() => this.runScriptInPackagesTopological());
74 }
75 else {
76 this.logger.verbose('Lexical', this.joinedCommand);
77 chain = chain.then(() => this.runScriptInPackagesLexical());
78 }
79 if (this.bail) {
80 // only the first error is caught
81 chain = chain.catch((err) => {
82 process.exitCode = err.exitCode;
83 // rethrow to halt chain and log properly
84 throw err;
85 });
86 }
87 else {
88 // detect error (if any) from collected results
89 chain = chain.then((results) => {
90 /* istanbul ignore else */
91 if (results.some((result) => result === null || result === void 0 ? void 0 : result.failed)) {
92 // propagate 'highest' error code, it's probably the most useful
93 const codes = results.filter((result) => result === null || result === void 0 ? void 0 : result.failed).map((result) => result.exitCode);
94 const exitCode = Math.max(...codes, 1);
95 this.logger.error('', 'Received non-zero exit code %d during execution', exitCode);
96 if (!this.options.stream) {
97 results
98 .filter((result) => result === null || result === void 0 ? void 0 : result.failed)
99 .forEach((result) => {
100 this.logger.error('', result.pkg.name, result.stderr);
101 });
102 }
103 process.exitCode = exitCode;
104 }
105 return results;
106 });
107 }
108 return chain.then((results) => {
109 const someFailed = results.some((result) => result === null || result === void 0 ? void 0 : result.failed);
110 const logType = someFailed ? 'error' : 'success';
111 this.logger[logType]('run', `Ran npm script '%s' in %d %s in %ss:`, this.script, this.count, this.packagePlural, (getElapsed() / 1000).toFixed(1));
112 if (!this.bail) {
113 results.forEach((result) => {
114 if (result === null || result === void 0 ? void 0 : result.failed) {
115 this.logger.error('', `- ${result.pkg.name}`);
116 }
117 else {
118 this.logger.success('', ` - ${result.pkg.name}`);
119 }
120 });
121 }
122 else {
123 this.logger.success('', this.packagesWithScript.map((pkg) => `- ${pkg.name}`).join('\n'));
124 }
125 });
126 }
127 getOpts(pkg) {
128 // these options are NOT passed directly to execa, they are composed in npm-run-script
129 return {
130 args: this.args,
131 npmClient: this.npmClient,
132 prefix: this.prefix,
133 reject: this.bail,
134 pkg,
135 };
136 }
137 getRunner() {
138 return this.options.stream
139 ? (pkg) => this.runScriptInPackageStreaming(pkg)
140 : (pkg) => this.runScriptInPackageCapturing(pkg);
141 }
142 runScriptInPackagesTopological() {
143 let profiler;
144 let runner;
145 if (this.options.profile) {
146 profiler = new exec_run_common_1.Profiler({
147 concurrency: this.concurrency,
148 log: this.logger,
149 outputDirectory: this.options.profileLocation,
150 });
151 const callback = this.getRunner();
152 runner = (pkg) => profiler.run(() => callback(pkg), pkg.name);
153 }
154 else {
155 runner = this.getRunner();
156 }
157 let chain = (0, core_1.runTopologically)(this.packagesWithScript, runner, {
158 concurrency: this.concurrency,
159 rejectCycles: this.options.rejectCycles,
160 });
161 if (profiler) {
162 chain = chain.then((results) => profiler.output().then(() => results));
163 }
164 return chain;
165 }
166 runScriptInPackagesParallel() {
167 return (0, p_map_1.default)(this.packagesWithScript, (pkg) => this.runScriptInPackageStreaming(pkg));
168 }
169 runScriptInPackagesLexical() {
170 return (0, p_map_1.default)(this.packagesWithScript, this.getRunner(), { concurrency: this.concurrency });
171 }
172 runScriptInPackageStreaming(pkg) {
173 if (this.options.cmdDryRun) {
174 return this.dryRunScript(this.script, pkg.name);
175 }
176 const chain = (0, lib_1.npmRunScriptStreaming)(this.script, this.getOpts(pkg));
177 if (!this.bail) {
178 chain.then((result) => {
179 return { ...result, pkg };
180 });
181 }
182 return chain;
183 }
184 runScriptInPackageCapturing(pkg) {
185 const getElapsed = (0, lib_1.timer)();
186 if (this.options.cmdDryRun) {
187 return this.dryRunScript(this.script, pkg.name);
188 }
189 return (0, lib_1.npmRunScript)(this.script, this.getOpts(pkg)).then((result) => {
190 this.logger.info('run', `Ran npm script '%s' in '%s' in %ss:`, this.script, pkg.name, (getElapsed() / 1000).toFixed(1));
191 (0, core_1.logOutput)(result.stdout);
192 if (!this.bail) {
193 return { ...result, pkg };
194 }
195 return result;
196 });
197 }
198 dryRunScript(scriptName, pkgName) {
199 this.logger.info('dry-run>', `Run npm script '%s' in '%s'`, scriptName, pkgName);
200 (0, core_1.logOutput)(`dry-run> ${pkgName}`);
201 return Promise.resolve();
202 }
203}
204exports.RunCommand = RunCommand;
205//# sourceMappingURL=run-command.js.map
\No newline at end of file