feat(core): add second way of capturing output
This commit is contained in:
parent
a34af96093
commit
96a7f69d33
@ -26,9 +26,13 @@ forEachCli(() => {
|
||||
runCLIAsync(`generate @nrwl/angular:component test --project ${mylib}`),
|
||||
]);
|
||||
const appResult = await runCLIAsync(`test ${myapp} --no-watch`);
|
||||
expect(appResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
||||
expect(appResult.combinedOutput).toContain(
|
||||
'Test Suites: 3 passed, 3 total'
|
||||
);
|
||||
const libResult = await runCLIAsync(`test ${mylib}`);
|
||||
expect(libResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
||||
expect(libResult.combinedOutput).toContain(
|
||||
'Test Suites: 3 passed, 3 total'
|
||||
);
|
||||
done();
|
||||
}, 45000);
|
||||
|
||||
@ -66,7 +70,9 @@ forEachCli(() => {
|
||||
);
|
||||
|
||||
const appResult = await runCLIAsync(`test ${mylib} --no-watch`);
|
||||
expect(appResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(appResult.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
done();
|
||||
}, 45000);
|
||||
|
||||
@ -84,7 +90,9 @@ forEachCli(() => {
|
||||
`
|
||||
);
|
||||
const appResult = await runCLIAsync(`test ${mylib} --no-watch`);
|
||||
expect(appResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(appResult.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
done();
|
||||
}, 45000);
|
||||
});
|
||||
|
||||
@ -232,7 +232,9 @@ async function checkApp(
|
||||
}
|
||||
|
||||
const testResults = await runCLIAsync(`test ${appName}`);
|
||||
expect(testResults.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(testResults.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
|
||||
if (supportUi()) {
|
||||
const e2eResults = runCLI(`e2e ${appName}-e2e --headless`);
|
||||
|
||||
@ -82,7 +82,9 @@ forEachCli((currentCLIName) => {
|
||||
|
||||
updateFile(`apps/${nodeapp}/src/assets/file.txt`, ``);
|
||||
const jestResult = await runCLIAsync(`test ${nodeapp}`);
|
||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(jestResult.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
await runCLIAsync(`build ${nodeapp}`);
|
||||
|
||||
checkFilesExist(
|
||||
@ -192,7 +194,9 @@ forEachCli((currentCLIName) => {
|
||||
|
||||
updateFile(`apps/${nestapp}/src/assets/file.txt`, ``);
|
||||
const jestResult = await runCLIAsync(`test ${nestapp}`);
|
||||
expect(jestResult.stderr).toContain('Test Suites: 2 passed, 2 total');
|
||||
expect(jestResult.combinedOutput).toContain(
|
||||
'Test Suites: 2 passed, 2 total'
|
||||
);
|
||||
|
||||
await runCLIAsync(`build ${nestapp}`);
|
||||
|
||||
@ -256,7 +260,9 @@ forEachCli((currentCLIName) => {
|
||||
expect(lintResults).toContain('All files pass linting.');
|
||||
|
||||
const jestResult = await runCLIAsync(`test ${nodelib}`);
|
||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(jestResult.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
}, 60000);
|
||||
|
||||
it('should be able to generate a publishable node library', async () => {
|
||||
@ -358,7 +364,9 @@ forEachCli((currentCLIName) => {
|
||||
expect(lintResults).toContain('All files pass linting.');
|
||||
|
||||
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(jestResult.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
}, 60000);
|
||||
|
||||
it('should be able to generate a nest library w/ controller', async () => {
|
||||
@ -371,7 +379,9 @@ forEachCli((currentCLIName) => {
|
||||
expect(lintResults).toContain('All files pass linting.');
|
||||
|
||||
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(jestResult.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
}, 60000);
|
||||
|
||||
it('should be able to generate a nest library w/ controller and service', async () => {
|
||||
@ -384,7 +394,9 @@ forEachCli((currentCLIName) => {
|
||||
expect(lintResults).toContain('All files pass linting.');
|
||||
|
||||
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
||||
expect(jestResult.stderr).toContain('Test Suites: 2 passed, 2 total');
|
||||
expect(jestResult.combinedOutput).toContain(
|
||||
'Test Suites: 2 passed, 2 total'
|
||||
);
|
||||
}, 60000);
|
||||
});
|
||||
|
||||
|
||||
@ -36,7 +36,9 @@ forEachCli((currentCLIName) => {
|
||||
updateFile(mainPath, `import '@proj/${libName}';\n` + readFile(mainPath));
|
||||
|
||||
const libTestResults = await runCLIAsync(`test ${libName}`);
|
||||
expect(libTestResults.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(libTestResults.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
|
||||
await testGeneratedApp(appName, {
|
||||
checkStyles: true,
|
||||
@ -210,10 +212,14 @@ forEachCli((currentCLIName) => {
|
||||
runCLI(`g @nrwl/react:redux orange --project=${libName}`);
|
||||
|
||||
const appTestResults = await runCLIAsync(`test ${appName}`);
|
||||
expect(appTestResults.stderr).toContain('Test Suites: 2 passed, 2 total');
|
||||
expect(appTestResults.combinedOutput).toContain(
|
||||
'Test Suites: 2 passed, 2 total'
|
||||
);
|
||||
|
||||
const libTestResults = await runCLIAsync(`test ${libName}`);
|
||||
expect(libTestResults.stderr).toContain('Test Suites: 2 passed, 2 total');
|
||||
expect(libTestResults.combinedOutput).toContain(
|
||||
'Test Suites: 2 passed, 2 total'
|
||||
);
|
||||
}, 120000);
|
||||
|
||||
it('should be able to use JSX', async () => {
|
||||
@ -306,7 +312,9 @@ forEachCli((currentCLIName) => {
|
||||
}
|
||||
|
||||
const testResults = await runCLIAsync(`test ${appName}`);
|
||||
expect(testResults.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(testResults.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
|
||||
if (opts.checkE2E) {
|
||||
const e2eResults = runCLI(`e2e ${appName}-e2e`);
|
||||
|
||||
@ -172,19 +172,19 @@ export function runCommandAsync(
|
||||
silenceError: false,
|
||||
env: process.env,
|
||||
}
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
): Promise<{ stdout: string; stderr: string; combinedOutput: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(
|
||||
command,
|
||||
{
|
||||
cwd: tmpProjPath(),
|
||||
env: process.env,
|
||||
env: { ...process.env, FORCE_COLOR: 'false' },
|
||||
},
|
||||
(err, stdout, stderr) => {
|
||||
if (!opts.silenceError && err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve({ stdout, stderr });
|
||||
resolve({ stdout, stderr, combinedOutput: `${stdout}${stderr}` });
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -196,7 +196,7 @@ export function runCLIAsync(
|
||||
silenceError: false,
|
||||
env: process.env,
|
||||
}
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
): Promise<{ stdout: string; stderr: string; combinedOutput: string }> {
|
||||
return runCommandAsync(`./node_modules/.bin/nx ${command}`, opts);
|
||||
}
|
||||
|
||||
|
||||
@ -48,7 +48,9 @@ forEachCli((currentCLIName) => {
|
||||
`<link rel="stylesheet" href="styles.css">`
|
||||
);
|
||||
const testResults = await runCLIAsync(`test ${appName}`);
|
||||
expect(testResults.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
expect(testResults.combinedOutput).toContain(
|
||||
'Test Suites: 1 passed, 1 total'
|
||||
);
|
||||
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
||||
expect(lintE2eResults).toContain('All files pass linting.');
|
||||
|
||||
|
||||
@ -42,8 +42,10 @@ export class TaskOrchestrator {
|
||||
function takeFromQueue() {
|
||||
if (left.length > 0) {
|
||||
const task = left.pop();
|
||||
return that
|
||||
.forkProcess(task)
|
||||
const p = that.pipeOutputCapture(task)
|
||||
? that.forkProcessPipeOutputCapture(task)
|
||||
: that.forkProcessDirectOutputCapture(task);
|
||||
return p
|
||||
.then((code) => {
|
||||
res.push({
|
||||
task,
|
||||
@ -122,7 +124,82 @@ export class TaskOrchestrator {
|
||||
}, []);
|
||||
}
|
||||
|
||||
private forkProcess(task: Task) {
|
||||
private pipeOutputCapture(task: Task) {
|
||||
try {
|
||||
const p = this.projectGraph.nodes[task.target.project];
|
||||
const b = p.data.architect[task.target.target].builder;
|
||||
// this is temporary. we simply want to assess if pipeOutputCapture
|
||||
// works well before making it configurable
|
||||
return (
|
||||
this.cache.temporaryOutputPath(task) &&
|
||||
(b === '@nrwl/workspace:run-commands' || b === '@nrwl/cypress:cypress')
|
||||
);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private forkProcessPipeOutputCapture(task: Task) {
|
||||
const taskOutputs = getOutputs(this.projectGraph.nodes, task);
|
||||
const outputPath = this.cache.temporaryOutputPath(task);
|
||||
return new Promise((res, rej) => {
|
||||
try {
|
||||
this.options.lifeCycle.startTask(task);
|
||||
const forwardOutput = this.shouldForwardOutput(outputPath, task);
|
||||
const env = this.envForForkedProcess(task, undefined, forwardOutput);
|
||||
const args = this.getCommandArgs(task);
|
||||
const commandLine = `${this.cli} ${args.join(' ')}`;
|
||||
|
||||
if (forwardOutput) {
|
||||
output.logCommand(commandLine);
|
||||
}
|
||||
const p = fork(this.getCommand(), args, {
|
||||
stdio: ['inherit', 'pipe', 'pipe', 'ipc'],
|
||||
env,
|
||||
});
|
||||
|
||||
let out = [];
|
||||
let outWithErr = [];
|
||||
p.stdout.on('data', (chunk) => {
|
||||
process.stdout.write(chunk);
|
||||
out.push(chunk.toString());
|
||||
outWithErr.push(chunk.toString());
|
||||
});
|
||||
p.stderr.on('data', (chunk) => {
|
||||
process.stderr.write(chunk);
|
||||
outWithErr.push(chunk.toString());
|
||||
});
|
||||
p.on('exit', (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(outWithErr.join(''));
|
||||
}
|
||||
if (outputPath && code === 0) {
|
||||
fs.writeFileSync(outputPath, outWithErr.join(''));
|
||||
this.cache
|
||||
.put(task, outputPath, taskOutputs)
|
||||
.then(() => {
|
||||
this.options.lifeCycle.endTask(task, code);
|
||||
res(code);
|
||||
})
|
||||
.catch((e) => {
|
||||
rej(e);
|
||||
});
|
||||
} else {
|
||||
this.options.lifeCycle.endTask(task, code);
|
||||
res(code);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
rej(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private forkProcessDirectOutputCapture(task: Task) {
|
||||
const taskOutputs = getOutputs(this.projectGraph.nodes, task);
|
||||
const outputPath = this.cache.temporaryOutputPath(task);
|
||||
return new Promise((res, rej) => {
|
||||
@ -187,8 +264,9 @@ export class TaskOrchestrator {
|
||||
...parseEnv(`${task.projectRoot}/.env`),
|
||||
...parseEnv(`${task.projectRoot}/.local.env`),
|
||||
};
|
||||
|
||||
const env = { ...envsFromFiles, ...process.env };
|
||||
const forceColor =
|
||||
process.env.FORCE_COLOR === undefined ? 'true' : process.env.FORCE_COLOR;
|
||||
const env = { ...envsFromFiles, FORCE_COLOR: forceColor, ...process.env };
|
||||
if (outputPath) {
|
||||
env.NX_TERMINAL_OUTPUT_PATH = outputPath;
|
||||
if (this.options.captureStderr) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user