Multiline strings as a job output in GitHub Actions

Context #

GitHub Actions allows to use the outputs from dependent jobs. For single line strings, you can do the following

jobs:
job1:
runs-on: ubuntu-latest
outputs:
output1: $
steps:
- id: set-output
run: |
echo "::set-output name=output1::'Hello World'"

job2:
runs-on: ubuntu-latest
needs: [job1]
steps:
- run: |
echo "Output1: $"

Unfortunately, the above solution doesn't work for multiline strings. By default, using the :::set-output command will cut the string to just the first line of content.

Implementation #

We have 2 main options at this time when creating new multiline outputs to be used by downstream jobs:

  • Escape the return characters to convert the multiline string into a single-line one. The runner will convert back appropriately when the output is used.
  • Leverage the actions/github-script and the core context (from the actions/toolkit package) to export the output through javascript

Escaping the characters through Bash string substitution #

Let's see how escaping would work in detail. The characters that need escaping are %, \n and \r, based on this github community question.

Leveraging string substitution in bash, this looks as follows:

content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"

Then, the jobs would look like:

jobs:
job1:
runs-on: ubuntu-latest
outputs:
output1: $
steps:
- id: set-output
run: |
# Assuming we have a $content variable already populated
content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"
echo "::set-output name=output1::$content"

job2:
runs-on: ubuntu-latest
needs: [job1]
steps:
- run: |
echo "Output1: $"

Using action/github-script and the core package in actions/toolkit #

The github-script action provides access to different APIs accessible through different objects. The core object referencees actions/core package, which allows setting the step's output using the setOutput function/

jobs:
job1:
runs-on: ubuntu-latest
outputs:
output1: $
steps:
- uses: actions/github-[email protected]
id: set-output
with:
script: |
# Assuming we have a `content` environment variable or output of previous step
core.setOutput("output1", `$`);

job2:
runs-on: ubuntu-latest
needs: [job1]
steps:
- run: |
echo "Output1: $"

References #

To learn more about it, check the following resources:

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.