Observed behavior
exec() in src/util/git.ts pushes both stdout and stderr chunks into the same outputs array, then resolves with the joined string on success (or rejects with it on failure):
const outputs = [] as Array<string>;
cmdProcess.stdout?.on('data', (data: Buffer): void => {
outputs.push(String(data));
});
cmdProcess.stderr?.on('data', /* ... */ (data: Buffer): void => {
outputs.push(String(data));
});
cmdProcess.on('close', (code: number): void => {
if (code === 0) {
resolve(outputs.join(''));
} else {
reject(new Error(outputs.join('')));
}
});
Consequences:
- On success, callers receive a string that may contain stderr noise (progress, warnings) interleaved with stdout. Tests like
expect(result).toContain('Test commit') happen to work, but anything that parses the resolved string can be fooled by stderr text.
- The interleaving order is non-deterministic and can corrupt structured output (e.g.
--porcelain lines split by a stderr message).
Expected behavior
stdout and stderr should be captured separately. Resolve with stdout only; use stderr (with a stdout fallback) in the error message.
Suggested fix
const stdout = [] as Array<string>;
const stderr = [] as Array<string>;
cmdProcess.stdout?.on('data', (data: Buffer) => { stdout.push(String(data)); });
cmdProcess.stderr?.on('data', (data: Buffer) => { stderr.push(String(data)); });
cmdProcess.on('close', (code, signal) => {
if (code === 0) {
resolve(stdout.join(''));
} else {
const detail = (stderr.join('') || stdout.join('')).trim();
reject(new Error(detail || `git exited with code ${code}, signal ${signal}`));
}
});
Also note that String(Buffer) (used in both branches) is unsafe for streams that may split a multi-byte UTF-8 character across two data events. Switching to stdout.setEncoding('utf8') and concatenating strings, or buffering and decoding once at the end, avoids that.
Observed behavior
exec()insrc/util/git.tspushes both stdout and stderr chunks into the sameoutputsarray, then resolves with the joined string on success (or rejects with it on failure):Consequences:
expect(result).toContain('Test commit')happen to work, but anything that parses the resolved string can be fooled by stderr text.--porcelainlines split by a stderr message).Expected behavior
stdout and stderr should be captured separately. Resolve with stdout only; use stderr (with a stdout fallback) in the error message.
Suggested fix
Also note that
String(Buffer)(used in both branches) is unsafe for streams that may split a multi-byte UTF-8 character across twodataevents. Switching tostdout.setEncoding('utf8')and concatenating strings, or buffering and decoding once at the end, avoids that.