fix(core): ensure ANSI escape codes are stripped in git-hasher process outputs

This commit is contained in:
James Henry 2021-09-16 20:36:22 +04:00 committed by Victor Savkin
parent a5ba9bc0c3
commit 4956ebea9f
4 changed files with 87 additions and 13 deletions

View File

@ -1,6 +1,6 @@
import { spawnSync } from 'child_process';
import { join } from 'path';
import { statSync } from 'fs'; import { statSync } from 'fs';
import { join } from 'path';
import { spawnProcess } from './spawn-process';
function parseGitLsTree(output: string): Map<string, string> { function parseGitLsTree(output: string): Map<string, string> {
const changes: Map<string, string> = new Map<string, string>(); const changes: Map<string, string> = new Map<string, string>();
@ -33,7 +33,7 @@ function parseGitStatus(path: string): Map<string, string> {
// we need to manually strip the root path from the filenames. // we need to manually strip the root path from the filenames.
const prefix = spawnProcess('git', ['rev-parse', '--show-prefix'], path); const prefix = spawnProcess('git', ['rev-parse', '--show-prefix'], path);
var chunks = output.split('\0'); const chunks = output.split('\0');
for (let i = 0; i < chunks.length; i++) { for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i]; const chunk = chunks[i];
if (chunk.length) { if (chunk.length) {
@ -52,16 +52,6 @@ function parseGitStatus(path: string): Map<string, string> {
return changes; return changes;
} }
function spawnProcess(command: string, args: string[], cwd: string): string {
const r = spawnSync(command, args, { cwd, maxBuffer: 50 * 1024 * 1024 });
if (r.status !== 0) {
throw new Error(
`Failed to run ${command} ${args.join(' ')}.\n${r.stdout}\n${r.stderr}`
);
}
return r.stdout.toString().trimEnd();
}
function getGitHashForFiles( function getGitHashForFiles(
filesToHash: string[], filesToHash: string[],
path: string path: string

View File

@ -0,0 +1,57 @@
import * as childProcess from 'child_process';
import { spawnProcess } from './spawn-process';
describe('spawnProcess()', () => {
let spy: jest.SpyInstance<
childProcess.SpawnSyncReturns<Buffer>,
[
command: string,
args?: readonly string[],
options?: childProcess.SpawnSyncOptions
]
>;
beforeEach(() => {
spy = jest.spyOn(childProcess, 'spawnSync');
});
afterEach(() => {
spy.mockReset();
spy.mockRestore();
});
it('should call spawnSync and return the stdout', () => {
const mockedStdout = 'stdout';
spy.mockImplementation(() => {
return {
status: 0,
stdout: mockedStdout,
} as any;
});
const output = spawnProcess('git', ['status', '-s', '-u', '-z', '.'], '');
expect(spy).toHaveBeenCalledTimes(1);
expect(output).toEqual(mockedStdout);
});
it('should work even when ANSI escape characters are present in the child process output - https://github.com/nrwl/nx/issues/7022', () => {
spy.mockImplementation(() => {
return {
status: 0,
// ANSI escaped characters can come through in the child process output, as reported here: https://github.com/nrwl/nx/issues/7022
stdout:
' \x1B[7;33mM\x1B[m packages/semver/src/generators/install/index.spec.ts\x00',
} as any;
});
const output = spawnProcess('git', ['status', '-s', '-u', '-z', '.'], '');
expect(spy).toHaveBeenCalledTimes(1);
/**
* Ensure the ANSI escaped characters have been stripped
* (the remaining trailing \0 is expected as part of the real-world git output)
*/
expect(output).toEqual(
' M packages/semver/src/generators/install/index.spec.ts\0'
);
});
});

View File

@ -0,0 +1,26 @@
import { spawnSync } from 'child_process';
// We can't use an import for this package because of how it is published
const stripAnsi = require('strip-ansi');
/**
* We separated this out into its own file to make it much easier to unit test
* and ensure that ANSI escape codes are appropriately stripped so that utilities
* in git-hasher work as intended in all cases.
*/
export function spawnProcess(
command: string,
args: string[],
cwd: string
): string {
const r = spawnSync(command, args, { cwd, maxBuffer: 50 * 1024 * 1024 });
if (r.status !== 0) {
throw new Error(
`Failed to run ${command} ${args.join(' ')}.\n${r.stdout}\n${r.stderr}`
);
}
const output = r.stdout.toString().trimEnd();
// We use strip-ansi to prevent issues such as https://github.com/nrwl/nx/issues/7022
return stripAnsi(output);
}

View File

@ -85,6 +85,7 @@ const IGNORE_MATCHES = {
'karma-coverage-istanbul-reporter', 'karma-coverage-istanbul-reporter',
'karma-jasmine', 'karma-jasmine',
'karma-jasmine-html-reporter', 'karma-jasmine-html-reporter',
'strip-ansi',
'webpack', 'webpack',
'webpack-dev-server', 'webpack-dev-server',
], ],