From 8d1441ec1965ff93f3dbf3cfe740940d5a20594e Mon Sep 17 00:00:00 2001 From: Thomas Boop Date: Thu, 10 Sep 2020 23:18:18 -0400 Subject: [PATCH 1/6] Add File Commands --- docs/commands.md | 115 +++++++++++++++++++-------- packages/core/__tests__/core.test.ts | 65 ++++++++++----- packages/core/src/command.ts | 14 +--- packages/core/src/core.ts | 10 ++- packages/core/src/file-command.ts | 24 ++++++ packages/core/src/utils.ts | 15 ++++ 6 files changed, 177 insertions(+), 66 deletions(-) create mode 100644 packages/core/src/file-command.ts create mode 100644 packages/core/src/utils.ts diff --git a/docs/commands.md b/docs/commands.md index 30d58d9437..97eaa8b1fa 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -7,37 +7,6 @@ these things in a script or other tool. To allow this, we provide a special `::` syntax which, if logged to `stdout` on a new line, will allow the runner to perform special behavior on your commands. The following commands are all supported: -### Set an environment variable - -To set an environment variable for future out of process steps, use `::set-env`: - -```sh -echo "::set-env name=FOO::BAR" -``` - -Running `$FOO` in a future step will now return `BAR` - -This is wrapped by the core exportVariable method which sets for future steps but also updates the variable for this step - -```javascript -export function exportVariable(name: string, val: string): void {} -``` - -### PATH Manipulation - -To prepend a string to PATH, use `::addPath`: - -```sh -echo "::add-path::BAR" -``` - -Running `$PATH` in a future step will now return `BAR:{Previous Path}`; - -This is wrapped by the core addPath method: -```javascript -export function addPath(inputPath: string): void {} -``` - ### Set outputs To set an output for the step, use `::set-output`: @@ -155,8 +124,90 @@ function setCommandEcho(enabled: boolean): void {} The `add-mask`, `debug`, `warning` and `error` commands do not support echoing. -### Command Prompt +### Command Prompt + CMD processes the `"` character differently from other shells when echoing. In CMD, the above snippets should have the `"` characters removed in order to correctly process. For example, the set output command would be: ```cmd echo ::set-output name=FOO::BAR ``` + + +# File Commands + +During the execution of a workflow, the runner generates temporary files that you can write to to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. + +### Set an environment variable + +To set an environment variable for future out of process steps, write to the file located at `GITHUB_ENV` or use the equivalent `actions/core` function + +```sh +echo "FOO=BAR" >> $GITHUB_ENV +``` + +Running `$FOO` in a future step will now return `BAR` + +For multiline strings, you may use the [heredoc syntax](https://tldp.org/LDP/abs/html/here-docs.html) with your choice of delimeter. In the below example, we use `EOF` +``` +steps: + - name: Set the value + id: step_one + run: | + echo 'JSON_RESPONSE<> $GITHUB_ENV + curl https://httpbin.org/json >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV +``` + +This would set the value of the `JSON_RESPONSE` env variable to: + +``` +{ + "slideshow": { + "author": "Yours Truly", + "date": "date of publication", + "slides": [ + { + "title": "Wake up to WonderWidgets!", + "type": "all" + }, + { + "items": [ + "Why WonderWidgets are great", + "Who buys WonderWidgets" + ], + "title": "Overview", + "type": "all" + } + ], + "title": "Sample Slide Show" + } +} +``` + +This is wrapped by the core `exportVariable` method which sets for future steps but also updates the variable for this step. + +```javascript +export function exportVariable(name: string, val: string): void {} +``` + +### PATH Manipulation + +To prepend a string to PATH write to the file located at `GITHUB_PATH` or use the equivalent `actions/core` function + +```sh +echo "foo=bar" >> $GITHUB_PATH +``` + +Running `$PATH` in a future step will now return `BAR:{Previous Path}`; + +This is wrapped by the core addPath method: +```javascript +export function addPath(inputPath: string): void {} +``` + +### Powershell + +Powershell does not use UTF8 by default. You will want to make sure you write in the correct encoding. For example, to set the path: +``` +steps: + - run: echo "mypath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 +``` \ No newline at end of file diff --git a/packages/core/__tests__/core.test.ts b/packages/core/__tests__/core.test.ts index 2901065262..1cdb7bffd1 100644 --- a/packages/core/__tests__/core.test.ts +++ b/packages/core/__tests__/core.test.ts @@ -1,3 +1,4 @@ +import * as fs from 'fs' import * as os from 'os' import * as path from 'path' import * as core from '../src/core' @@ -24,6 +25,13 @@ const testEnvVars = { } describe('@actions/core', () => { + beforeAll(() => { + const filePath = path.join(__dirname, `test`) + if (!fs.existsSync(filePath)) { + fs.mkdirSync(filePath) + } + }) + beforeEach(() => { for (const key in testEnvVars) process.env[key] = testEnvVars[key as keyof typeof testEnvVars] @@ -36,32 +44,33 @@ describe('@actions/core', () => { }) it('exportVariable produces the correct command and sets the env', () => { + const command = 'ENV' + createFileCommandFile(command) core.exportVariable('my var', 'var val') - assertWriteCalls([`::set-env name=my var::var val${os.EOL}`]) - }) - - it('exportVariable escapes variable names', () => { - core.exportVariable('special char var \r\n,:', 'special val') - expect(process.env['special char var \r\n,:']).toBe('special val') - assertWriteCalls([ - `::set-env name=special char var %0D%0A%2C%3A::special val${os.EOL}` - ]) - }) - - it('exportVariable escapes variable values', () => { - core.exportVariable('my var2', 'var val\r\n') - expect(process.env['my var2']).toBe('var val\r\n') - assertWriteCalls([`::set-env name=my var2::var val%0D%0A${os.EOL}`]) + verifyFileCommand( + command, + `my var<<_GitHubActionsFileCommandDelimeter_${os.EOL}var val${os.EOL}_GitHubActionsFileCommandDelimeter_${os.EOL}` + ) }) it('exportVariable handles boolean inputs', () => { + const command = 'ENV' + createFileCommandFile(command) core.exportVariable('my var', true) - assertWriteCalls([`::set-env name=my var::true${os.EOL}`]) + verifyFileCommand( + command, + `my var<<_GitHubActionsFileCommandDelimeter_${os.EOL}true${os.EOL}_GitHubActionsFileCommandDelimeter_${os.EOL}` + ) }) it('exportVariable handles number inputs', () => { + const command = 'ENV' + createFileCommandFile(command) core.exportVariable('my var', 5) - assertWriteCalls([`::set-env name=my var::5${os.EOL}`]) + verifyFileCommand( + command, + `my var<<_GitHubActionsFileCommandDelimeter_${os.EOL}5${os.EOL}_GitHubActionsFileCommandDelimeter_${os.EOL}` + ) }) it('setSecret produces the correct command', () => { @@ -70,11 +79,13 @@ describe('@actions/core', () => { }) it('prependPath produces the correct commands and sets the env', () => { + const command = 'PATH' + createFileCommandFile(command) core.addPath('myPath') expect(process.env['PATH']).toBe( `myPath${path.delimiter}path1${path.delimiter}path2` ) - assertWriteCalls([`::add-path::myPath${os.EOL}`]) + verifyFileCommand(command, `myPath${os.EOL}`) }) it('getInput gets non-required input', () => { @@ -259,3 +270,21 @@ function assertWriteCalls(calls: string[]): void { expect(process.stdout.write).toHaveBeenNthCalledWith(i + 1, calls[i]) } } + +function createFileCommandFile(command: string): void { + const filePath = path.join(__dirname, `test/${command}`) + process.env[`GITHUB_${command}`] = filePath + fs.appendFileSync(filePath, '', { + encoding: 'utf8' + }) +} + +function verifyFileCommand(command: string, expectedContents: string): void { + const filePath = path.join(__dirname, `test/${command}`) + const contents = fs.readFileSync(filePath, 'utf8') + try { + expect(contents).toEqual(expectedContents) + } finally { + fs.unlinkSync(filePath) + } +} diff --git a/packages/core/src/command.ts b/packages/core/src/command.ts index acdf9def37..63b5bca642 100644 --- a/packages/core/src/command.ts +++ b/packages/core/src/command.ts @@ -1,4 +1,5 @@ import * as os from 'os' +import {toCommandValue} from './utils' // For internal use, subject to change. @@ -76,19 +77,6 @@ class Command { } } -/** - * Sanitizes an input into a string so it can be passed into issueCommand safely - * @param input input to sanitize into a string - */ -export function toCommandValue(input: any): string { - if (input === null || input === undefined) { - return '' - } else if (typeof input === 'string' || input instanceof String) { - return input as string - } - return JSON.stringify(input) -} - function escapeData(s: any): string { return toCommandValue(s) .replace(/%/g, '%25') diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 0cf9f04ca7..d5cfdbcada 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -1,4 +1,6 @@ -import {issue, issueCommand, toCommandValue} from './command' +import {issue, issueCommand} from './command' +import {issueCommand as issueFileCommand} from './file-command' +import {toCommandValue} from './utils' import * as os from 'os' import * as path from 'path' @@ -39,7 +41,9 @@ export enum ExitCode { export function exportVariable(name: string, val: any): void { const convertedVal = toCommandValue(val) process.env[name] = convertedVal - issueCommand('set-env', {name}, convertedVal) + const delimiter = '_GitHubActionsFileCommandDelimeter_' + const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}` + issueFileCommand('ENV', commandValue) } /** @@ -55,7 +59,7 @@ export function setSecret(secret: string): void { * @param inputPath */ export function addPath(inputPath: string): void { - issueCommand('add-path', {}, inputPath) + issueFileCommand('PATH', inputPath) process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}` } diff --git a/packages/core/src/file-command.ts b/packages/core/src/file-command.ts new file mode 100644 index 0000000000..978d8ff94b --- /dev/null +++ b/packages/core/src/file-command.ts @@ -0,0 +1,24 @@ +// For internal use, subject to change. + +// We use any as a valid input type +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import * as fs from 'fs' +import * as os from 'os' +import {toCommandValue} from './utils' + +export function issueCommand(command: string, message: any): void { + const filePath = process.env[`GITHUB_${command}`] + if (!filePath) { + throw new Error( + `Unable to find environment variable for file command ${command}` + ) + } + if (!fs.existsSync(filePath)) { + throw new Error(`Missing file at path: ${filePath}`) + } + + fs.appendFileSync(filePath, `${toCommandValue(message)}${os.EOL}`, { + encoding: 'utf8' + }) +} diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts new file mode 100644 index 0000000000..2f1d60ceb3 --- /dev/null +++ b/packages/core/src/utils.ts @@ -0,0 +1,15 @@ +// We use any as a valid input type +/* eslint-disable @typescript-eslint/no-explicit-any */ + +/** + * Sanitizes an input into a string so it can be passed into issueCommand safely + * @param input input to sanitize into a string + */ +export function toCommandValue(input: any): string { + if (input === null || input === undefined) { + return '' + } else if (typeof input === 'string' || input instanceof String) { + return input as string + } + return JSON.stringify(input) +} From 54459256d2be76ac23cd8f13cff6fc5a33eb0b90 Mon Sep 17 00:00:00 2001 From: Thomas Boop Date: Tue, 22 Sep 2020 15:10:56 -0400 Subject: [PATCH 2/6] pr updates w/ feedback --- docs/commands.md | 32 ++-------------- packages/core/__tests__/core.test.ts | 56 +++++++++++++++++++++++----- packages/core/src/core.ts | 26 +++++++++++-- 3 files changed, 73 insertions(+), 41 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 97eaa8b1fa..233429eed2 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -146,7 +146,7 @@ echo "FOO=BAR" >> $GITHUB_ENV Running `$FOO` in a future step will now return `BAR` -For multiline strings, you may use the [heredoc syntax](https://tldp.org/LDP/abs/html/here-docs.html) with your choice of delimeter. In the below example, we use `EOF` +For multiline strings, you may use the heredoc style syntax with your choice of delimeter. In the below example, we use `EOF` ``` steps: - name: Set the value @@ -157,31 +157,7 @@ steps: echo 'EOF' >> $GITHUB_ENV ``` -This would set the value of the `JSON_RESPONSE` env variable to: - -``` -{ - "slideshow": { - "author": "Yours Truly", - "date": "date of publication", - "slides": [ - { - "title": "Wake up to WonderWidgets!", - "type": "all" - }, - { - "items": [ - "Why WonderWidgets are great", - "Who buys WonderWidgets" - ], - "title": "Overview", - "type": "all" - } - ], - "title": "Sample Slide Show" - } -} -``` +This would set the value of the `JSON_RESPONSE` env variable to the value of the curl response. This is wrapped by the core `exportVariable` method which sets for future steps but also updates the variable for this step. @@ -194,10 +170,10 @@ export function exportVariable(name: string, val: string): void {} To prepend a string to PATH write to the file located at `GITHUB_PATH` or use the equivalent `actions/core` function ```sh -echo "foo=bar" >> $GITHUB_PATH +echo "/Users/test/.nvm/versions/node/v12.18.3/bin" >> $GITHUB_PATH ``` -Running `$PATH` in a future step will now return `BAR:{Previous Path}`; +Running `$PATH` in a future step will now return `/Users/test/.nvm/versions/node/v12.18.3/bin:{Previous Path}`; This is wrapped by the core addPath method: ```javascript diff --git a/packages/core/__tests__/core.test.ts b/packages/core/__tests__/core.test.ts index 1cdb7bffd1..924416d239 100644 --- a/packages/core/__tests__/core.test.ts +++ b/packages/core/__tests__/core.test.ts @@ -12,16 +12,20 @@ const testEnvVars = { 'my secret': '', 'special char secret \r\n];': '', 'my secret2': '', - PATH: `path1${path.delimiter}path2`, + 'PATH': `path1${path.delimiter}path2`, // Set inputs - INPUT_MY_INPUT: 'val', - INPUT_MISSING: '', + 'INPUT_MY_INPUT': 'val', + 'INPUT_MISSING': '', 'INPUT_SPECIAL_CHARS_\'\t"\\': '\'\t"\\ response ', - INPUT_MULTIPLE_SPACES_VARIABLE: 'I have multiple spaces', + 'INPUT_MULTIPLE_SPACES_VARIABLE': 'I have multiple spaces', // Save inputs - STATE_TEST_1: 'state_val' + 'STATE_TEST_1': 'state_val', + + // File Commands + 'GITHUB_PATH': '', + 'GITHUB_ENV': '' } describe('@actions/core', () => { @@ -34,13 +38,39 @@ describe('@actions/core', () => { beforeEach(() => { for (const key in testEnvVars) - process.env[key] = testEnvVars[key as keyof typeof testEnvVars] - + { + process.env[key] = (testEnvVars as { [key: string]: any })[key] as string + } process.stdout.write = jest.fn() }) - afterEach(() => { - for (const key in testEnvVars) Reflect.deleteProperty(testEnvVars, key) + it('legacy exportVariable produces the correct command and sets the env', () => { + core.exportVariable('my var', 'var val') + assertWriteCalls([`::set-env name=my var::var val${os.EOL}`]) + }) + + it('legacy exportVariable escapes variable names', () => { + core.exportVariable('special char var \r\n,:', 'special val') + expect(process.env['special char var \r\n,:']).toBe('special val') + assertWriteCalls([ + `::set-env name=special char var %0D%0A%2C%3A::special val${os.EOL}` + ]) + }) + + it('legacy exportVariable escapes variable values', () => { + core.exportVariable('my var2', 'var val\r\n') + expect(process.env['my var2']).toBe('var val\r\n') + assertWriteCalls([`::set-env name=my var2::var val%0D%0A${os.EOL}`]) + }) + + it('legacy exportVariable handles boolean inputs', () => { + core.exportVariable('my var', true) + assertWriteCalls([`::set-env name=my var::true${os.EOL}`]) + }) + + it('legacy exportVariable handles number inputs', () => { + core.exportVariable('my var', 5) + assertWriteCalls([`::set-env name=my var::5${os.EOL}`]) }) it('exportVariable produces the correct command and sets the env', () => { @@ -88,6 +118,14 @@ describe('@actions/core', () => { verifyFileCommand(command, `myPath${os.EOL}`) }) + it('legacy prependPath produces the correct commands and sets the env', () => { + core.addPath('myPath') + expect(process.env['PATH']).toBe( + `myPath${path.delimiter}path1${path.delimiter}path2` + ) + assertWriteCalls([`::add-path::myPath${os.EOL}`]) + }) + it('getInput gets non-required input', () => { expect(core.getInput('my input')).toBe('val') }) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index d5cfdbcada..7e3f944bfc 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -41,9 +41,18 @@ export enum ExitCode { export function exportVariable(name: string, val: any): void { const convertedVal = toCommandValue(val) process.env[name] = convertedVal - const delimiter = '_GitHubActionsFileCommandDelimeter_' - const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}` - issueFileCommand('ENV', commandValue) + + var filePath = process.env["GITHUB_ENV"] || "" + if (filePath && filePath.length > 0) + { + const delimiter = '_GitHubActionsFileCommandDelimeter_' + const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}` + issueFileCommand('ENV', commandValue) + } + else + { + issueCommand('set-env', {name}, convertedVal) + } } /** @@ -59,7 +68,16 @@ export function setSecret(secret: string): void { * @param inputPath */ export function addPath(inputPath: string): void { - issueFileCommand('PATH', inputPath) + + var filePath = process.env["GITHUB_PATH"] || "" + if (filePath && filePath.length > 0) + { + issueFileCommand('PATH', inputPath) + } + else + { + issueCommand('add-path', {}, inputPath) + } process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}` } From 728ace1a141f6a385ab6af3a927bfe5e5159cba9 Mon Sep 17 00:00:00 2001 From: Thomas Boop Date: Tue, 22 Sep 2020 15:13:33 -0400 Subject: [PATCH 3/6] run format --- packages/core/__tests__/core.test.ts | 19 +++++++++---------- packages/core/src/core.ts | 19 ++++++------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/packages/core/__tests__/core.test.ts b/packages/core/__tests__/core.test.ts index 924416d239..2463703deb 100644 --- a/packages/core/__tests__/core.test.ts +++ b/packages/core/__tests__/core.test.ts @@ -12,20 +12,20 @@ const testEnvVars = { 'my secret': '', 'special char secret \r\n];': '', 'my secret2': '', - 'PATH': `path1${path.delimiter}path2`, + PATH: `path1${path.delimiter}path2`, // Set inputs - 'INPUT_MY_INPUT': 'val', - 'INPUT_MISSING': '', + INPUT_MY_INPUT: 'val', + INPUT_MISSING: '', 'INPUT_SPECIAL_CHARS_\'\t"\\': '\'\t"\\ response ', - 'INPUT_MULTIPLE_SPACES_VARIABLE': 'I have multiple spaces', + INPUT_MULTIPLE_SPACES_VARIABLE: 'I have multiple spaces', // Save inputs - 'STATE_TEST_1': 'state_val', + STATE_TEST_1: 'state_val', // File Commands - 'GITHUB_PATH': '', - 'GITHUB_ENV': '' + GITHUB_PATH: '', + GITHUB_ENV: '' } describe('@actions/core', () => { @@ -37,9 +37,8 @@ describe('@actions/core', () => { }) beforeEach(() => { - for (const key in testEnvVars) - { - process.env[key] = (testEnvVars as { [key: string]: any })[key] as string + for (const key in testEnvVars) { + process.env[key] = (testEnvVars as {[key: string]: any})[key] as string } process.stdout.write = jest.fn() }) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 7e3f944bfc..02a30903bd 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -42,15 +42,12 @@ export function exportVariable(name: string, val: any): void { const convertedVal = toCommandValue(val) process.env[name] = convertedVal - var filePath = process.env["GITHUB_ENV"] || "" - if (filePath && filePath.length > 0) - { + var filePath = process.env['GITHUB_ENV'] || '' + if (filePath && filePath.length > 0) { const delimiter = '_GitHubActionsFileCommandDelimeter_' const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}` issueFileCommand('ENV', commandValue) - } - else - { + } else { issueCommand('set-env', {name}, convertedVal) } } @@ -68,14 +65,10 @@ export function setSecret(secret: string): void { * @param inputPath */ export function addPath(inputPath: string): void { - - var filePath = process.env["GITHUB_PATH"] || "" - if (filePath && filePath.length > 0) - { + var filePath = process.env['GITHUB_PATH'] || '' + if (filePath && filePath.length > 0) { issueFileCommand('PATH', inputPath) - } - else - { + } else { issueCommand('add-path', {}, inputPath) } process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}` From 5d159adfaa2f5f34a56e195400cc60247b659323 Mon Sep 17 00:00:00 2001 From: Thomas Boop Date: Tue, 22 Sep 2020 15:22:43 -0400 Subject: [PATCH 4/6] fix lint/format --- packages/core/__tests__/core.test.ts | 2 +- packages/core/src/core.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/__tests__/core.test.ts b/packages/core/__tests__/core.test.ts index 2463703deb..0e52e9b2cf 100644 --- a/packages/core/__tests__/core.test.ts +++ b/packages/core/__tests__/core.test.ts @@ -38,7 +38,7 @@ describe('@actions/core', () => { beforeEach(() => { for (const key in testEnvVars) { - process.env[key] = (testEnvVars as {[key: string]: any})[key] as string + process.env[key] = testEnvVars[key as keyof typeof testEnvVars] } process.stdout.write = jest.fn() }) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 02a30903bd..6f95908dad 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -42,7 +42,7 @@ export function exportVariable(name: string, val: any): void { const convertedVal = toCommandValue(val) process.env[name] = convertedVal - var filePath = process.env['GITHUB_ENV'] || '' + const filePath = process.env['GITHUB_ENV'] || '' if (filePath && filePath.length > 0) { const delimiter = '_GitHubActionsFileCommandDelimeter_' const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}` @@ -65,7 +65,7 @@ export function setSecret(secret: string): void { * @param inputPath */ export function addPath(inputPath: string): void { - var filePath = process.env['GITHUB_PATH'] || '' + const filePath = process.env['GITHUB_PATH'] || '' if (filePath && filePath.length > 0) { issueFileCommand('PATH', inputPath) } else { From 2276a1d396fb73eb31b374399f1945b2c15a1a96 Mon Sep 17 00:00:00 2001 From: Thomas Boop Date: Tue, 22 Sep 2020 15:27:13 -0400 Subject: [PATCH 5/6] slight update with an example in the docs --- docs/commands.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 233429eed2..f29ad40941 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -134,7 +134,7 @@ echo ::set-output name=FOO::BAR # File Commands -During the execution of a workflow, the runner generates temporary files that you can write to to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. +During the execution of a workflow, the runner generates temporary files that you can write to to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. Multiple commands can be written to the same file, seperated by newlines. ### Set an environment variable @@ -146,7 +146,7 @@ echo "FOO=BAR" >> $GITHUB_ENV Running `$FOO` in a future step will now return `BAR` -For multiline strings, you may use the heredoc style syntax with your choice of delimeter. In the below example, we use `EOF` +For multiline strings, you may use a heredoc style syntax with your choice of delimeter. In the below example, we use `EOF` ``` steps: - name: Set the value @@ -159,6 +159,13 @@ steps: This would set the value of the `JSON_RESPONSE` env variable to the value of the curl response. +The expected syntax for the heredoc style is: +``` +{VARIABLE_NAME}<<{DELIMETER} +{VARIABLE_VALUE} +{DELIMETER} +``` + This is wrapped by the core `exportVariable` method which sets for future steps but also updates the variable for this step. ```javascript From 764016d08b1240af7d75fa159245a1de34383473 Mon Sep 17 00:00:00 2001 From: Thomas Boop Date: Wed, 23 Sep 2020 09:46:20 -0400 Subject: [PATCH 6/6] pr feedback --- docs/commands.md | 4 ++-- packages/core/src/core.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index f29ad40941..1b09af48af 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -132,9 +132,9 @@ echo ::set-output name=FOO::BAR ``` -# File Commands +# Environment files -During the execution of a workflow, the runner generates temporary files that you can write to to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. Multiple commands can be written to the same file, seperated by newlines. +During the execution of a workflow, the runner generates temporary files that can be used to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. Multiple commands can be written to the same file, separated by newlines. ### Set an environment variable diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 6f95908dad..e7e366c501 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -43,7 +43,7 @@ export function exportVariable(name: string, val: any): void { process.env[name] = convertedVal const filePath = process.env['GITHUB_ENV'] || '' - if (filePath && filePath.length > 0) { + if (filePath) { const delimiter = '_GitHubActionsFileCommandDelimeter_' const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}` issueFileCommand('ENV', commandValue) @@ -66,7 +66,7 @@ export function setSecret(secret: string): void { */ export function addPath(inputPath: string): void { const filePath = process.env['GITHUB_PATH'] || '' - if (filePath && filePath.length > 0) { + if (filePath) { issueFileCommand('PATH', inputPath) } else { issueCommand('add-path', {}, inputPath)