@testim/testim-cli 3.228.0 → 3.231.0
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const findRoot = require('find-root');
|
|
@@ -7,16 +7,17 @@ const { spawn: threadSpawn, config } = require('threads');
|
|
|
7
7
|
const Promise = require('bluebird');
|
|
8
8
|
const fs = require('fs-extra');
|
|
9
9
|
const utils = require('../../../utils');
|
|
10
|
-
const logger = require('../../../commons/logger').getLogger(
|
|
10
|
+
const logger = require('../../../commons/logger').getLogger('cli-service');
|
|
11
11
|
const { getS3Artifact } = require('../../../commons/testimServicesApi');
|
|
12
12
|
const npmWrapper = require('../../../commons/npmWrapper');
|
|
13
13
|
const featureFlags = require('../../../commons/featureFlags');
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
let workerThreads;
|
|
15
16
|
|
|
16
17
|
config.set({
|
|
17
18
|
basepath: {
|
|
18
|
-
node: __dirname
|
|
19
|
-
}
|
|
19
|
+
node: __dirname,
|
|
20
|
+
},
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
const transactions = {};
|
|
@@ -32,19 +33,19 @@ function convertWindowsBackslash(input) {
|
|
|
32
33
|
return input.replace(/\\/g, '/');
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
function runCode(transactionId, incomingParams, context, code, packageLocalLocations = {}, timeout, fileDataUrl) {
|
|
36
|
+
function runCode(transactionId, incomingParams, context, code, packageLocalLocations = {}, timeout = undefined, fileDataUrl = undefined) {
|
|
36
37
|
const requireCode = Object.keys(packageLocalLocations).reduce((all, pMember) => {
|
|
37
38
|
all += `
|
|
38
39
|
var ${pMember} = require('${convertWindowsBackslash(packageLocalLocations[pMember])}');
|
|
39
40
|
`;
|
|
40
41
|
return all;
|
|
41
|
-
},
|
|
42
|
+
}, '');
|
|
42
43
|
|
|
43
44
|
if (fileDataUrl === 'data:') { // fix chrome/safari bug that creates malformed datauri for empty files
|
|
44
45
|
fileDataUrl = 'data:,';
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
const fileDataUrlToFileBuffer = !fileDataUrl ?
|
|
48
|
+
const fileDataUrlToFileBuffer = !fileDataUrl ? 'var fileBuffer = null;' :
|
|
48
49
|
`
|
|
49
50
|
${dataUriToBuffer.toString()}
|
|
50
51
|
var fileBuffer = dataUriToBuffer('${fileDataUrl}');
|
|
@@ -212,7 +213,7 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
|
|
|
212
213
|
thread
|
|
213
214
|
.send({ incomingParams, context, code })
|
|
214
215
|
.on('message', message => {
|
|
215
|
-
const messageWithLogs = Object.assign({}, message, { tstConsoleLogs: testimConsoleLogDataAggregates })
|
|
216
|
+
const messageWithLogs = Object.assign({}, message, { tstConsoleLogs: testimConsoleLogDataAggregates });
|
|
216
217
|
logger.debug('Run code worker response', { messageWithLogs, transactionId });
|
|
217
218
|
resolve(messageWithLogs);
|
|
218
219
|
})
|
|
@@ -220,7 +221,7 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
|
|
|
220
221
|
testimConsoleLogDataAggregates.push(logMessage);
|
|
221
222
|
})
|
|
222
223
|
.on('error', (err) => {
|
|
223
|
-
if (err.message ===
|
|
224
|
+
if (err.message === 'malformed data: URI') {
|
|
224
225
|
logger.error('Run code worker error', { err, transactionId, fileDataUrl });
|
|
225
226
|
} else {
|
|
226
227
|
logger.error('Run code worker error', { err, transactionId });
|
|
@@ -233,9 +234,9 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
|
|
|
233
234
|
resultValue: err && err.toString(),
|
|
234
235
|
exports: {},
|
|
235
236
|
exportsTest: {},
|
|
236
|
-
exportsGlobal: {}
|
|
237
|
+
exportsGlobal: {},
|
|
237
238
|
},
|
|
238
|
-
success: false
|
|
239
|
+
success: false,
|
|
239
240
|
});
|
|
240
241
|
})
|
|
241
242
|
.on('exit', () => {
|
|
@@ -243,7 +244,7 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
|
|
|
243
244
|
});
|
|
244
245
|
}).timeout(timeout)
|
|
245
246
|
.catch(Promise.TimeoutError, err => {
|
|
246
|
-
logger.warn(
|
|
247
|
+
logger.warn('timeout to run code', { transactionId, err });
|
|
247
248
|
return Promise.resolve({
|
|
248
249
|
tstConsoleLogs: testimConsoleLogDataAggregates,
|
|
249
250
|
status: 'failed',
|
|
@@ -251,23 +252,301 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
|
|
|
251
252
|
resultValue: err && err.toString(),
|
|
252
253
|
exports: {},
|
|
253
254
|
exportsTest: {},
|
|
254
|
-
exportsGlobal: {}
|
|
255
|
+
exportsGlobal: {},
|
|
255
256
|
},
|
|
256
|
-
success: false
|
|
257
|
+
success: false,
|
|
257
258
|
});
|
|
258
259
|
})
|
|
259
260
|
.finally(() => thread && thread.kill());
|
|
260
261
|
}
|
|
261
262
|
|
|
262
|
-
function
|
|
263
|
-
|
|
264
|
-
return
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
263
|
+
function requireOrImportMethod(path) {
|
|
264
|
+
try {
|
|
265
|
+
return { sync: true, lib: require(path) };
|
|
266
|
+
} catch (err) {
|
|
267
|
+
if (err.code === 'ERR_REQUIRE_ESM') {
|
|
268
|
+
const fs = require('fs');
|
|
269
|
+
const pathModule = require('path');
|
|
270
|
+
|
|
271
|
+
const lib = fs.promises.readFile(`${path}${pathModule.sep}package.json`).then(file => {
|
|
272
|
+
const packageJson = JSON.parse(file);
|
|
273
|
+
const fullPath = pathModule.join(path, packageJson.main || `${pathModule.sep}index.js`);
|
|
274
|
+
return import(fullPath);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return { sync: false, lib };
|
|
278
|
+
}
|
|
279
|
+
throw err;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function runCodeWithWorkerThread(transactionId, incomingParams, context, code, packageLocalLocations = {}, timeout = undefined, fileDataUrl = undefined) {
|
|
284
|
+
// technically shouldn't happen, but better safe than sorry.
|
|
285
|
+
if (!workerThreads) {
|
|
286
|
+
workerThreads = require('worker_threads');
|
|
287
|
+
}
|
|
288
|
+
const { Worker } = workerThreads;
|
|
289
|
+
const requireCode = Object.keys(packageLocalLocations).reduce((all, pMember) => {
|
|
290
|
+
all += `
|
|
291
|
+
var res = requireOrImportMethod('${convertWindowsBackslash(packageLocalLocations[pMember])}');
|
|
292
|
+
if (res.sync) {
|
|
293
|
+
var ${pMember} = res.lib;
|
|
294
|
+
} else {
|
|
295
|
+
var ${pMember} = await res.lib;
|
|
296
|
+
}
|
|
297
|
+
`;
|
|
298
|
+
return all;
|
|
299
|
+
}, '');
|
|
300
|
+
|
|
301
|
+
if (fileDataUrl === 'data:') { // fix chrome/safari bug that creates malformed datauri for empty files
|
|
302
|
+
fileDataUrl = 'data:,';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const fileDataUrlToFileBuffer = !fileDataUrl ? 'var fileBuffer = null;' :
|
|
306
|
+
`
|
|
307
|
+
${dataUriToBuffer.toString()}
|
|
308
|
+
var fileBuffer = dataUriToBuffer('${fileDataUrl}');
|
|
309
|
+
`;
|
|
310
|
+
|
|
311
|
+
function constructWithArguments(constructor, args) {
|
|
312
|
+
function F() {
|
|
313
|
+
return constructor.apply(this, args);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
F.prototype = constructor.prototype;
|
|
317
|
+
return new F();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
//https://github.com/anseki/console-substitute
|
|
321
|
+
// note that this method is a bit different than the one in the non-worker one.
|
|
322
|
+
const consoleOverride = `
|
|
323
|
+
const getMessage = arguments => {
|
|
324
|
+
const args = Array.prototype.slice.call(arguments);
|
|
325
|
+
let message = args.shift() + '';
|
|
326
|
+
if (!args.length) {
|
|
327
|
+
return message;
|
|
328
|
+
}
|
|
329
|
+
message = message.replace(/%([odifs])/g, function (s, param) {
|
|
330
|
+
// Formatting is not yet supported.
|
|
331
|
+
var arg;
|
|
332
|
+
if (!args.length) {
|
|
333
|
+
return '';
|
|
334
|
+
}
|
|
335
|
+
arg = args.shift();
|
|
336
|
+
if (param === 'o') {
|
|
337
|
+
return arg + '';
|
|
338
|
+
} else if (param === 'd' || param === 'i') {
|
|
339
|
+
arg = typeof arg === 'boolean' ? (arg ? 1 : 0) : parseInt(arg, 10);
|
|
340
|
+
return isNaN(arg) ? '0' : arg + '';
|
|
341
|
+
} else if (param === 'f') {
|
|
342
|
+
arg = typeof arg === 'boolean' ? (arg ? 1 : 0) : parseFloat(arg);
|
|
343
|
+
return isNaN(arg) ? '0.000000' : arg.toFixed(6) + '';
|
|
344
|
+
} else if (param === 's') {
|
|
345
|
+
return arg + '';
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
if (message) {
|
|
349
|
+
args.unshift(message);
|
|
350
|
+
}
|
|
351
|
+
return args.join(' ').replace(/\\s*$/, ' ');
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const pushNewMessage = (method, consoleArgs) => {
|
|
355
|
+
const message = getMessage(consoleArgs);
|
|
356
|
+
parentPort.postMessage({
|
|
357
|
+
action: 'progress',
|
|
358
|
+
data: {
|
|
359
|
+
method,
|
|
360
|
+
msg: message,
|
|
361
|
+
timestamp: Date.now(),
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
["log", "info", "warn", "error", "debug"].forEach(function (method) {
|
|
367
|
+
const nativeMethod = console[method];
|
|
368
|
+
const oldMethod = nativeMethod && nativeMethod.bind(console);
|
|
369
|
+
console[method] = function () {
|
|
370
|
+
pushNewMessage(method, arguments);
|
|
371
|
+
oldMethod && oldMethod.apply(console, arguments);
|
|
372
|
+
};
|
|
373
|
+
});
|
|
374
|
+
`;
|
|
375
|
+
|
|
376
|
+
const injectCode = `
|
|
377
|
+
function injectCode(params, args, incomingParams, context, code) {
|
|
378
|
+
${constructWithArguments.toString()}
|
|
379
|
+
|
|
380
|
+
var resolve = function (result) {
|
|
381
|
+
parentPort.postMessage({
|
|
382
|
+
action: 'finish',
|
|
383
|
+
data: {
|
|
384
|
+
status: 'done',
|
|
385
|
+
result: result,
|
|
386
|
+
success: true,
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
var reject = function (result) {
|
|
391
|
+
parentPort.postMessage({
|
|
392
|
+
action: 'finish',
|
|
393
|
+
data: {
|
|
394
|
+
status: 'failed',
|
|
395
|
+
result: result,
|
|
396
|
+
success: false,
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
params.push(code);
|
|
403
|
+
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
|
404
|
+
var functionToRun = constructWithArguments(AsyncFunction, params);
|
|
405
|
+
|
|
406
|
+
var result = functionToRun.apply(null, args);
|
|
407
|
+
if (isPromise(result)) {
|
|
408
|
+
result.then(function (res) {
|
|
409
|
+
resolve({
|
|
410
|
+
resultValue: res,
|
|
411
|
+
exports: exportedData,
|
|
412
|
+
exportsTest: exportedTestData,
|
|
413
|
+
exportsGlobal: exportedGlobalData
|
|
414
|
+
});
|
|
415
|
+
}).catch(function (err) {
|
|
416
|
+
reject({
|
|
417
|
+
resultValue: err && err.toString(),
|
|
418
|
+
exports: exportedData,
|
|
419
|
+
exportsTest: exportedTestData,
|
|
420
|
+
exportsGlobal: exportedGlobalData
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
} else {
|
|
424
|
+
resolve({
|
|
425
|
+
resultValue: result,
|
|
426
|
+
exports: exportedData,
|
|
427
|
+
exportsTest: exportedTestData,
|
|
428
|
+
exportsGlobal: exportedGlobalData
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
} catch (e) {
|
|
432
|
+
reject({
|
|
433
|
+
resultValue: e && e.toString(),
|
|
434
|
+
exports: exportedData,
|
|
435
|
+
exportsTest: exportedTestData,
|
|
436
|
+
exportsGlobal: exportedGlobalData
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
`;
|
|
441
|
+
|
|
442
|
+
const runFn = `
|
|
443
|
+
(async function() {
|
|
444
|
+
const { parentPort } = require('worker_threads');
|
|
445
|
+
${requireOrImportMethod}
|
|
446
|
+
|
|
447
|
+
// requireCode will set async to be true if needed.
|
|
448
|
+
${requireCode}
|
|
449
|
+
|
|
450
|
+
${fileDataUrlToFileBuffer}
|
|
451
|
+
|
|
452
|
+
${consoleOverride}
|
|
453
|
+
|
|
454
|
+
${utils.isPromise.toString()}
|
|
455
|
+
|
|
456
|
+
parentPort.once('message', input => {
|
|
457
|
+
const {incomingParams, context, code} = input;
|
|
458
|
+
|
|
459
|
+
var exportedData = {};
|
|
460
|
+
var exportedTestData = {};
|
|
461
|
+
var exportedGlobalData = {};
|
|
462
|
+
|
|
463
|
+
var params = ["context"]
|
|
464
|
+
.concat(incomingParams.as.functionParameters)
|
|
465
|
+
.concat(${JSON.stringify(Object.keys(packageLocalLocations))})
|
|
466
|
+
.concat(['exports', 'exportsTest', 'exportsGlobal']);
|
|
467
|
+
|
|
468
|
+
var args = [context]
|
|
469
|
+
.concat(incomingParams.as.functionArguments)
|
|
470
|
+
.concat([${Object.keys(packageLocalLocations).join(',')}])
|
|
471
|
+
.concat([exportedData, exportedTestData, exportedGlobalData]);
|
|
472
|
+
|
|
473
|
+
if(fileBuffer) {
|
|
474
|
+
params = params.concat(['fileBuffer']);
|
|
475
|
+
args = args.concat([fileBuffer]);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
${injectCode}
|
|
479
|
+
|
|
480
|
+
injectCode(params, args, incomingParams, context, code);
|
|
269
481
|
});
|
|
482
|
+
})();
|
|
483
|
+
`;
|
|
484
|
+
|
|
485
|
+
const testimConsoleLogDataAggregates = [];
|
|
486
|
+
const thread = new Worker(runFn, {
|
|
487
|
+
eval: true,
|
|
270
488
|
});
|
|
489
|
+
return new Promise((resolve) => {
|
|
490
|
+
thread
|
|
491
|
+
.on('message', message => {
|
|
492
|
+
if (message.action === 'finish') {
|
|
493
|
+
const { data } = message;
|
|
494
|
+
const messageWithLogs = Object.assign({}, data, { tstConsoleLogs: testimConsoleLogDataAggregates });
|
|
495
|
+
logger.debug('Run code worker response', { messageWithLogs, transactionId });
|
|
496
|
+
resolve(messageWithLogs);
|
|
497
|
+
} else if (message.action === 'progress') {
|
|
498
|
+
testimConsoleLogDataAggregates.push(message.data);
|
|
499
|
+
}
|
|
500
|
+
})
|
|
501
|
+
.on('error', (err) => {
|
|
502
|
+
if (err.message === 'malformed data: URI') {
|
|
503
|
+
logger.error('Run code worker error', { err, transactionId, fileDataUrl });
|
|
504
|
+
} else {
|
|
505
|
+
logger.error('Run code worker error', { err, transactionId });
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
resolve({
|
|
509
|
+
tstConsoleLogs: testimConsoleLogDataAggregates,
|
|
510
|
+
status: 'failed',
|
|
511
|
+
result: {
|
|
512
|
+
resultValue: err && err.toString(),
|
|
513
|
+
exports: {},
|
|
514
|
+
exportsTest: {},
|
|
515
|
+
exportsGlobal: {},
|
|
516
|
+
},
|
|
517
|
+
success: false,
|
|
518
|
+
});
|
|
519
|
+
})
|
|
520
|
+
.on('exit', () => {
|
|
521
|
+
logger.debug('Run code worker has been terminated', { transactionId });
|
|
522
|
+
});
|
|
523
|
+
// context can contain methods and proxies which cannot pass.
|
|
524
|
+
thread.postMessage({ incomingParams, context: JSON.parse(JSON.stringify(context)), code });
|
|
525
|
+
}).timeout(timeout)
|
|
526
|
+
.catch(Promise.TimeoutError, err => {
|
|
527
|
+
logger.warn('timeout to run code', { transactionId, err });
|
|
528
|
+
return Promise.resolve({
|
|
529
|
+
tstConsoleLogs: testimConsoleLogDataAggregates,
|
|
530
|
+
status: 'failed',
|
|
531
|
+
result: {
|
|
532
|
+
resultValue: err && err.toString(),
|
|
533
|
+
exports: {},
|
|
534
|
+
exportsTest: {},
|
|
535
|
+
exportsGlobal: {},
|
|
536
|
+
},
|
|
537
|
+
success: false,
|
|
538
|
+
});
|
|
539
|
+
})
|
|
540
|
+
.finally(() => thread && thread.terminate());
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function removeFolder(installFolder) {
|
|
544
|
+
return new Promise(resolve => fs.remove(installFolder)
|
|
545
|
+
.then(resolve)
|
|
546
|
+
.catch(err => {
|
|
547
|
+
logger.warn('failed to remove install npm packages folder', { err });
|
|
548
|
+
return resolve();
|
|
549
|
+
}));
|
|
271
550
|
}
|
|
272
551
|
|
|
273
552
|
function cleanPackages(transactionId) {
|
|
@@ -291,31 +570,14 @@ function getTransactionId(stepResultId, testResultId, stepId, retryIndex) {
|
|
|
291
570
|
return `${testResultId}_${stepId}_${stepResultId}_${retryIndex}`;
|
|
292
571
|
}
|
|
293
572
|
|
|
294
|
-
function mapNpmInstallDataToInstallData(npmInstallData, packageData) {
|
|
295
|
-
const npmInstallDataObject = npmInstallData.reduce((obj, [packageFullName, packageLocalLocation]) => {
|
|
296
|
-
const strudelIndex = packageFullName.lastIndexOf('@');
|
|
297
|
-
const npmInstalledPackageName = packageFullName.substr(0, strudelIndex);
|
|
298
|
-
obj[npmInstalledPackageName] = {
|
|
299
|
-
packageFullName,
|
|
300
|
-
packageLocalLocation
|
|
301
|
-
};
|
|
302
|
-
return obj;
|
|
303
|
-
}, {});
|
|
304
|
-
return packageData.map(data => {
|
|
305
|
-
const npmPackageName = data.packageName;
|
|
306
|
-
return Object.assign({}, npmInstallDataObject[npmPackageName], data);
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
|
|
310
573
|
function installPackage(stepId, testResultId, retryIndex, packageData, stepResultId, timeout) {
|
|
311
574
|
const transactionId = getTransactionId(stepResultId, testResultId, stepId, retryIndex);
|
|
312
575
|
return runNpmInstall(transactionId, packageData, timeout)
|
|
313
576
|
.then(({ data, installFolder }) => {
|
|
314
577
|
transactions[transactionId] = transactions[transactionId] || {};
|
|
315
578
|
transactions[transactionId].installFolder = installFolder;
|
|
316
|
-
return
|
|
579
|
+
return data;
|
|
317
580
|
});
|
|
318
|
-
|
|
319
581
|
}
|
|
320
582
|
|
|
321
583
|
function runCodeWithPackages(code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, timeout, fileDataUrl, s3filepath) {
|
|
@@ -333,8 +595,20 @@ function runCodeWithPackages(code, stepId, incomingParams, context, testResultId
|
|
|
333
595
|
if (s3fileDataUrl) {
|
|
334
596
|
fileDataUrl = s3fileDataUrl;
|
|
335
597
|
}
|
|
336
|
-
}).then(() =>
|
|
337
|
-
|
|
598
|
+
}).then(() => {
|
|
599
|
+
if (typeof workerThreads === 'undefined') {
|
|
600
|
+
try {
|
|
601
|
+
workerThreads = require('worker_threads');
|
|
602
|
+
} catch (err) {
|
|
603
|
+
workerThreads = false;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (workerThreads && featureFlags.flags.enableWorkerThreadsCliCodeExecution.isEnabled()) {
|
|
608
|
+
return runCodeWithWorkerThread(transactionId, incomingParams, context, code, packageLocalLocations, timeout, fileDataUrl);
|
|
609
|
+
}
|
|
610
|
+
return runCode(transactionId, incomingParams, context, code, packageLocalLocations, timeout, fileDataUrl);
|
|
611
|
+
}).then(res => Object.assign({}, res, { nodeVersion: process.version }))
|
|
338
612
|
.finally(() => cleanPackages(transactionId));
|
|
339
613
|
}
|
|
340
614
|
|
|
@@ -343,6 +617,9 @@ function runNpmInstall(transactionId, packageData, timeout) {
|
|
|
343
617
|
const localPackageInstallFolder = getLocalPackageInstallFolder();
|
|
344
618
|
const installFolder = path.join(localPackageInstallFolder, `/${transactionId}`);
|
|
345
619
|
const proxyUri = global.proxyUri;
|
|
620
|
+
|
|
621
|
+
// while correct, everything is in a try/catch so it should be fine.
|
|
622
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
346
623
|
return new Promise(async (resolve, reject) => {
|
|
347
624
|
let output = '';
|
|
348
625
|
try {
|
|
@@ -358,8 +635,8 @@ function runNpmInstall(transactionId, packageData, timeout) {
|
|
|
358
635
|
const packageLocalLocation = path.resolve(installFolder, 'node_modules', pData.packageName);
|
|
359
636
|
return Object.assign({}, pData, {
|
|
360
637
|
packageFullName,
|
|
361
|
-
packageLocalLocation
|
|
362
|
-
})
|
|
638
|
+
packageLocalLocation,
|
|
639
|
+
});
|
|
363
640
|
});
|
|
364
641
|
|
|
365
642
|
resolve({ data: packageDataWithVersions, installFolder });
|
|
@@ -367,11 +644,10 @@ function runNpmInstall(transactionId, packageData, timeout) {
|
|
|
367
644
|
logger.warn('npm package install failed', { transactionId, err });
|
|
368
645
|
reject(err);
|
|
369
646
|
}
|
|
370
|
-
|
|
371
647
|
})
|
|
372
648
|
.timeout(timeout)
|
|
373
649
|
.catch(Promise.TimeoutError, err => {
|
|
374
|
-
logger.warn(
|
|
650
|
+
logger.warn('timeout to install package', { packages, transactionId, err, timeout });
|
|
375
651
|
throw err;
|
|
376
652
|
});
|
|
377
653
|
}
|
|
@@ -397,5 +673,5 @@ function cleanLocalPackageInstallFolder() {
|
|
|
397
673
|
module.exports = {
|
|
398
674
|
runCodeWithPackages,
|
|
399
675
|
installPackage,
|
|
400
|
-
cleanLocalPackageInstallFolder
|
|
676
|
+
cleanLocalPackageInstallFolder,
|
|
401
677
|
};
|
package/commons/featureFlags.js
CHANGED
|
@@ -56,6 +56,7 @@ class FeatureFlagsService {
|
|
|
56
56
|
applitoolsNewIntegration: new Rox.Flag(),
|
|
57
57
|
testNamesToBeforeSuiteHook: new Rox.Flag(),
|
|
58
58
|
addCustomCapabilities: new Rox.Variant('{}'),
|
|
59
|
+
enableWorkerThreadsCliCodeExecution: new Rox.Flag(true),
|
|
59
60
|
};
|
|
60
61
|
Rox.register('default', this.flags);
|
|
61
62
|
}
|