GitHub Actions Set Output Migration For Multiline Pull Request Comments
Published on . Last updated on .
For this website I use a github action posting an application snapshot report as a pull request comment.
Recently this warning started to appear in GitHub workflow run summary view:
The
set-output
command is deprecated and will be disabled soon. Please upgrade to using Environment Files.
I went off to investigate it and not only successfully migrated set-output
to the recommended $GITHUB_OUTPUT
solution, but also was able to replace somewhat
convoluted pull request commenting approach with a much simpler
Job Summary
feature
recently introduced by GitHub Actions team.
GitHub Action Job Using Now Deprecated set-output
Approach
Below is the original workflow job code which reads some text file into outputs.report
variable
and posts it as a pull request commit comment.
This version was causing the warning above.
First step of the job:
- reads
env.report_filename
file content into the local (bash)report
variable - replaces new line symbols with special symbols to be handled properly when read back
- uses now deprecated
::set-output
to pass the local (bash)report
variable into the runningstep.outputs.report
variable so that subsequent steps of the same job have access to it
Second step uses
peter-evans/commit-comment@v2
action to post multiline content from outputs.report
variable as
a pull request commit comment on a GitHub page.
- id: read-report-file-into-output name: Read Report File into Output Variable run: | report=$(cat ${{ env.report_filename }}) report="${report//'%'/'%25'}" report="${report//$'\n'/'%0A'}" report="${report//$'\r'/'%0D'}" echo ::set-output name=report::$report - id: post-report-as-pr-comment name: Post Report as Pull Request Comment uses: peter-evans/commit-comment@v2 with: body: "```\n${{ steps.read-report-file-into-output.outputs.report }}\n```"
yml
Note that id
of the first step is used by the second step to access outputs.report
variable.
Migration from set-output
to $GITHUB_OUTPUT
Now $GITHUB_OUTPUT
and $GITHUB_STATE
environment variables
are provided as a replacement
for deprecated set-output
and set-state
commands.
New echo "{name}={value}" >> $GITHUB_OUTPUT
syntax is quite simple and straightforward to use.
It is consistent between all
Environment files,
meaning you can set environment, state and output variables using the same syntax.
In fact it is very similar to the one used in bash/linux terminal for redirecting command output to files. Just that instead of arbitrary strings we are redirecting key&value pairs.
The only complication comes when we need to pass multiline text as an environment variable value. Instead of somewhat magical special symbols we used in the snippet above, there is a new and well documented approach:
- name: Set Multiline Value as Env Variable run: | { echo '{name}<<{delimiter}' echo '{value}' echo '{delimiter}' } >> $GITHUB_ENV
yml
Where name
is the name of environment/state/output value we want to define, i.e. ”report
“,
delimeter
is a randomly generated string (below we will see how to do that) and value
is
the actual multiline content we want to store.
Here is the updated yaml using $GITHUB_OUTPUT
environment file:
- id: read-report-file-into-output name: Read Report File into Output Variable run: | delimiter="$(openssl rand -hex 8)" { echo "report<<${delimiter}" cat ${{ env.report_filename }} echo "${delimiter}" } >> $GITHUB_OUTPUT - id: post-report-as-pr-comment name: Post report as Pull Request Comment uses: peter-evans/commit-comment@v2 with: body: "```\n${{ steps.read-report-file-into-output.outputs.report }}\n```"
yml
openssl rand -hex 8
command generates a unique string for the delimeter
value.
We have to have it randomly generated to protect ourselves from code injection,
which, apparently, is harder to implement when your new line symbol is unpredictable.
Congratulations, that’s pretty much it! — we have updated our workflow with the new syntax, and that pesky warning won’t appear on our workflow run summary pages.
Replacing Pull Request Comment with $GITHUB_STEP_SUMMARY
While at it I also noticed a new Job Summary concept, which allows to render arbitrary workflow step summaries (in markdown) on a workflow run page.
I decided to use the new summary approach instead of PR comment, since it allows
to remove the third party peter-evans/commit-comment@v2
action
and downgrade GITHUB_TOKEN
permissions for jobs run by Dependabot pull requests.
Previously I had to have permissions.contents: write
set for the job responsible for
posting a comment.
It also means that I have an easier and more scalable way to print various reports and logs from my workflows, and I plan to extend its usage in the future.
Here is the end result which works beautifully and is simpler than the one I started with:
- id: pass-report-into-summary name: Pass Report into the Summary run: | { echo "### My Report Header" echo "\`\`\`" cat ${{ env.report_filename }} echo "" echo "\`\`\`" } >> $GITHUB_STEP_SUMMARY
yml
We “route” all the output we want to be rendered as a summary to
the $GITHUB_STEP_SUMMARY
environment file — line by line.
Such output is supposed to be a valid markdown, and that’s why I’m using code block
wrapper for the free formatted content of my report file.
We also have to escape backticks to be handled properly in the terminal or use
the alternative ~~~
syntax.
And this is how the summary looks like on a GitHub Actions workflow run page:
And that’s all for today, happy coding!
Thanks to Shamil Isyaev for pointing out that we can redirect a group of commands into an output variable. Code snippets were updated to use this approach.