feat(core): improve outputs when using --parallel and --with-deps
This commit is contained in:
parent
b671959f68
commit
0b7535ae92
@ -61,7 +61,9 @@ forEachCli(cliName => {
|
|||||||
expect(buildWithDeps).toContain(`${cliCommand} run ${mylib2}:build`);
|
expect(buildWithDeps).toContain(`${cliCommand} run ${mylib2}:build`);
|
||||||
|
|
||||||
const testsWithDeps = runCLI(`test ${myapp} --with-deps`);
|
const testsWithDeps = runCLI(`test ${myapp} --with-deps`);
|
||||||
expect(testsWithDeps).toContain(`NX Running target test for projects:`);
|
expect(testsWithDeps).toContain(
|
||||||
|
`NX Running target test for project ${myapp} and its 2 deps`
|
||||||
|
);
|
||||||
expect(testsWithDeps).toContain(myapp);
|
expect(testsWithDeps).toContain(myapp);
|
||||||
expect(testsWithDeps).toContain(mylib1);
|
expect(testsWithDeps).toContain(mylib1);
|
||||||
expect(testsWithDeps).toContain(mylib2);
|
expect(testsWithDeps).toContain(mylib2);
|
||||||
@ -647,15 +649,27 @@ forEachCli(cliName => {
|
|||||||
]);
|
]);
|
||||||
}, 120000);
|
}, 120000);
|
||||||
|
|
||||||
function expectCached(actual: string, expected: string[]) {
|
function expectCached(
|
||||||
const section = actual.split('read the output from cache')[1];
|
actualOutput: string,
|
||||||
const r = section
|
expectedCachedProjects: string[]
|
||||||
.split('\n')
|
) {
|
||||||
.filter(l => l.trim().startsWith('-'))
|
const cachedProjects = [];
|
||||||
.map(l => l.split('- ')[1].trim());
|
const lines = actualOutput.split('\n');
|
||||||
r.sort((a, b) => a.localeCompare(b));
|
lines.forEach((s, i) => {
|
||||||
expected.sort((a, b) => a.localeCompare(b));
|
if (s.startsWith(`> ${cliCommand} run`)) {
|
||||||
expect(r).toEqual(expected);
|
const projectName = s
|
||||||
|
.split(`> ${cliCommand} run `)[1]
|
||||||
|
.split(':')[0]
|
||||||
|
.trim();
|
||||||
|
if (lines[i + 2].indexOf('Cached Output') > -1) {
|
||||||
|
cachedProjects.push(projectName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cachedProjects.sort((a, b) => a.localeCompare(b));
|
||||||
|
expectedCachedProjects.sort((a, b) => a.localeCompare(b));
|
||||||
|
expect(cachedProjects).toEqual(expectedCachedProjects);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,7 +5,10 @@ import { findWorkspaceRoot } from './find-workspace-root';
|
|||||||
const workspace = findWorkspaceRoot(process.cwd());
|
const workspace = findWorkspaceRoot(process.cwd());
|
||||||
|
|
||||||
if (process.env.NX_TERMINAL_OUTPUT_PATH) {
|
if (process.env.NX_TERMINAL_OUTPUT_PATH) {
|
||||||
setUpOutputWatching(process.env.NX_TERMINAL_CAPTURE_STDERR === 'true');
|
setUpOutputWatching(
|
||||||
|
process.env.NX_TERMINAL_CAPTURE_STDERR === 'true',
|
||||||
|
process.env.NX_FORWARD_OUTPUT === 'true'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
requireCli();
|
requireCli();
|
||||||
|
|
||||||
@ -40,11 +43,12 @@ function requireCli() {
|
|||||||
* And the cached output should be correct unless the CLI bypasses process.stdout or console.log and uses some
|
* And the cached output should be correct unless the CLI bypasses process.stdout or console.log and uses some
|
||||||
* C-binary to write to stdout.
|
* C-binary to write to stdout.
|
||||||
*/
|
*/
|
||||||
function setUpOutputWatching(captureStderr: boolean) {
|
function setUpOutputWatching(captureStderr: boolean, forwardOutput: boolean) {
|
||||||
const stdoutWrite = process.stdout._write;
|
const stdoutWrite = process.stdout._write;
|
||||||
const stderrWrite = process.stderr._write;
|
const stderrWrite = process.stderr._write;
|
||||||
|
|
||||||
let out = [];
|
let out = [];
|
||||||
|
let outWithErr = [];
|
||||||
|
|
||||||
process.stdout._write = (
|
process.stdout._write = (
|
||||||
chunk: any,
|
chunk: any,
|
||||||
@ -52,7 +56,12 @@ function setUpOutputWatching(captureStderr: boolean) {
|
|||||||
callback: Function
|
callback: Function
|
||||||
) => {
|
) => {
|
||||||
out.push(chunk.toString());
|
out.push(chunk.toString());
|
||||||
stdoutWrite.apply(process.stdout, [chunk, encoding, callback]);
|
outWithErr.push(chunk.toString());
|
||||||
|
if (forwardOutput) {
|
||||||
|
stdoutWrite.apply(process.stdout, [chunk, encoding, callback]);
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
process.stderr._write = (
|
process.stderr._write = (
|
||||||
@ -60,15 +69,27 @@ function setUpOutputWatching(captureStderr: boolean) {
|
|||||||
encoding: string,
|
encoding: string,
|
||||||
callback: Function
|
callback: Function
|
||||||
) => {
|
) => {
|
||||||
if (captureStderr) {
|
outWithErr.push(chunk.toString());
|
||||||
out.push(chunk.toString());
|
if (forwardOutput) {
|
||||||
|
stderrWrite.apply(process.stderr, [chunk, encoding, callback]);
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
}
|
}
|
||||||
stderrWrite.apply(process.stderr, [chunk, encoding, callback]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
process.on('exit', code => {
|
process.on('exit', code => {
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
fs.writeFileSync(process.env.NX_TERMINAL_OUTPUT_PATH, out.join(''));
|
fs.writeFileSync(
|
||||||
|
process.env.NX_TERMINAL_OUTPUT_PATH,
|
||||||
|
captureStderr ? outWithErr.join('') : out.join('')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (!forwardOutput) {
|
||||||
|
fs.writeFileSync(
|
||||||
|
process.env.NX_TERMINAL_OUTPUT_PATH,
|
||||||
|
outWithErr.join('')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,7 +115,8 @@ export function affected(command: string, parsedArgs: yargs.Arguments): void {
|
|||||||
env,
|
env,
|
||||||
nxArgs,
|
nxArgs,
|
||||||
overrides,
|
overrides,
|
||||||
new DefaultReporter()
|
new DefaultReporter(),
|
||||||
|
null
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { runCommand } from '../tasks-runner/run-command';
|
|||||||
import { NxArgs, splitArgsIntoNxArgsAndOverrides } from './utils';
|
import { NxArgs, splitArgsIntoNxArgsAndOverrides } from './utils';
|
||||||
import {
|
import {
|
||||||
createProjectGraph,
|
createProjectGraph,
|
||||||
|
isWorkspaceProject,
|
||||||
|
onlyWorkspaceProjects,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectGraphNode,
|
ProjectGraphNode,
|
||||||
withDeps
|
withDeps
|
||||||
@ -30,7 +32,8 @@ export function runMany(parsedArgs: yargs.Arguments): void {
|
|||||||
env,
|
env,
|
||||||
nxArgs,
|
nxArgs,
|
||||||
overrides,
|
overrides,
|
||||||
new DefaultReporter()
|
new DefaultReporter(),
|
||||||
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +78,7 @@ function runnableForTarget(
|
|||||||
for (let project of projects) {
|
for (let project of projects) {
|
||||||
if (projectHasTarget(project, target)) {
|
if (projectHasTarget(project, target)) {
|
||||||
runnable.push(project);
|
runnable.push(project);
|
||||||
} else {
|
} else if (isWorkspaceProject(project)) {
|
||||||
notRunnable.push(project);
|
notRunnable.push(project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,10 +30,20 @@ export function runOne(opts: {
|
|||||||
);
|
);
|
||||||
const env = readEnvironment(opts.target, projectsMap);
|
const env = readEnvironment(opts.target, projectsMap);
|
||||||
const reporter = nxArgs.withDeps
|
const reporter = nxArgs.withDeps
|
||||||
? new (require(`../tasks-runner/default-reporter`)).DefaultReporter()
|
? new (require(`../tasks-runner/run-one-reporter`)).RunOneReporter(
|
||||||
|
opts.project
|
||||||
|
)
|
||||||
: new EmptyReporter();
|
: new EmptyReporter();
|
||||||
|
|
||||||
runCommand(projects, projectGraph, env, nxArgs, overrides, reporter);
|
runCommand(
|
||||||
|
projects,
|
||||||
|
projectGraph,
|
||||||
|
env,
|
||||||
|
nxArgs,
|
||||||
|
overrides,
|
||||||
|
reporter,
|
||||||
|
opts.project
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProjects(
|
function getProjects(
|
||||||
|
|||||||
@ -7,21 +7,21 @@ export interface ReporterArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class DefaultReporter {
|
export class DefaultReporter {
|
||||||
beforeRun(
|
private projectNames: string[];
|
||||||
affectedProjectNames: string[],
|
|
||||||
affectedArgs: ReporterArgs,
|
beforeRun(projectNames: string[], args: ReporterArgs, taskOverrides: any) {
|
||||||
taskOverrides: any
|
this.projectNames = projectNames;
|
||||||
) {
|
|
||||||
if (affectedProjectNames.length <= 0) {
|
if (projectNames.length <= 0) {
|
||||||
let description = `with "${affectedArgs.target}"`;
|
let description = `with "${args.target}"`;
|
||||||
if (affectedArgs.configuration) {
|
if (args.configuration) {
|
||||||
description += ` that are configured for "${affectedArgs.configuration}"`;
|
description += ` that are configured for "${args.configuration}"`;
|
||||||
}
|
}
|
||||||
output.logSingleLine(`No projects ${description} were run`);
|
output.logSingleLine(`No projects ${description} were run`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bodyLines = affectedProjectNames.map(
|
const bodyLines = projectNames.map(
|
||||||
affectedProject => `${output.colors.gray('-')} ${affectedProject}`
|
affectedProject => `${output.colors.gray('-')} ${affectedProject}`
|
||||||
);
|
);
|
||||||
if (Object.keys(taskOverrides).length > 0) {
|
if (Object.keys(taskOverrides).length > 0) {
|
||||||
@ -34,29 +34,39 @@ export class DefaultReporter {
|
|||||||
|
|
||||||
output.log({
|
output.log({
|
||||||
title: `${output.colors.gray('Running target')} ${
|
title: `${output.colors.gray('Running target')} ${
|
||||||
affectedArgs.target
|
args.target
|
||||||
} ${output.colors.gray('for projects:')}`,
|
} ${output.colors.gray('for projects:')}`,
|
||||||
bodyLines
|
bodyLines
|
||||||
});
|
});
|
||||||
|
|
||||||
output.addVerticalSeparator();
|
output.addVerticalSeparatorWithoutNewLines();
|
||||||
}
|
}
|
||||||
|
|
||||||
printResults(
|
printResults(
|
||||||
affectedArgs: ReporterArgs,
|
args: ReporterArgs,
|
||||||
failedProjectNames: string[],
|
failedProjectNames: string[],
|
||||||
startedWithFailedProjects: boolean,
|
startedWithFailedProjects: boolean,
|
||||||
cachedProjectNames: string[]
|
cachedProjectNames: string[]
|
||||||
) {
|
) {
|
||||||
output.addNewline();
|
output.addNewline();
|
||||||
output.addVerticalSeparator();
|
output.addVerticalSeparatorWithoutNewLines();
|
||||||
|
|
||||||
if (failedProjectNames.length === 0) {
|
if (failedProjectNames.length === 0) {
|
||||||
|
const bodyLines =
|
||||||
|
cachedProjectNames.length > 0
|
||||||
|
? [
|
||||||
|
output.colors.gray(
|
||||||
|
`Nx read the output from cache instead of running the command for ${cachedProjectNames.length} out of ${this.projectNames.length} projects.`
|
||||||
|
)
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
output.success({
|
output.success({
|
||||||
title: `Running target "${affectedArgs.target}" succeeded`
|
title: `Running target "${args.target}" succeeded`,
|
||||||
|
bodyLines
|
||||||
});
|
});
|
||||||
|
|
||||||
if (affectedArgs.onlyFailed && startedWithFailedProjects) {
|
if (args.onlyFailed && startedWithFailedProjects) {
|
||||||
output.warn({
|
output.warn({
|
||||||
title: `Only projects ${output.underline(
|
title: `Only projects ${output.underline(
|
||||||
'which had previously failed'
|
'which had previously failed'
|
||||||
@ -76,7 +86,7 @@ export class DefaultReporter {
|
|||||||
project => `${output.colors.gray('-')} ${project}`
|
project => `${output.colors.gray('-')} ${project}`
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
if (!affectedArgs.onlyFailed && !startedWithFailedProjects) {
|
if (!args.onlyFailed && !startedWithFailedProjects) {
|
||||||
bodyLines.push('');
|
bodyLines.push('');
|
||||||
bodyLines.push(
|
bodyLines.push(
|
||||||
`${output.colors.gray(
|
`${output.colors.gray(
|
||||||
@ -85,17 +95,7 @@ export class DefaultReporter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
output.error({
|
output.error({
|
||||||
title: `Running target "${affectedArgs.target}" failed`,
|
title: `Running target "${args.target}" failed`,
|
||||||
bodyLines
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cachedProjectNames.length > 0) {
|
|
||||||
const bodyLines = cachedProjectNames.map(
|
|
||||||
project => `${output.colors.gray('-')} ${project}`
|
|
||||||
);
|
|
||||||
output.note({
|
|
||||||
title: `Nx read the output from cache instead of running the command for the following projects:`,
|
|
||||||
bodyLines
|
bodyLines
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,7 +40,12 @@ export interface DefaultTasksRunnerOptions {
|
|||||||
export const defaultTasksRunner: TasksRunner<DefaultTasksRunnerOptions> = (
|
export const defaultTasksRunner: TasksRunner<DefaultTasksRunnerOptions> = (
|
||||||
tasks: Task[],
|
tasks: Task[],
|
||||||
options: DefaultTasksRunnerOptions,
|
options: DefaultTasksRunnerOptions,
|
||||||
context: { target: string; projectGraph: ProjectGraph; nxJson: NxJson }
|
context: {
|
||||||
|
target: string;
|
||||||
|
initiatingProject?: string;
|
||||||
|
projectGraph: ProjectGraph;
|
||||||
|
nxJson: NxJson;
|
||||||
|
}
|
||||||
): Observable<TaskCompleteEvent> => {
|
): Observable<TaskCompleteEvent> => {
|
||||||
if (!options.lifeCycle) {
|
if (!options.lifeCycle) {
|
||||||
options.lifeCycle = new NoopLifeCycle();
|
options.lifeCycle = new NoopLifeCycle();
|
||||||
@ -65,14 +70,23 @@ export const defaultTasksRunner: TasksRunner<DefaultTasksRunnerOptions> = (
|
|||||||
async function runAllTasks(
|
async function runAllTasks(
|
||||||
tasks: Task[],
|
tasks: Task[],
|
||||||
options: DefaultTasksRunnerOptions,
|
options: DefaultTasksRunnerOptions,
|
||||||
context: { target: string; projectGraph: ProjectGraph; nxJson: NxJson }
|
context: {
|
||||||
|
target: string;
|
||||||
|
initiatingProject?: string;
|
||||||
|
projectGraph: ProjectGraph;
|
||||||
|
nxJson: NxJson;
|
||||||
|
}
|
||||||
): Promise<Array<{ task: Task; type: any; success: boolean }>> {
|
): Promise<Array<{ task: Task; type: any; success: boolean }>> {
|
||||||
const stages = new TaskOrderer(
|
const stages = new TaskOrderer(
|
||||||
context.target,
|
context.target,
|
||||||
context.projectGraph
|
context.projectGraph
|
||||||
).splitTasksIntoStages(tasks);
|
).splitTasksIntoStages(tasks);
|
||||||
|
|
||||||
const orchestrator = new TaskOrchestrator(context.projectGraph, options);
|
const orchestrator = new TaskOrchestrator(
|
||||||
|
context.initiatingProject,
|
||||||
|
context.projectGraph,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
const res = [];
|
const res = [];
|
||||||
for (let i = 0; i < stages.length; ++i) {
|
for (let i = 0; i < stages.length; ++i) {
|
||||||
|
|||||||
@ -18,7 +18,8 @@ export async function runCommand<T extends RunArgs>(
|
|||||||
{ nxJson, workspaceResults }: Environment,
|
{ nxJson, workspaceResults }: Environment,
|
||||||
nxArgs: NxArgs,
|
nxArgs: NxArgs,
|
||||||
overrides: any,
|
overrides: any,
|
||||||
reporter: any
|
reporter: any,
|
||||||
|
initiatingProject: string | null
|
||||||
) {
|
) {
|
||||||
reporter.beforeRun(projectsToRun.map(p => p.name), nxArgs, overrides);
|
reporter.beforeRun(projectsToRun.map(p => p.name), nxArgs, overrides);
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ export async function runCommand<T extends RunArgs>(
|
|||||||
|
|
||||||
const cached = [];
|
const cached = [];
|
||||||
tasksRunner(tasks, tasksOptions, {
|
tasksRunner(tasks, tasksOptions, {
|
||||||
|
initiatingProject: initiatingProject,
|
||||||
target: nxArgs.target,
|
target: nxArgs.target,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
nxJson
|
nxJson
|
||||||
|
|||||||
79
packages/workspace/src/tasks-runner/run-one-reporter.ts
Normal file
79
packages/workspace/src/tasks-runner/run-one-reporter.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
|
export interface ReporterArgs {
|
||||||
|
target?: string;
|
||||||
|
configuration?: string;
|
||||||
|
onlyFailed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RunOneReporter {
|
||||||
|
private projectNames: string[];
|
||||||
|
constructor(private readonly initiatingProject: string) {}
|
||||||
|
|
||||||
|
beforeRun(projectNames: string[], args: ReporterArgs, taskOverrides: any) {
|
||||||
|
this.projectNames = projectNames;
|
||||||
|
const numberOfDeps = projectNames.length - 1;
|
||||||
|
|
||||||
|
if (numberOfDeps > 0) {
|
||||||
|
output.log({
|
||||||
|
title: `${output.colors.gray('Running target')} ${
|
||||||
|
args.target
|
||||||
|
} ${output.colors.gray('for project')} ${
|
||||||
|
this.initiatingProject
|
||||||
|
} ${output.colors.gray(`and its ${numberOfDeps} deps.`)}`
|
||||||
|
});
|
||||||
|
output.addVerticalSeparatorWithoutNewLines();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printResults(
|
||||||
|
args: ReporterArgs,
|
||||||
|
failedProjectNames: string[],
|
||||||
|
startedWithFailedProjects: boolean,
|
||||||
|
cachedProjectNames: string[]
|
||||||
|
) {
|
||||||
|
output.addNewline();
|
||||||
|
output.addVerticalSeparatorWithoutNewLines();
|
||||||
|
|
||||||
|
if (failedProjectNames.length === 0) {
|
||||||
|
const bodyLines =
|
||||||
|
cachedProjectNames.length > 0
|
||||||
|
? [
|
||||||
|
output.colors.gray(
|
||||||
|
`Nx read the output from cache instead of running the command for ${cachedProjectNames.length} out of ${this.projectNames.length} projects.`
|
||||||
|
)
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
output.success({
|
||||||
|
title: `Running target "${args.target}" succeeded`,
|
||||||
|
bodyLines
|
||||||
|
});
|
||||||
|
|
||||||
|
if (args.onlyFailed && startedWithFailedProjects) {
|
||||||
|
output.warn({
|
||||||
|
title: `Only projects ${output.underline(
|
||||||
|
'which had previously failed'
|
||||||
|
)} were run`,
|
||||||
|
bodyLines: [
|
||||||
|
`You should verify by running ${output.underline(
|
||||||
|
'without'
|
||||||
|
)} ${output.bold('--only-failed')}`
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const bodyLines = [
|
||||||
|
output.colors.gray('Failed projects:'),
|
||||||
|
'',
|
||||||
|
...failedProjectNames.map(
|
||||||
|
project => `${output.colors.gray('-')} ${project}`
|
||||||
|
)
|
||||||
|
];
|
||||||
|
output.error({
|
||||||
|
title: `Running target "${args.target}" failed`,
|
||||||
|
bodyLines
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import { fork } from 'child_process';
|
|||||||
import { DefaultTasksRunnerOptions } from './default-tasks-runner';
|
import { DefaultTasksRunnerOptions } from './default-tasks-runner';
|
||||||
import { output } from '../utils/output';
|
import { output } from '../utils/output';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs';
|
||||||
import { appRootPath } from '../utils/app-root';
|
import { appRootPath } from '../utils/app-root';
|
||||||
|
|
||||||
export class TaskOrchestrator {
|
export class TaskOrchestrator {
|
||||||
@ -15,6 +16,7 @@ export class TaskOrchestrator {
|
|||||||
cli = cliCommand();
|
cli = cliCommand();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private readonly initiatingProject: string | undefined,
|
||||||
private readonly projectGraph: ProjectGraph,
|
private readonly projectGraph: ProjectGraph,
|
||||||
private readonly options: DefaultTasksRunnerOptions
|
private readonly options: DefaultTasksRunnerOptions
|
||||||
) {}
|
) {}
|
||||||
@ -93,8 +95,16 @@ export class TaskOrchestrator {
|
|||||||
tasks.forEach(t => {
|
tasks.forEach(t => {
|
||||||
this.options.lifeCycle.startTask(t.task);
|
this.options.lifeCycle.startTask(t.task);
|
||||||
|
|
||||||
output.note({ title: `Cached Output:` });
|
if (
|
||||||
process.stdout.write(t.cachedResult.terminalOutput);
|
!this.initiatingProject ||
|
||||||
|
this.initiatingProject === t.task.target.project
|
||||||
|
) {
|
||||||
|
const args = this.getCommandArgs(t.task);
|
||||||
|
output.logCommand(`${this.cli} ${args.join(' ')}`);
|
||||||
|
output.note({ title: `Cached Output:` });
|
||||||
|
process.stdout.write(t.cachedResult.terminalOutput);
|
||||||
|
}
|
||||||
|
|
||||||
const outputs = getOutputs(this.projectGraph.nodes, t.task);
|
const outputs = getOutputs(this.projectGraph.nodes, t.task);
|
||||||
this.cache.copyFilesFromCache(t.cachedResult, outputs);
|
this.cache.copyFilesFromCache(t.cachedResult, outputs);
|
||||||
|
|
||||||
@ -117,21 +127,25 @@ export class TaskOrchestrator {
|
|||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
try {
|
try {
|
||||||
this.options.lifeCycle.startTask(task);
|
this.options.lifeCycle.startTask(task);
|
||||||
|
const forwardOutput = this.shouldForwardOutput(outputPath, task);
|
||||||
const env = { ...process.env };
|
const env = this.envForForkedProcess(outputPath, forwardOutput);
|
||||||
if (outputPath) {
|
|
||||||
env.NX_TERMINAL_OUTPUT_PATH = outputPath;
|
|
||||||
if (this.options.captureStderr) {
|
|
||||||
env.NX_TERMINAL_CAPTURE_STDERR = 'true';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const args = this.getCommandArgs(task);
|
const args = this.getCommandArgs(task);
|
||||||
console.log(`> ${this.cli} ${args.join(' ')}`);
|
const commandLine = `${this.cli} ${args.join(' ')}`;
|
||||||
|
|
||||||
|
if (forwardOutput) {
|
||||||
|
output.logCommand(commandLine);
|
||||||
|
}
|
||||||
const p = fork(this.getCommand(), args, {
|
const p = fork(this.getCommand(), args, {
|
||||||
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
||||||
env
|
env
|
||||||
});
|
});
|
||||||
p.on('close', code => {
|
p.on('close', code => {
|
||||||
|
// we didn't print any output as we were running the command
|
||||||
|
// print all the collected output
|
||||||
|
if (!forwardOutput) {
|
||||||
|
output.logCommand(commandLine);
|
||||||
|
process.stdout.write(fs.readFileSync(outputPath));
|
||||||
|
}
|
||||||
if (outputPath && code === 0) {
|
if (outputPath && code === 0) {
|
||||||
this.cache.put(task, outputPath, taskOutputs).then(() => {
|
this.cache.put(task, outputPath, taskOutputs).then(() => {
|
||||||
this.options.lifeCycle.endTask(task, code);
|
this.options.lifeCycle.endTask(task, code);
|
||||||
@ -149,6 +163,27 @@ export class TaskOrchestrator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private envForForkedProcess(outputPath: string, forwardOutput: boolean) {
|
||||||
|
const env = { ...process.env };
|
||||||
|
if (outputPath) {
|
||||||
|
env.NX_TERMINAL_OUTPUT_PATH = outputPath;
|
||||||
|
if (this.options.captureStderr) {
|
||||||
|
env.NX_TERMINAL_CAPTURE_STDERR = 'true';
|
||||||
|
}
|
||||||
|
if (forwardOutput) {
|
||||||
|
env.NX_FORWARD_OUTPUT = 'true';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldForwardOutput(outputPath: string | undefined, task: Task) {
|
||||||
|
if (!outputPath) return true;
|
||||||
|
if (!this.options.parallel) return true;
|
||||||
|
if (task.target.project === this.initiatingProject) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private getCommand() {
|
private getCommand() {
|
||||||
return path.join(
|
return path.join(
|
||||||
this.workspaceRoot,
|
this.workspaceRoot,
|
||||||
|
|||||||
@ -31,6 +31,7 @@ export type TasksRunner<T = unknown> = (
|
|||||||
options: T,
|
options: T,
|
||||||
context?: {
|
context?: {
|
||||||
target?: string;
|
target?: string;
|
||||||
|
initiatingProject?: string | null;
|
||||||
projectGraph: ProjectGraph;
|
projectGraph: ProjectGraph;
|
||||||
nxJson: NxJson;
|
nxJson: NxJson;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export interface CLINoteMessageConfig {
|
|||||||
|
|
||||||
export interface CLISuccessMessageConfig {
|
export interface CLISuccessMessageConfig {
|
||||||
title: string;
|
title: string;
|
||||||
|
bodyLines?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,6 +87,10 @@ class CLIOutput {
|
|||||||
this.writeToStdOut(`\n${chalk.gray(this.VERTICAL_SEPARATOR)}\n\n`);
|
this.writeToStdOut(`\n${chalk.gray(this.VERTICAL_SEPARATOR)}\n\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addVerticalSeparatorWithoutNewLines() {
|
||||||
|
this.writeToStdOut(`${chalk.gray(this.VERTICAL_SEPARATOR)}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
error({ title, slug, bodyLines }: CLIErrorMessageConfig) {
|
error({ title, slug, bodyLines }: CLIErrorMessageConfig) {
|
||||||
this.addNewline();
|
this.addNewline();
|
||||||
|
|
||||||
@ -151,7 +156,7 @@ class CLIOutput {
|
|||||||
this.addNewline();
|
this.addNewline();
|
||||||
}
|
}
|
||||||
|
|
||||||
success({ title }: CLISuccessMessageConfig) {
|
success({ title, bodyLines }: CLISuccessMessageConfig) {
|
||||||
this.addNewline();
|
this.addNewline();
|
||||||
|
|
||||||
this.writeOutputTitle({
|
this.writeOutputTitle({
|
||||||
@ -159,6 +164,8 @@ class CLIOutput {
|
|||||||
title: chalk.bold.green(title)
|
title: chalk.bold.green(title)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.writeOptionalOutputBody(bodyLines);
|
||||||
|
|
||||||
this.addNewline();
|
this.addNewline();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +179,14 @@ class CLIOutput {
|
|||||||
this.addNewline();
|
this.addNewline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logCommand(message: string) {
|
||||||
|
this.addNewline();
|
||||||
|
|
||||||
|
this.writeToStdOut(chalk.bold(`> ${message} `));
|
||||||
|
|
||||||
|
this.addNewline();
|
||||||
|
}
|
||||||
|
|
||||||
log({ title, bodyLines }: CLIWarnMessageConfig) {
|
log({ title, bodyLines }: CLIWarnMessageConfig) {
|
||||||
this.addNewline();
|
this.addNewline();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user