nx
Version:
624 lines (623 loc) • 28.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runCommand = runCommand;
exports.runCommandForTasks = runCommandForTasks;
exports.invokeTasksRunner = invokeTasksRunner;
exports.getRunner = getRunner;
exports.getRunnerOptions = getRunnerOptions;
const enquirer_1 = require("enquirer");
const ora = require("ora");
const path_1 = require("path");
const nx_json_1 = require("../config/nx-json");
const client_1 = require("../daemon/client/client");
const create_task_hasher_1 = require("../hasher/create-task-hasher");
const hash_task_1 = require("../hasher/hash-task");
const native_1 = require("../native");
const project_graph_1 = require("../project-graph/project-graph");
const fileutils_1 = require("../utils/fileutils");
const is_ci_1 = require("../utils/is-ci");
const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
const output_1 = require("../utils/output");
const handle_errors_1 = require("../utils/handle-errors");
const sync_generators_1 = require("../utils/sync-generators");
const workspace_root_1 = require("../utils/workspace-root");
const create_task_graph_1 = require("./create-task-graph");
const life_cycle_1 = require("./life-cycle");
const dynamic_run_many_terminal_output_life_cycle_1 = require("./life-cycles/dynamic-run-many-terminal-output-life-cycle");
const dynamic_run_one_terminal_output_life_cycle_1 = require("./life-cycles/dynamic-run-one-terminal-output-life-cycle");
const static_run_many_terminal_output_life_cycle_1 = require("./life-cycles/static-run-many-terminal-output-life-cycle");
const static_run_one_terminal_output_life_cycle_1 = require("./life-cycles/static-run-one-terminal-output-life-cycle");
const store_run_information_life_cycle_1 = require("./life-cycles/store-run-information-life-cycle");
const task_history_life_cycle_1 = require("./life-cycles/task-history-life-cycle");
const task_history_life_cycle_old_1 = require("./life-cycles/task-history-life-cycle-old");
const task_profiling_life_cycle_1 = require("./life-cycles/task-profiling-life-cycle");
const task_timings_life_cycle_1 = require("./life-cycles/task-timings-life-cycle");
const task_results_life_cycle_1 = require("./life-cycles/task-results-life-cycle");
const task_graph_utils_1 = require("./task-graph-utils");
const utils_1 = require("./utils");
const chalk = require("chalk");
const nx_key_1 = require("../utils/nx-key");
const tasks_execution_hooks_1 = require("../project-graph/plugins/tasks-execution-hooks");
async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides) {
const { runnerOptions } = getRunner(nxArgs, nxJson);
const isRunOne = initiatingProject != null;
const useDynamicOutput = shouldUseDynamicLifeCycle(tasks, runnerOptions, nxArgs.outputStyle);
const overridesWithoutHidden = { ...overrides };
delete overridesWithoutHidden['__overrides_unparsed__'];
if (isRunOne) {
if (useDynamicOutput) {
return await (0, dynamic_run_one_terminal_output_life_cycle_1.createRunOneDynamicOutputRenderer)({
initiatingProject,
tasks,
args: nxArgs,
overrides: overridesWithoutHidden,
});
}
return {
lifeCycle: new static_run_one_terminal_output_life_cycle_1.StaticRunOneTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs),
renderIsDone: Promise.resolve(),
};
}
else {
if (useDynamicOutput) {
return await (0, dynamic_run_many_terminal_output_life_cycle_1.createRunManyDynamicOutputRenderer)({
projectNames,
tasks,
args: nxArgs,
overrides: overridesWithoutHidden,
});
}
else {
return {
lifeCycle: new static_run_many_terminal_output_life_cycle_1.StaticRunManyTerminalOutputLifeCycle(projectNames, tasks, nxArgs, overridesWithoutHidden),
renderIsDone: Promise.resolve(),
};
}
}
}
function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies, projectNames, nxArgs, overrides, extraOptions) {
const taskGraph = (0, create_task_graph_1.createTaskGraph)(projectGraph, extraTargetDependencies, projectNames, nxArgs.targets, nxArgs.configuration, overrides, extraOptions.excludeTaskDependencies);
const cycle = (0, task_graph_utils_1.findCycle)(taskGraph);
if (cycle) {
if (process.env.NX_IGNORE_CYCLES === 'true' || nxArgs.nxIgnoreCycles) {
output_1.output.warn({
title: `The task graph has a circular dependency`,
bodyLines: [`${cycle.join(' --> ')}`],
});
(0, task_graph_utils_1.makeAcyclic)(taskGraph);
}
else {
output_1.output.error({
title: `Could not execute command because the task graph has a circular dependency`,
bodyLines: [`${cycle.join(' --> ')}`],
});
process.exit(1);
}
}
// validate that no atomized tasks like e2e-ci are used without Nx Cloud
if (!(0, nx_cloud_utils_1.isNxCloudUsed)((0, nx_json_1.readNxJson)()) &&
!process.env['NX_SKIP_ATOMIZER_VALIDATION']) {
(0, task_graph_utils_1.validateNoAtomizedTasks)(taskGraph, projectGraph);
}
return taskGraph;
}
async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
const status = await (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
await (0, tasks_execution_hooks_1.runPreTasksExecution)({
workspaceRoot: workspace_root_1.workspaceRoot,
nxJsonConfiguration: nxJson,
});
const taskResults = await runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, {
...nxArgs,
skipNxCache: nxArgs.skipNxCache ||
process.env.NX_SKIP_NX_CACHE === 'true' ||
process.env.NX_DISABLE_NX_CACHE === 'true',
}, overrides, initiatingProject, extraTargetDependencies, extraOptions);
const result = Object.values(taskResults).some((taskResult) => taskResult.status === 'failure' || taskResult.status === 'skipped')
? 1
: 0;
await (0, tasks_execution_hooks_1.runPostTasksExecution)({
taskResults,
workspaceRoot: workspace_root_1.workspaceRoot,
nxJsonConfiguration: nxJson,
});
return result;
});
return status;
}
async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
const projectNames = projectsToRun.map((t) => t.name);
const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
const tasks = Object.values(taskGraph.tasks);
const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides);
const taskResults = await invokeTasksRunner({
tasks,
projectGraph,
taskGraph,
lifeCycle,
nxJson,
nxArgs,
loadDotEnvFiles: extraOptions.loadDotEnvFiles,
initiatingProject,
});
await renderIsDone;
await (0, nx_key_1.printNxKey)();
return taskResults;
}
async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions) {
let taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
if (nxArgs.skipSync) {
return { projectGraph, taskGraph };
}
// collect unique syncGenerators from the tasks
const uniqueSyncGenerators = (0, sync_generators_1.collectEnabledTaskSyncGeneratorsFromTaskGraph)(taskGraph, projectGraph, nxJson);
if (!uniqueSyncGenerators.size) {
// There are no sync generators registered in the tasks to run
return { projectGraph, taskGraph };
}
const syncGenerators = Array.from(uniqueSyncGenerators);
const results = await (0, sync_generators_1.getSyncGeneratorChanges)(syncGenerators);
if (!results.length) {
// There are no changes to sync, workspace is up to date
return { projectGraph, taskGraph };
}
const { failedGeneratorsCount, areAllResultsFailures, anySyncGeneratorsFailed, } = (0, sync_generators_1.processSyncGeneratorResultErrors)(results);
const failedSyncGeneratorsFixMessageLines = (0, sync_generators_1.getFailedSyncGeneratorsFixMessageLines)(results, nxArgs.verbose);
const outOfSyncTitle = 'The workspace is out of sync';
const resultBodyLines = (0, sync_generators_1.getSyncGeneratorSuccessResultsMessageLines)(results);
const fixMessage = 'Make sure to run `nx sync` to apply the identified changes or set `sync.applyChanges` to `true` in your `nx.json` to apply them automatically when running tasks in interactive environments.';
const willErrorOnCiMessage = 'This will result in an error in CI.';
if ((0, is_ci_1.isCI)() || !process.stdout.isTTY) {
// If the user is running in CI or is running in a non-TTY environment we
// throw an error to stop the execution of the tasks.
if (areAllResultsFailures) {
output_1.output.error({
title: `The workspace is probably out of sync because ${failedGeneratorsCount === 1
? 'a sync generator'
: 'some sync generators'} failed to run`,
bodyLines: failedSyncGeneratorsFixMessageLines,
});
}
else {
output_1.output.error({
title: outOfSyncTitle,
bodyLines: [...resultBodyLines, '', fixMessage],
});
if (anySyncGeneratorsFailed) {
output_1.output.error({
title: failedGeneratorsCount === 1
? 'A sync generator failed to run'
: 'Some sync generators failed to run',
bodyLines: failedSyncGeneratorsFixMessageLines,
});
}
}
process.exit(1);
}
if (areAllResultsFailures) {
output_1.output.warn({
title: `The workspace is probably out of sync because ${failedGeneratorsCount === 1
? 'a sync generator'
: 'some sync generators'} failed to run`,
bodyLines: failedSyncGeneratorsFixMessageLines,
});
await confirmRunningTasksWithSyncFailures();
// if all sync generators failed to run there's nothing to sync, we just let the tasks run
return { projectGraph, taskGraph };
}
if (nxJson.sync?.applyChanges === false) {
// If the user has set `sync.applyChanges` to `false` in their `nx.json`
// we don't prompt the them and just log a warning informing them that
// the workspace is out of sync and they have it set to not apply changes
// automatically.
output_1.output.warn({
title: outOfSyncTitle,
bodyLines: [
...resultBodyLines,
'',
'Your workspace is set to not apply the identified changes automatically (`sync.applyChanges` is set to `false` in your `nx.json`).',
willErrorOnCiMessage,
fixMessage,
],
});
if (anySyncGeneratorsFailed) {
output_1.output.warn({
title: failedGeneratorsCount === 1
? 'A sync generator failed to run'
: 'Some sync generators failed to run',
bodyLines: failedSyncGeneratorsFixMessageLines,
});
await confirmRunningTasksWithSyncFailures();
}
return { projectGraph, taskGraph };
}
output_1.output.warn({
title: outOfSyncTitle,
bodyLines: [
...resultBodyLines,
'',
nxJson.sync?.applyChanges === true
? 'Proceeding to sync the identified changes automatically (`sync.applyChanges` is set to `true` in your `nx.json`).'
: willErrorOnCiMessage,
],
});
const applyChanges = nxJson.sync?.applyChanges === true ||
(await promptForApplyingSyncGeneratorChanges());
if (applyChanges) {
const spinner = ora('Syncing the workspace...');
spinner.start();
// Flush sync generator changes to disk
const flushResult = await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
if ('generatorFailures' in flushResult) {
spinner.fail();
output_1.output.error({
title: 'Failed to sync the workspace',
bodyLines: [
...(0, sync_generators_1.getFlushFailureMessageLines)(flushResult, nxArgs.verbose),
...(flushResult.generalFailure
? [
'If needed, you can run the tasks with the `--skip-sync` flag to disable syncing.',
]
: []),
],
});
await confirmRunningTasksWithSyncFailures();
}
// Re-create project graph and task graph
projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
const successTitle = anySyncGeneratorsFailed
? // the identified changes were synced successfully, but the workspace
// is still not up to date, which we'll mention next
'The identified changes were synced successfully!'
: // the workspace is fully up to date
'The workspace was synced successfully!';
const successSubtitle = nxJson.sync?.applyChanges === true
? 'Please make sure to commit the changes to your repository or this will error in CI.'
: // The user was prompted and we already logged a message about erroring in CI
// so here we just tell them to commit the changes.
'Please make sure to commit the changes to your repository.';
spinner.succeed(`${successTitle}\n\n${successSubtitle}`);
if (anySyncGeneratorsFailed) {
output_1.output.warn({
title: `The workspace is probably still out of sync because ${failedGeneratorsCount === 1
? 'a sync generator'
: 'some sync generators'} failed to run`,
bodyLines: failedSyncGeneratorsFixMessageLines,
});
await confirmRunningTasksWithSyncFailures();
}
}
else {
if (anySyncGeneratorsFailed) {
output_1.output.warn({
title: failedGeneratorsCount === 1
? 'A sync generator failed to report the sync status'
: 'Some sync generators failed to report the sync status',
bodyLines: failedSyncGeneratorsFixMessageLines,
});
await confirmRunningTasksWithSyncFailures();
}
else {
output_1.output.warn({
title: 'Syncing the workspace was skipped',
bodyLines: [
'This could lead to unexpected results or errors when running tasks.',
fixMessage,
],
});
}
}
return { projectGraph, taskGraph };
}
async function promptForApplyingSyncGeneratorChanges() {
try {
const promptConfig = {
name: 'applyChanges',
type: 'autocomplete',
message: 'Would you like to sync the identified changes to get your workspace up to date?',
choices: [
{
name: 'yes',
message: 'Yes, sync the changes and run the tasks',
},
{
name: 'no',
message: 'No, run the tasks without syncing the changes',
},
],
footer: () => chalk.dim('\nYou can skip this prompt by setting the `sync.applyChanges` option to `true` in your `nx.json`.\nFor more information, refer to the docs: https://nx.dev/concepts/sync-generators.'),
};
return await (0, enquirer_1.prompt)([promptConfig]).then(({ applyChanges }) => applyChanges === 'yes');
}
catch {
process.exit(1);
}
}
async function confirmRunningTasksWithSyncFailures() {
try {
const promptConfig = {
name: 'runTasks',
type: 'autocomplete',
message: 'Would you like to ignore the sync failures and continue running the tasks?',
choices: [
{
name: 'yes',
message: 'Yes, ignore the failures and run the tasks',
},
{
name: 'no',
message: `No, don't run the tasks`,
},
],
footer: () => chalk.dim(`\nWhen running in CI and there are sync failures, the tasks won't run. Addressing the errors above is highly recommended to prevent failures in CI.`),
};
const runTasks = await (0, enquirer_1.prompt)([
promptConfig,
]).then(({ runTasks }) => runTasks === 'yes');
if (!runTasks) {
process.exit(1);
}
}
catch {
process.exit(1);
}
}
function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
if (nxArgs.outputStyle == 'stream' ||
process.env.NX_BATCH_MODE === 'true' ||
nxArgs.batch) {
process.env.NX_STREAM_OUTPUT = 'true';
process.env.NX_PREFIX_OUTPUT = 'true';
}
if (nxArgs.outputStyle == 'stream-without-prefixes') {
process.env.NX_STREAM_OUTPUT = 'true';
}
if (loadDotEnvFiles) {
process.env.NX_LOAD_DOT_ENV_FILES = 'true';
}
}
async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, }) {
setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles);
// this needs to be done before we start to run the tasks
const taskDetails = (0, hash_task_1.getTaskDetails)();
const { tasksRunner, runnerOptions } = getRunner(nxArgs, nxJson);
let hasher = (0, create_task_hasher_1.createTaskHasher)(projectGraph, nxJson, runnerOptions);
// this is used for two reasons: to fetch all remote cache hits AND
// to submit everything that is known in advance to Nx Cloud to run in
// a distributed fashion
await (0, hash_task_1.hashTasksThatDoNotDependOnOutputsOfOtherTasks)(hasher, projectGraph, taskGraph, nxJson, taskDetails);
const taskResultsLifecycle = new task_results_life_cycle_1.TaskResultsLifeCycle();
const compositedLifeCycle = new life_cycle_1.CompositeLifeCycle([
...constructLifeCycles(lifeCycle),
taskResultsLifecycle,
]);
let promiseOrObservable = tasksRunner(tasks, {
...runnerOptions,
lifeCycle: compositedLifeCycle,
}, {
initiatingProject: nxArgs.outputStyle === 'compact' ? null : initiatingProject,
projectGraph,
nxJson,
nxArgs,
taskGraph,
hasher: {
hashTask(task, taskGraph_, env) {
if (!taskGraph_) {
output_1.output.warn({
title: `TaskGraph is now required as an argument to hashTask`,
bodyLines: [
`The TaskGraph object can be retrieved from the context`,
'This will result in an error in Nx 20',
],
});
taskGraph_ = taskGraph;
}
if (!env) {
output_1.output.warn({
title: `The environment variables are now required as an argument to hashTask`,
bodyLines: [
`Please pass the environment variables used when running the task`,
'This will result in an error in Nx 20',
],
});
env = process.env;
}
return hasher.hashTask(task, taskGraph_, env);
},
hashTasks(task, taskGraph_, env) {
if (!taskGraph_) {
output_1.output.warn({
title: `TaskGraph is now required as an argument to hashTasks`,
bodyLines: [
`The TaskGraph object can be retrieved from the context`,
'This will result in an error in Nx 20',
],
});
taskGraph_ = taskGraph;
}
if (!env) {
output_1.output.warn({
title: `The environment variables are now required as an argument to hashTasks`,
bodyLines: [
`Please pass the environment variables used when running the tasks`,
'This will result in an error in Nx 20',
],
});
env = process.env;
}
return hasher.hashTasks(task, taskGraph_, env);
},
},
daemon: client_1.daemonClient,
});
if (promiseOrObservable.subscribe) {
promiseOrObservable = convertObservableToPromise(promiseOrObservable);
}
await promiseOrObservable;
return taskResultsLifecycle.getTaskResults();
}
function constructLifeCycles(lifeCycle) {
const lifeCycles = [];
lifeCycles.push(new store_run_information_life_cycle_1.StoreRunInformationLifeCycle());
lifeCycles.push(lifeCycle);
if (process.env.NX_PERF_LOGGING === 'true') {
lifeCycles.push(new task_timings_life_cycle_1.TaskTimingsLifeCycle());
}
if (process.env.NX_PROFILE) {
lifeCycles.push(new task_profiling_life_cycle_1.TaskProfilingLifeCycle(process.env.NX_PROFILE));
}
if (!(0, nx_cloud_utils_1.isNxCloudUsed)((0, nx_json_1.readNxJson)())) {
lifeCycles.push(process.env.NX_DISABLE_DB !== 'true' && !native_1.IS_WASM
? new task_history_life_cycle_1.TaskHistoryLifeCycle()
: new task_history_life_cycle_old_1.LegacyTaskHistoryLifeCycle());
}
return lifeCycles;
}
async function convertObservableToPromise(obs) {
return await new Promise((res) => {
let tasksResults = {};
obs.subscribe({
next: (t) => {
tasksResults[t.task.id] = t.success ? 'success' : 'failure';
},
error: (error) => {
output_1.output.error({
title: 'Unhandled error in task executor',
});
console.error(error);
res(tasksResults);
},
complete: () => {
res(tasksResults);
},
});
});
}
function shouldUseDynamicLifeCycle(tasks, options, outputStyle) {
if (process.env.NX_BATCH_MODE === 'true' ||
process.env.NX_VERBOSE_LOGGING === 'true' ||
process.env.NX_TASKS_RUNNER_DYNAMIC_OUTPUT === 'false') {
return false;
}
if (!process.stdout.isTTY)
return false;
if ((0, is_ci_1.isCI)())
return false;
if (outputStyle === 'static' || outputStyle === 'stream')
return false;
return !tasks.find((t) => (0, utils_1.shouldStreamOutput)(t, null));
}
function loadTasksRunner(modulePath) {
try {
const maybeTasksRunner = require(modulePath);
// to support both babel and ts formats
return 'default' in maybeTasksRunner
? maybeTasksRunner.default
: maybeTasksRunner;
}
catch (e) {
if (e.code === 'MODULE_NOT_FOUND' &&
(modulePath === 'nx-cloud' || modulePath === '@nrwl/nx-cloud')) {
return require('../nx-cloud/nx-cloud-tasks-runner-shell')
.nxCloudTasksRunnerShell;
}
throw e;
}
}
function getRunner(nxArgs, nxJson) {
let runner = nxArgs.runner;
runner = runner ?? 'default';
if (runner !== 'default' && !nxJson.tasksRunnerOptions?.[runner]) {
throw new Error(`Could not find runner configuration for ${runner}`);
}
const modulePath = getTasksRunnerPath(runner, nxJson);
try {
if (isCustomRunnerPath(modulePath)) {
output_1.output.warn({
title: `Custom task runners will be replaced by a new API starting with Nx 21.`,
bodyLines: [
`For more information, see https://nx.dev/deprecated/custom-tasks-runner`,
],
});
}
const tasksRunner = loadTasksRunner(modulePath);
return {
tasksRunner,
runnerOptions: getRunnerOptions(runner, nxJson, nxArgs, modulePath === 'nx-cloud'),
};
}
catch {
throw new Error(`Could not find runner configuration for ${runner}`);
}
}
const defaultTasksRunnerPath = require.resolve('./default-tasks-runner');
function getTasksRunnerPath(runner, nxJson) {
let modulePath = nxJson.tasksRunnerOptions?.[runner]?.runner;
if (modulePath) {
if ((0, fileutils_1.isRelativePath)(modulePath)) {
return (0, path_1.join)(workspace_root_1.workspaceRoot, modulePath);
}
return modulePath;
}
const isCloudRunner =
// No tasksRunnerOptions for given --runner
nxJson.nxCloudAccessToken ||
// No runner prop in tasks runner options, check if access token is set.
nxJson.tasksRunnerOptions?.[runner]?.options?.accessToken ||
// Cloud access token specified in env var.
process.env.NX_CLOUD_ACCESS_TOKEN ||
// Nx Cloud ID specified in nxJson
nxJson.nxCloudId;
return isCloudRunner ? 'nx-cloud' : defaultTasksRunnerPath;
}
function getRunnerOptions(runner, nxJson, nxArgs, isCloudDefault) {
const defaultCacheableOperations = [];
for (const key in nxJson.targetDefaults) {
if (nxJson.targetDefaults[key].cache) {
defaultCacheableOperations.push(key);
}
}
const result = {
...nxJson.tasksRunnerOptions?.[runner]?.options,
...nxArgs,
};
// NOTE: we don't pull from env here because the cloud package
// supports it within nx-cloud's implementation. We could
// normalize it here, and that may make more sense, but
// leaving it as is for now.
if (nxJson.nxCloudAccessToken && isCloudDefault) {
result.accessToken ??= nxJson.nxCloudAccessToken;
}
if (nxJson.nxCloudId && isCloudDefault) {
result.nxCloudId ??= nxJson.nxCloudId;
}
if (nxJson.nxCloudUrl && isCloudDefault) {
result.url ??= nxJson.nxCloudUrl;
}
if (nxJson.nxCloudEncryptionKey && isCloudDefault) {
result.encryptionKey ??= nxJson.nxCloudEncryptionKey;
}
if (nxJson.parallel) {
result.parallel ??= nxJson.parallel;
}
if (nxJson.cacheDirectory) {
result.cacheDirectory ??= nxJson.cacheDirectory;
}
if (defaultCacheableOperations.length) {
result.cacheableOperations ??= [];
result.cacheableOperations = result.cacheableOperations.concat(defaultCacheableOperations);
}
if (nxJson.useDaemonProcess !== undefined) {
result.useDaemonProcess ??= nxJson.useDaemonProcess;
}
return result;
}
function isCustomRunnerPath(modulePath) {
return ![
'nx-cloud',
'@nrwl/nx-cloud',
'nx/tasks-runners/default',
defaultTasksRunnerPath,
].includes(modulePath);
}