nx/packages/workspace/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.ts

151 lines
4.3 KiB
TypeScript

import type { Task } from '@nrwl/devkit';
import { output, TaskCacheStatus } from '../../utilities/output';
import { TaskStatus } from '../tasks-runner';
import { getCommandArgsForTask } from '../utils';
import type { LifeCycle } from '../life-cycle';
/**
* The following life cycle's outputs are static, meaning no previous content
* is rewritten or modified as new outputs are added. It is therefore intended
* for use in CI environments.
*
* For the common case of a user executing a command on their local machine,
* the dynamic equivalent of this life cycle is usually preferable.
*/
export class StaticRunManyTerminalOutputLifeCycle implements LifeCycle {
failedTasks = [] as Task[];
cachedTasks = [] as Task[];
skippedTasks = [] as Task[];
constructor(
private readonly projectNames: string[],
private readonly tasks: Task[],
private readonly args: {
target?: string;
configuration?: string;
},
private readonly taskOverrides: any
) {}
startCommand(): void {
if (this.projectNames.length <= 0) {
let description = `with "${this.args.target}"`;
if (this.args.configuration) {
description += ` that are configured for "${this.args.configuration}"`;
}
output.logSingleLine(`No projects ${description} were run`);
return;
}
const bodyLines = this.projectNames.map(
(affectedProject) => ` ${output.colors.gray('-')} ${affectedProject}`
);
if (Object.keys(this.taskOverrides).length > 0) {
bodyLines.push('');
bodyLines.push(`${output.colors.gray('With flags:')}`);
Object.entries(this.taskOverrides)
.map(([flag, value]) => ` --${flag}=${value}`)
.forEach((arg) => bodyLines.push(arg));
}
let title = `Running target ${output.bold(
this.args.target
)} for ${output.bold(this.projectNames.length)} project(s)`;
const dependentTasksCount = this.tasks.length - this.projectNames.length;
if (dependentTasksCount > 0) {
title += ` and ${output.bold(
dependentTasksCount
)} task(s) they depend on`;
}
title += ':';
output.log({
color: 'cyan',
title,
bodyLines,
});
output.addVerticalSeparatorWithoutNewLines('cyan');
}
endCommand(): void {
output.addNewline();
if (this.failedTasks.length === 0) {
output.addVerticalSeparatorWithoutNewLines('green');
const bodyLines =
this.cachedTasks.length > 0
? [
output.colors.gray(
`Nx read the output from the cache instead of running the command for ${this.cachedTasks.length} out of ${this.tasks.length} tasks.`
),
]
: [];
output.success({
title: `Successfully ran target ${output.bold(
this.args.target
)} for ${output.bold(this.projectNames.length)} projects`,
bodyLines,
});
} else {
output.addVerticalSeparatorWithoutNewLines('red');
const bodyLines = [];
if (this.skippedTasks.length > 0) {
bodyLines.push(
output.colors.gray(
'Tasks not run because their dependencies failed:'
),
'',
...this.skippedTasks.map(
(task) => `${output.colors.gray('-')} ${task.id}`
),
''
);
}
bodyLines.push(
output.colors.gray('Failed tasks:'),
'',
...this.failedTasks.map(
(task) => `${output.colors.gray('-')} ${task.id}`
)
);
output.error({
title: `Running target "${this.args.target}" failed`,
bodyLines,
});
}
}
endTasks(
taskResults: { task: Task; status: TaskStatus; code: number }[]
): void {
for (let t of taskResults) {
if (t.status === 'failure') {
this.failedTasks.push(t.task);
} else if (t.status === 'skipped') {
this.skippedTasks.push(t.task);
} else if (t.status === 'local-cache') {
this.cachedTasks.push(t.task);
} else if (t.status === 'remote-cache') {
this.cachedTasks.push(t.task);
}
}
}
printTaskTerminalOutput(
task: Task,
cacheStatus: TaskCacheStatus,
terminalOutput: string
) {
const args = getCommandArgsForTask(task);
output.logCommand(
`${args.filter((a) => a !== 'run').join(' ')}`,
cacheStatus
);
process.stdout.write(terminalOutput);
}
}