nx 19.0.0-canary.20240419-e617e54 → 19.0.0-canary.20240423-b37bfdb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,7 @@ export interface RunCommandsOptions extends Json {
22
22
  readyWhen?: string;
23
23
  cwd?: string;
24
24
  env?: Record<string, string>;
25
+ forwardAllArgs?: boolean;
25
26
  args?: string | string[];
26
27
  envFile?: string;
27
28
  __unparsed__: string[];
@@ -7,17 +7,10 @@ const yargsParser = require("yargs-parser");
7
7
  const npm_run_path_1 = require("npm-run-path");
8
8
  const chalk = require("chalk");
9
9
  const pseudo_terminal_1 = require("../../tasks-runner/pseudo-terminal");
10
+ const exit_codes_1 = require("../../utils/exit-codes");
10
11
  exports.LARGE_BUFFER = 1024 * 1000000;
11
- const exitListeners = new Set();
12
- function processExitListener() {
13
- for (const listener of exitListeners) {
14
- listener();
15
- }
16
- }
17
- process.on('exit', processExitListener);
18
- process.on('SIGTERM', processExitListener);
19
- process.on('SIGINT', processExitListener);
20
- process.on('SIGQUIT', processExitListener);
12
+ let pseudoTerminal;
13
+ const childProcesses = new Set();
21
14
  async function loadEnvVars(path) {
22
15
  if (path) {
23
16
  const result = (await Promise.resolve().then(() => require('dotenv'))).config({ path });
@@ -46,8 +39,10 @@ const propKeys = [
46
39
  'usePty',
47
40
  'streamOutput',
48
41
  'verbose',
42
+ 'forwardAllArgs',
49
43
  ];
50
44
  async function default_1(options, context) {
45
+ registerProcessListener();
51
46
  await loadEnvVars(options.envFile);
52
47
  const normalized = normalizeOptions(options);
53
48
  if (options.readyWhen && !options.parallel) {
@@ -141,14 +136,12 @@ function normalizeOptions(options) {
141
136
  options.parsedArgs = parseArgs(unparsedCommandArgs, options.unknownOptions, options.args);
142
137
  options.unparsedCommandArgs = unparsedCommandArgs;
143
138
  options.commands.forEach((c) => {
144
- c.command = interpolateArgsIntoCommand(c.command, options, c.forwardAllArgs ?? true);
139
+ c.command = interpolateArgsIntoCommand(c.command, options, c.forwardAllArgs ?? options.forwardAllArgs ?? true);
145
140
  });
146
141
  return options;
147
142
  }
148
143
  async function runSerially(options, context) {
149
- const pseudoTerminal = pseudo_terminal_1.PseudoTerminal.isSupported()
150
- ? (0, pseudo_terminal_1.getPseudoTerminal)()
151
- : null;
144
+ pseudoTerminal ??= pseudo_terminal_1.PseudoTerminal.isSupported() ? (0, pseudo_terminal_1.getPseudoTerminal)() : null;
152
145
  let terminalOutput = '';
153
146
  for (const c of options.commands) {
154
147
  const result = await createProcess(pseudoTerminal, c, undefined, options.color, calculateCwd(options.cwd, context), options.env ?? {}, false, options.usePty, options.streamOutput);
@@ -182,6 +175,7 @@ async function createProcess(pseudoTerminal, commandConfig, readyWhen, color, cw
182
175
  jsEnv: env,
183
176
  quiet: !streamOutput,
184
177
  });
178
+ childProcesses.add(cp);
185
179
  return new Promise((res) => {
186
180
  cp.onOutput((output) => {
187
181
  terminalOutput += output;
@@ -212,11 +206,7 @@ function nodeProcess(commandConfig, cwd, env, readyWhen, streamOutput = true) {
212
206
  env,
213
207
  cwd,
214
208
  });
215
- /**
216
- * Ensure the child process is killed when the parent exits
217
- */
218
- const childProcessKiller = (signal) => childProcess.kill(signal);
219
- exitListeners.add(childProcessKiller);
209
+ childProcesses.add(childProcess);
220
210
  childProcess.stdout.on('data', (data) => {
221
211
  const output = addColorAndPrefix(data, commandConfig);
222
212
  terminalOutput += output;
@@ -246,7 +236,7 @@ function nodeProcess(commandConfig, cwd, env, readyWhen, streamOutput = true) {
246
236
  res({ success: false, terminalOutput });
247
237
  });
248
238
  childProcess.on('exit', (code) => {
249
- exitListeners.delete(childProcessKiller);
239
+ childProcesses.delete(childProcess);
250
240
  if (!readyWhen) {
251
241
  res({ success: code === 0, terminalOutput });
252
242
  }
@@ -369,3 +359,57 @@ function filterPropKeysFromUnParsedOptions(__unparsed__, unparsedCommandArgs = {
369
359
  }
370
360
  return parsedOptions;
371
361
  }
362
+ let registered = false;
363
+ function registerProcessListener() {
364
+ if (registered) {
365
+ return;
366
+ }
367
+ registered = true;
368
+ // When the nx process gets a message, it will be sent into the task's process
369
+ process.on('message', (message) => {
370
+ // this.publisher.publish(message.toString());
371
+ if (pseudoTerminal) {
372
+ pseudoTerminal.sendMessageToChildren(message);
373
+ }
374
+ childProcesses.forEach((p) => {
375
+ if ('connected' in p && p.connected) {
376
+ p.send(message);
377
+ }
378
+ });
379
+ });
380
+ // Terminate any task processes on exit
381
+ process.on('exit', () => {
382
+ childProcesses.forEach((p) => {
383
+ if ('connected' in p ? p.connected : p.isAlive) {
384
+ p.kill();
385
+ }
386
+ });
387
+ });
388
+ process.on('SIGINT', () => {
389
+ childProcesses.forEach((p) => {
390
+ if ('connected' in p ? p.connected : p.isAlive) {
391
+ p.kill('SIGTERM');
392
+ }
393
+ });
394
+ // we exit here because we don't need to write anything to cache.
395
+ process.exit((0, exit_codes_1.signalToCode)('SIGINT'));
396
+ });
397
+ process.on('SIGTERM', () => {
398
+ childProcesses.forEach((p) => {
399
+ if ('connected' in p ? p.connected : p.isAlive) {
400
+ p.kill('SIGTERM');
401
+ }
402
+ });
403
+ // no exit here because we expect child processes to terminate which
404
+ // will store results to the cache and will terminate this process
405
+ });
406
+ process.on('SIGHUP', () => {
407
+ childProcesses.forEach((p) => {
408
+ if ('connected' in p ? p.connected : p.isAlive) {
409
+ p.kill('SIGTERM');
410
+ }
411
+ });
412
+ // no exit here because we expect child processes to terminate which
413
+ // will store results to the cache and will terminate this process
414
+ });
415
+ }
@@ -135,6 +135,11 @@
135
135
  "$source": "unparsed"
136
136
  },
137
137
  "x-priority": "internal"
138
+ },
139
+ "forwardAllArgs": {
140
+ "type": "boolean",
141
+ "description": "Whether arguments should be forwarded when interpolation is not present.",
142
+ "default": true
138
143
  }
139
144
  },
140
145
  "additionalProperties": true,
@@ -388,7 +388,7 @@ function mergeTargetConfigurations(target, baseTarget, projectConfigSourceMap, s
388
388
  const { configurations: defaultConfigurations, options: defaultOptions, ...baseTargetProperties } = baseTarget ?? {};
389
389
  // Target is "compatible", e.g. executor is defined only once or is the same
390
390
  // in both places. This means that it is likely safe to merge
391
- const isCompatible = isCompatibleTarget(baseTargetProperties, target);
391
+ const isCompatible = isCompatibleTarget(baseTarget ?? {}, target);
392
392
  // If the targets are not compatible, we would normally overwrite the old target
393
393
  // with the new one. However, we have a special case for targets that have the
394
394
  // ONLY_MODIFIES_EXISTING_TARGET symbol set. This prevents the merged target
@@ -24,6 +24,10 @@ const EXTENDED_LEFT_PAD = ` `;
24
24
  */
25
25
  async function createRunManyDynamicOutputRenderer({ projectNames, tasks, args, overrides, }) {
26
26
  cliCursor.hide();
27
+ // Show the cursor again after the process exits
28
+ process.on('exit', () => {
29
+ cliCursor.show();
30
+ });
27
31
  let resolveRenderIsDonePromise;
28
32
  const renderIsDone = new Promise((resolve) => (resolveRenderIsDonePromise = resolve)).then(() => {
29
33
  clearRenderInterval();
@@ -24,6 +24,10 @@ const EXTENDED_LEFT_PAD = ` `;
24
24
  */
25
25
  async function createRunOneDynamicOutputRenderer({ initiatingProject, tasks, args, overrides, }) {
26
26
  cliCursor.hide();
27
+ // Show the cursor again after the process exits
28
+ process.on('exit', () => {
29
+ cliCursor.show();
30
+ });
27
31
  let resolveRenderIsDonePromise;
28
32
  const renderIsDone = new Promise((resolve) => (resolveRenderIsDonePromise = resolve)).then(() => {
29
33
  clearRenderInterval();
@@ -142,6 +142,12 @@ function supportedPtyPlatform() {
142
142
  if (process.platform !== 'win32') {
143
143
  return true;
144
144
  }
145
+ // TODO: Re-enable Windows support when it's stable
146
+ // Currently, there's an issue with control chars.
147
+ // See: https://github.com/nrwl/nx/issues/22358
148
+ if (process.env.NX_WINDOWS_PTY_SUPPORT !== 'true') {
149
+ return false;
150
+ }
145
151
  let windowsVersion = os.release().split('.');
146
152
  let windowsBuild = windowsVersion[2];
147
153
  if (!windowsBuild) {