From ce7d6c22da750609d14879df2028533ced43f728 Mon Sep 17 00:00:00 2001 From: Luke Tomlinson Date: Wed, 19 May 2021 16:58:11 -0400 Subject: [PATCH 1/7] Add getExecOutput function --- packages/exec/__tests__/exec.test.ts | 40 ++++++++++++++++++++++++++ packages/exec/src/exec.ts | 42 ++++++++++++++++++++++++++-- packages/exec/src/interfaces.ts | 24 ++++++++++------ 3 files changed, 96 insertions(+), 10 deletions(-) diff --git a/packages/exec/__tests__/exec.test.ts b/packages/exec/__tests__/exec.test.ts index ae9844d661..136fcf89f8 100644 --- a/packages/exec/__tests__/exec.test.ts +++ b/packages/exec/__tests__/exec.test.ts @@ -952,6 +952,46 @@ describe('@actions/exec', () => { 'args[22]: "hello:world again"\r\n' + 'args[23]: "hello world\\\\"' ) + + it('Handles output callbacks', async () => { + const stdErrPath: string = path.join( + __dirname, + 'scripts', + 'stderroutput.js' + ) + const stdOutPath: string = path.join( + __dirname, + 'scripts', + 'stdoutoutput.js' + ) + const nodePath: string = await io.which('node', true) + let stdoutCalled = false + let stderrCalled = false + + const _testExecOptions = getExecOptions() + _testExecOptions.listeners = { + stdout: (data: Buffer) => { + expect(data).toEqual(Buffer.from('this is output to stdout')) + stdoutCalled = true + }, + stderr: (data: Buffer) => { + expect(data).toEqual(Buffer.from('this is output to stderr')) + stderrCalled = true + } + } + + let exitCode = await exec.exec( + `"${nodePath}"`, + [stdOutPath], + _testExecOptions + ) + expect(exitCode).toBe(0) + exitCode = await exec.exec(`"${nodePath}"`, [stdErrPath], _testExecOptions) + expect(exitCode).toBe(0) + + expect(stdoutCalled).toBeTruthy() + expect(stderrCalled).toBeTruthy() + }) }) } }) diff --git a/packages/exec/src/exec.ts b/packages/exec/src/exec.ts index 80a0363c49..f8c2dc3f21 100644 --- a/packages/exec/src/exec.ts +++ b/packages/exec/src/exec.ts @@ -1,7 +1,7 @@ -import {ExecOptions} from './interfaces' +import {ExecOptions, ExecOutput, ExecListeners} from './interfaces' import * as tr from './toolrunner' -export {ExecOptions} +export {ExecOptions, ExecOutput, ExecListeners} /** * Exec a command. @@ -28,3 +28,41 @@ export async function exec( const runner: tr.ToolRunner = new tr.ToolRunner(toolPath, args, options) return runner.exec() } + +export async function getExecOutput(commandLine: string, args?: string[], options?: ExecOptions): Promise { + type BufferListener = (data: Buffer) => void + let stdout = '' + let stderr = '' + + const originalStdoutListener = options?.listeners?.stdout + const originalStdErrListener = options?.listeners?.stderr + + const stdErrListener = (data: Buffer) => { + stderr += data.toString() + if (originalStdErrListener) { + originalStdErrListener(data) + } + } + + const stdOutListener = (data: Buffer) => { + stdout += data.toString() + if (originalStdoutListener) { + originalStdoutListener(data) + } + } + + const listeners: ExecListeners = { + ...options?.listeners, + stdout: stdOutListener, + stderr: stdErrListener + } + + const exitCode = await exec(commandLine, args, {...options, listeners} ) + + //return undefined for stdout/stderr if they are empty + return { + exitCode, + stdout: stdout || undefined, + stderr: stderr || undefined + } +} \ No newline at end of file diff --git a/packages/exec/src/interfaces.ts b/packages/exec/src/interfaces.ts index 436fc0ac7c..012c48ccc6 100644 --- a/packages/exec/src/interfaces.ts +++ b/packages/exec/src/interfaces.ts @@ -34,15 +34,23 @@ export interface ExecOptions { input?: Buffer /** optional. Listeners for output. Callback functions that will be called on these events */ - listeners?: { - stdout?: (data: Buffer) => void + listeners?: ExecListeners +} - stderr?: (data: Buffer) => void +export interface ExecOutput { + exitCode: number + stdout?: string + stderr?: string +} - stdline?: (data: string) => void +export interface ExecListeners { + stdout?: (data: Buffer) => void - errline?: (data: string) => void + stderr?: (data: Buffer) => void - debug?: (data: string) => void - } -} + stdline?: (data: string) => void + + errline?: (data: string) => void + + debug?: (data: string) => void +} \ No newline at end of file From fb48cac224d8280a476890dbe9e94f954ef3e2a1 Mon Sep 17 00:00:00 2001 From: Luke Tomlinson Date: Thu, 20 May 2021 11:42:53 -0400 Subject: [PATCH 2/7] Add tests for exec output --- packages/exec/__tests__/exec.test.ts | 177 ++++++++++++++---- .../__tests__/scripts/stdoutoutputlarge.js | 3 + packages/exec/src/exec.ts | 29 +-- packages/exec/src/interfaces.ts | 18 +- 4 files changed, 173 insertions(+), 54 deletions(-) create mode 100644 packages/exec/__tests__/scripts/stdoutoutputlarge.js diff --git a/packages/exec/__tests__/exec.test.ts b/packages/exec/__tests__/exec.test.ts index 136fcf89f8..05e3786f0a 100644 --- a/packages/exec/__tests__/exec.test.ts +++ b/packages/exec/__tests__/exec.test.ts @@ -636,6 +636,143 @@ describe('@actions/exec', () => { expect(output.trim()).toBe(`args[0]: "hello"${os.EOL}args[1]: "world"`) }) + it('correctly outputs for getExecOutput', async () => { + const stdErrPath: string = path.join( + __dirname, + 'scripts', + 'stderroutput.js' + ) + const stdOutPath: string = path.join( + __dirname, + 'scripts', + 'stdoutoutput.js' + ) + const nodePath: string = await io.which('node', true) + + const {exitCode: exitCodeOut, stdout} = await exec.getExecOutput( + `"${nodePath}"`, + [stdOutPath], + getExecOptions() + ) + + expect(exitCodeOut).toBe(0) + expect(stdout).toBe('this is output to stdout') + + const {exitCode: exitCodeErr, stderr} = await exec.getExecOutput( + `"${nodePath}"`, + [stdErrPath], + getExecOptions() + ) + expect(exitCodeErr).toBe(0) + expect(stderr).toBe('this is output to stderr') + }) + + it('correctly outputs for getExecOutput with additional listeners', async () => { + const stdErrPath: string = path.join( + __dirname, + 'scripts', + 'stderroutput.js' + ) + const stdOutPath: string = path.join( + __dirname, + 'scripts', + 'stdoutoutput.js' + ) + + let numberOfBuffers = 0 + const nodePath: string = await io.which('node', true) + let listenerOut = '' + + const {exitCode: exitCodeOut, stdout} = await exec.getExecOutput( + `"${nodePath}"`, + [stdOutPath], + { + ...getExecOptions(), + listeners: { + stdout: data => { + listenerOut = data.toString() + numberOfBuffers += 1 + } + } + } + ) + + expect(exitCodeOut).toBe(0) + expect(stdout).toBe('this is output to stdout') + expect(listenerOut).toBe('this is output to stdout') + expect(numberOfBuffers).toBe(1) + + let listenerErr = '' + const {exitCode: exitCodeErr, stderr} = await exec.getExecOutput( + `"${nodePath}"`, + [stdErrPath], + { + ...getExecOptions(), + listeners: { + stderr: data => { + listenerErr = data.toString() + } + } + } + ) + expect(exitCodeErr).toBe(0) + expect(stderr).toBe('this is output to stderr') + expect(listenerErr).toBe('this is output to stderr') + }) + + it('correctly outputs for getExecOutput when total size exceeds buffer size', async () => { + const stdErrPath: string = path.join( + __dirname, + 'scripts', + 'stderroutput.js' + ) + const stdOutPath: string = path.join( + __dirname, + 'scripts', + 'stdoutoutputlarge.js' + ) + + let numFullBuffers = 0 + const nodePath: string = await io.which('node', true) + let listenerOut = '' + + const {exitCode: exitCodeOut, stdout} = await exec.getExecOutput( + `"${nodePath}"`, + [stdOutPath], + { + ...getExecOptions(), + listeners: { + stdout: data => { + numFullBuffers += 1 + listenerOut += data.toString() + } + } + } + ) + + expect(exitCodeOut).toBe(0) + expect(Buffer.byteLength(stdout || '', 'utf8')).toBe(2 ** 32) + expect(Buffer.byteLength(listenerOut, 'utf8')).toBe(2 ** 32) + expect(numFullBuffers).toBeGreaterThan(1) + + let listenerErr = '' + const {exitCode: exitCodeErr, stderr} = await exec.getExecOutput( + `"${nodePath}"`, + [stdErrPath], + { + ...getExecOptions(), + listeners: { + stderr: data => { + listenerErr = data.toString() + } + } + } + ) + expect(exitCodeErr).toBe(0) + expect(stderr).toBe('this is output to stderr') + expect(listenerErr).toBe('this is output to stderr') + }) + if (IS_WINDOWS) { it('Exec roots relative tool path using process.cwd (Windows path separator)', async () => { let exitCode: number @@ -952,46 +1089,6 @@ describe('@actions/exec', () => { 'args[22]: "hello:world again"\r\n' + 'args[23]: "hello world\\\\"' ) - - it('Handles output callbacks', async () => { - const stdErrPath: string = path.join( - __dirname, - 'scripts', - 'stderroutput.js' - ) - const stdOutPath: string = path.join( - __dirname, - 'scripts', - 'stdoutoutput.js' - ) - const nodePath: string = await io.which('node', true) - let stdoutCalled = false - let stderrCalled = false - - const _testExecOptions = getExecOptions() - _testExecOptions.listeners = { - stdout: (data: Buffer) => { - expect(data).toEqual(Buffer.from('this is output to stdout')) - stdoutCalled = true - }, - stderr: (data: Buffer) => { - expect(data).toEqual(Buffer.from('this is output to stderr')) - stderrCalled = true - } - } - - let exitCode = await exec.exec( - `"${nodePath}"`, - [stdOutPath], - _testExecOptions - ) - expect(exitCode).toBe(0) - exitCode = await exec.exec(`"${nodePath}"`, [stdErrPath], _testExecOptions) - expect(exitCode).toBe(0) - - expect(stdoutCalled).toBeTruthy() - expect(stderrCalled).toBeTruthy() - }) }) } }) diff --git a/packages/exec/__tests__/scripts/stdoutoutputlarge.js b/packages/exec/__tests__/scripts/stdoutoutputlarge.js new file mode 100644 index 0000000000..27922e878a --- /dev/null +++ b/packages/exec/__tests__/scripts/stdoutoutputlarge.js @@ -0,0 +1,3 @@ +//Default highWaterMark for readable stream buffers us 64K (2^16) +//so we go over that to get more than a buffer's worth +process.stdout.write('a'.repeat(2**32)); diff --git a/packages/exec/src/exec.ts b/packages/exec/src/exec.ts index f8c2dc3f21..c9d6e93421 100644 --- a/packages/exec/src/exec.ts +++ b/packages/exec/src/exec.ts @@ -29,40 +29,43 @@ export async function exec( return runner.exec() } -export async function getExecOutput(commandLine: string, args?: string[], options?: ExecOptions): Promise { - type BufferListener = (data: Buffer) => void +export async function getExecOutput( + commandLine: string, + args?: string[], + options?: ExecOptions +): Promise { let stdout = '' let stderr = '' - + const originalStdoutListener = options?.listeners?.stdout const originalStdErrListener = options?.listeners?.stderr - - const stdErrListener = (data: Buffer) => { + + const stdErrListener = (data: Buffer): void => { stderr += data.toString() if (originalStdErrListener) { originalStdErrListener(data) } } - const stdOutListener = (data: Buffer) => { + const stdOutListener = (data: Buffer): void => { stdout += data.toString() if (originalStdoutListener) { originalStdoutListener(data) } } - - const listeners: ExecListeners = { + + const listeners: ExecListeners = { ...options?.listeners, stdout: stdOutListener, stderr: stdErrListener } - const exitCode = await exec(commandLine, args, {...options, listeners} ) + const exitCode = await exec(commandLine, args, {...options, listeners}) //return undefined for stdout/stderr if they are empty return { - exitCode, - stdout: stdout || undefined, - stderr: stderr || undefined + exitCode, + stdout: stdout || undefined, + stderr: stderr || undefined } -} \ No newline at end of file +} diff --git a/packages/exec/src/interfaces.ts b/packages/exec/src/interfaces.ts index 012c48ccc6..a995aeb9e1 100644 --- a/packages/exec/src/interfaces.ts +++ b/packages/exec/src/interfaces.ts @@ -37,20 +37,36 @@ export interface ExecOptions { listeners?: ExecListeners } +/** + * Interface for the output of getExecOutput() + */ export interface ExecOutput { + /**The exit code of the process */ exitCode: number + + /**The entire stdout of the process as a string */ stdout?: string + + /**The entire stderr of the process as a string */ stderr?: string } +/** + * The user defined listeners for an exec call + */ export interface ExecListeners { + /** A call back for each buffer of stdout */ stdout?: (data: Buffer) => void + /** A call back for each buffer of stderr */ stderr?: (data: Buffer) => void + /** A call back for each line of stdout */ stdline?: (data: string) => void + /** A call back for each line of stderr */ errline?: (data: string) => void + /** A call back for each debug log */ debug?: (data: string) => void -} \ No newline at end of file +} From b70fd48babbe8348bee8b4a5f28ef1a49eaa63d3 Mon Sep 17 00:00:00 2001 From: Luke Tomlinson Date: Thu, 20 May 2021 12:31:02 -0400 Subject: [PATCH 3/7] Modify tests to not rely on buffer size, but only test larger output --- packages/exec/__tests__/exec.test.ts | 10 ++-------- packages/exec/__tests__/scripts/stdoutoutputlarge.js | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/exec/__tests__/exec.test.ts b/packages/exec/__tests__/exec.test.ts index 05e3786f0a..1d92dec040 100644 --- a/packages/exec/__tests__/exec.test.ts +++ b/packages/exec/__tests__/exec.test.ts @@ -679,7 +679,6 @@ describe('@actions/exec', () => { 'stdoutoutput.js' ) - let numberOfBuffers = 0 const nodePath: string = await io.which('node', true) let listenerOut = '' @@ -691,7 +690,6 @@ describe('@actions/exec', () => { listeners: { stdout: data => { listenerOut = data.toString() - numberOfBuffers += 1 } } } @@ -700,7 +698,6 @@ describe('@actions/exec', () => { expect(exitCodeOut).toBe(0) expect(stdout).toBe('this is output to stdout') expect(listenerOut).toBe('this is output to stdout') - expect(numberOfBuffers).toBe(1) let listenerErr = '' const {exitCode: exitCodeErr, stderr} = await exec.getExecOutput( @@ -732,7 +729,6 @@ describe('@actions/exec', () => { 'stdoutoutputlarge.js' ) - let numFullBuffers = 0 const nodePath: string = await io.which('node', true) let listenerOut = '' @@ -743,7 +739,6 @@ describe('@actions/exec', () => { ...getExecOptions(), listeners: { stdout: data => { - numFullBuffers += 1 listenerOut += data.toString() } } @@ -751,9 +746,8 @@ describe('@actions/exec', () => { ) expect(exitCodeOut).toBe(0) - expect(Buffer.byteLength(stdout || '', 'utf8')).toBe(2 ** 32) - expect(Buffer.byteLength(listenerOut, 'utf8')).toBe(2 ** 32) - expect(numFullBuffers).toBeGreaterThan(1) + expect(Buffer.byteLength(stdout || '', 'utf8')).toBe(2 ** 24) + expect(Buffer.byteLength(listenerOut, 'utf8')).toBe(2 ** 24) let listenerErr = '' const {exitCode: exitCodeErr, stderr} = await exec.getExecOutput( diff --git a/packages/exec/__tests__/scripts/stdoutoutputlarge.js b/packages/exec/__tests__/scripts/stdoutoutputlarge.js index 27922e878a..e31635ce80 100644 --- a/packages/exec/__tests__/scripts/stdoutoutputlarge.js +++ b/packages/exec/__tests__/scripts/stdoutoutputlarge.js @@ -1,3 +1,3 @@ //Default highWaterMark for readable stream buffers us 64K (2^16) //so we go over that to get more than a buffer's worth -process.stdout.write('a'.repeat(2**32)); +process.stdout.write('a'.repeat(2**24)); From 424974ce1383554deb838f40814941b3ad9c56a5 Mon Sep 17 00:00:00 2001 From: Luke Tomlinson Date: Thu, 20 May 2021 15:13:40 -0400 Subject: [PATCH 4/7] Handle split multi-byte characters + PR feedback --- packages/exec/__tests__/exec.test.ts | 29 +++++++++++++++++++ .../__tests__/scripts/stdoutoutputlarge.js | 2 +- .../__tests__/scripts/stdoutputspecial.js | 4 +++ packages/exec/src/exec.ts | 28 +++++++++++++++--- packages/exec/src/interfaces.ts | 4 +-- packages/io/src/io.ts | 1 - 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 packages/exec/__tests__/scripts/stdoutputspecial.js diff --git a/packages/exec/__tests__/exec.test.ts b/packages/exec/__tests__/exec.test.ts index 1d92dec040..5896eb501d 100644 --- a/packages/exec/__tests__/exec.test.ts +++ b/packages/exec/__tests__/exec.test.ts @@ -767,6 +767,35 @@ describe('@actions/exec', () => { expect(listenerErr).toBe('this is output to stderr') }) + it('correctly outputs for getExecOutput with multi-byte characters', async () => { + const stdOutPath: string = path.join( + __dirname, + 'scripts', + 'stdoutputspecial.js' + ) + + const nodePath: string = await io.which('node', true) + let listenerOut = '' + let numStdOutBufferCalls = 0 + const {exitCode: exitCodeOut, stdout} = await exec.getExecOutput( + `"${nodePath}"`, + [stdOutPath], + { + ...getExecOptions(), + listeners: { + stdout: _ => { + numStdOutBufferCalls += 1 + } + } + } + ) + + expect(exitCodeOut).toBe(0) + //one call for each half of the © character, ensuring it was actually split and not sent together + expect(numStdOutBufferCalls).toBe(2) + expect(stdout).toBe('©') + }) + if (IS_WINDOWS) { it('Exec roots relative tool path using process.cwd (Windows path separator)', async () => { let exitCode: number diff --git a/packages/exec/__tests__/scripts/stdoutoutputlarge.js b/packages/exec/__tests__/scripts/stdoutoutputlarge.js index e31635ce80..c7f7122dfa 100644 --- a/packages/exec/__tests__/scripts/stdoutoutputlarge.js +++ b/packages/exec/__tests__/scripts/stdoutoutputlarge.js @@ -1,3 +1,3 @@ //Default highWaterMark for readable stream buffers us 64K (2^16) //so we go over that to get more than a buffer's worth -process.stdout.write('a'.repeat(2**24)); +process.stdout.write('a\n'.repeat(2**24)); diff --git a/packages/exec/__tests__/scripts/stdoutputspecial.js b/packages/exec/__tests__/scripts/stdoutputspecial.js new file mode 100644 index 0000000000..85233491b3 --- /dev/null +++ b/packages/exec/__tests__/scripts/stdoutputspecial.js @@ -0,0 +1,4 @@ +process.stdout.write(Buffer.from([0xC2])) //first half of © character +process.stdout.emit('drain') //force first byte to be sent and not appended with next one +process.stdout.write(Buffer.from([0xA9])) //second half of © character + diff --git a/packages/exec/src/exec.ts b/packages/exec/src/exec.ts index c9d6e93421..3989de0eb4 100644 --- a/packages/exec/src/exec.ts +++ b/packages/exec/src/exec.ts @@ -1,3 +1,4 @@ +import {StringDecoder} from 'string_decoder' import {ExecOptions, ExecOutput, ExecListeners} from './interfaces' import * as tr from './toolrunner' @@ -29,6 +30,17 @@ export async function exec( return runner.exec() } +/** + * Exec a command and get the output. + * Output will be streamed to the live console. + * Returns promise with the exit code and collected stdout and stderr + * + * @param commandLine command to execute (can include additional args). Must be correctly escaped. + * @param args optional arguments for tool. Escaping is handled by the lib. + * @param options optional exec options. See ExecOptions + * @returns Promise exit code, stdout, and stderr + */ + export async function getExecOutput( commandLine: string, args?: string[], @@ -37,18 +49,22 @@ export async function getExecOutput( let stdout = '' let stderr = '' + //Using string decoder covers the case where a mult-byte character is split + let stdoutDecoder = new StringDecoder('utf8') + let stderrDecoder = new StringDecoder('utf8') + const originalStdoutListener = options?.listeners?.stdout const originalStdErrListener = options?.listeners?.stderr const stdErrListener = (data: Buffer): void => { - stderr += data.toString() + stderr += stderrDecoder.write(data) if (originalStdErrListener) { originalStdErrListener(data) } } const stdOutListener = (data: Buffer): void => { - stdout += data.toString() + stdout += stdoutDecoder.write(data) if (originalStdoutListener) { originalStdoutListener(data) } @@ -62,10 +78,14 @@ export async function getExecOutput( const exitCode = await exec(commandLine, args, {...options, listeners}) + //flush any remaining characters + stdout += stdoutDecoder.end() + stderr += stderrDecoder.end() + //return undefined for stdout/stderr if they are empty return { exitCode, - stdout: stdout || undefined, - stderr: stderr || undefined + stdout, + stderr } } diff --git a/packages/exec/src/interfaces.ts b/packages/exec/src/interfaces.ts index a995aeb9e1..c86080c4f5 100644 --- a/packages/exec/src/interfaces.ts +++ b/packages/exec/src/interfaces.ts @@ -45,10 +45,10 @@ export interface ExecOutput { exitCode: number /**The entire stdout of the process as a string */ - stdout?: string + stdout: string /**The entire stderr of the process as a string */ - stderr?: string + stderr: string } /** diff --git a/packages/io/src/io.ts b/packages/io/src/io.ts index e75e14f775..d210b3c6c4 100644 --- a/packages/io/src/io.ts +++ b/packages/io/src/io.ts @@ -17,7 +17,6 @@ export interface CopyOptions { /** Optional. Whether to copy the source directory along with all the files. Only takes effect when recursive=true and copying a directory. Default is true*/ copySourceDirectory?: boolean } - /** * Interface for cp/mv options */ From 19e1659da16daf3b1eea5ec25e37e7e45eb00a53 Mon Sep 17 00:00:00 2001 From: Luke Tomlinson Date: Thu, 20 May 2021 15:33:58 -0400 Subject: [PATCH 5/7] Fix tests --- packages/exec/__tests__/exec.test.ts | 4 ++-- packages/io/src/io.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/exec/__tests__/exec.test.ts b/packages/exec/__tests__/exec.test.ts index 5896eb501d..c94d53e25c 100644 --- a/packages/exec/__tests__/exec.test.ts +++ b/packages/exec/__tests__/exec.test.ts @@ -746,8 +746,8 @@ describe('@actions/exec', () => { ) expect(exitCodeOut).toBe(0) - expect(Buffer.byteLength(stdout || '', 'utf8')).toBe(2 ** 24) - expect(Buffer.byteLength(listenerOut, 'utf8')).toBe(2 ** 24) + expect(Buffer.byteLength(stdout || '', 'utf8')).toBe(2 ** 25) + expect(Buffer.byteLength(listenerOut, 'utf8')).toBe(2 ** 25) let listenerErr = '' const {exitCode: exitCodeErr, stderr} = await exec.getExecOutput( diff --git a/packages/io/src/io.ts b/packages/io/src/io.ts index d210b3c6c4..e75e14f775 100644 --- a/packages/io/src/io.ts +++ b/packages/io/src/io.ts @@ -17,6 +17,7 @@ export interface CopyOptions { /** Optional. Whether to copy the source directory along with all the files. Only takes effect when recursive=true and copying a directory. Default is true*/ copySourceDirectory?: boolean } + /** * Interface for cp/mv options */ From 9bd49b27b50e824fd8610b4d31cfd6e2445b4046 Mon Sep 17 00:00:00 2001 From: Luke Tomlinson Date: Thu, 20 May 2021 15:40:24 -0400 Subject: [PATCH 6/7] Lint --- packages/exec/__tests__/exec.test.ts | 3 +-- packages/exec/src/exec.ts | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/exec/__tests__/exec.test.ts b/packages/exec/__tests__/exec.test.ts index c94d53e25c..054d269084 100644 --- a/packages/exec/__tests__/exec.test.ts +++ b/packages/exec/__tests__/exec.test.ts @@ -775,7 +775,6 @@ describe('@actions/exec', () => { ) const nodePath: string = await io.which('node', true) - let listenerOut = '' let numStdOutBufferCalls = 0 const {exitCode: exitCodeOut, stdout} = await exec.getExecOutput( `"${nodePath}"`, @@ -783,7 +782,7 @@ describe('@actions/exec', () => { { ...getExecOptions(), listeners: { - stdout: _ => { + stdout: () => { numStdOutBufferCalls += 1 } } diff --git a/packages/exec/src/exec.ts b/packages/exec/src/exec.ts index 3989de0eb4..92b5d8e717 100644 --- a/packages/exec/src/exec.ts +++ b/packages/exec/src/exec.ts @@ -50,8 +50,8 @@ export async function getExecOutput( let stderr = '' //Using string decoder covers the case where a mult-byte character is split - let stdoutDecoder = new StringDecoder('utf8') - let stderrDecoder = new StringDecoder('utf8') + const stdoutDecoder = new StringDecoder('utf8') + const stderrDecoder = new StringDecoder('utf8') const originalStdoutListener = options?.listeners?.stdout const originalStdErrListener = options?.listeners?.stderr From b23f9a5e2ff3dd1824af03e2018255f347ee4063 Mon Sep 17 00:00:00 2001 From: Luke Tomlinson Date: Thu, 20 May 2021 16:05:14 -0400 Subject: [PATCH 7/7] Update how split byte are sent for tests --- packages/exec/__tests__/scripts/stdoutputspecial.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/exec/__tests__/scripts/stdoutputspecial.js b/packages/exec/__tests__/scripts/stdoutputspecial.js index 85233491b3..21bc5e1f26 100644 --- a/packages/exec/__tests__/scripts/stdoutputspecial.js +++ b/packages/exec/__tests__/scripts/stdoutputspecial.js @@ -1,4 +1,5 @@ -process.stdout.write(Buffer.from([0xC2])) //first half of © character -process.stdout.emit('drain') //force first byte to be sent and not appended with next one -process.stdout.write(Buffer.from([0xA9])) //second half of © character - +//first half of © character +process.stdout.write(Buffer.from([0xC2]), (err) => { + //write in the callback so that the second byte is sent separately + process.stdout.write(Buffer.from([0xA9])) //second half of © character +})