Using $GITHUB_OUTPUT to write output parameters from GitHub action jobs & steps
Moving away from set-output and save-state to writing output parameters to a environment file.
With GitHub actions deprecating the save-state and set-output command, the new way of persisting output from a GitHub step or job is to pass the same to the $GITHUB_OUTPUT environment files. While working with GitHub actions, depending on which type of runner you choose for your jobs, the default shell is different. For example, if you are running a runner ubuntu-latest
then the default shell for it is bash
, whereas if you are using a windows-latest
runner, then the default shell for it is pwsh
. In this post, we will go through the different ways in which you can output from an executing step within Github actions so that other action steps/jobs can access those output parameters.
Linux runners-based jobs in Github actions:
The Linux runner on GitHub action supports the shells and you can write outputs to them using the below given syntax:
Shell | Output syntax |
bash | echo {name}={value} >> $GITHUB_OUTPUT |
pwsh | echo {name}={value} >> $env:GITHUB_OUTPUT |
jobs:
Linux-Runner:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Read version from repository
id: read-file
shell: pwsh
run: |
$content = Get-Content -Path version.txt -Raw
echo outputContent=$content >> $env:GITHUB_OUTPUT
working-directory: ${{ github.workspace }}
- name: Read version from repository using bash shell
id: read-file-bash
shell: bash
run: |
content=`cat version.txt`
echo outputContent=$content >> $GITHUB_OUTPUT
- name: Print version from file to console
id: write-content
shell: bash
run: |
echo "Pwsh version: ${{ steps.read-file.outputs.outputContent }}"
echo "Bash version: ${{ steps.read-file-bash.outputs.outputContent }}"
Windows runners-based jobs in Github actions:
The Windows runner on GitHub action supports some more shells than the Linux one & provides the output parameters within GH actions to be persisted in $GITHUB_OUTPUT using the below-given syntax.
Shell | Output syntax |
bash | echo {name}={value} >> $GITHUB_OUTPUT |
pwsh | echo {name}={value} >> $env:GITHUB_OUTPUT |
windows powershell | "{name}={value}" >> Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append |
cmd | echo {name}=%{value}% >> %GITHUB_OUTPUT% |
jobs:
Windows-Runner:
runs-on: windows-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Read version from repository using PS Core
id: read-file
shell: pwsh
run: |
$content = Get-Content -Path version.txt -Raw
echo outputContent=$content >> $env:GITHUB_OUTPUT
working-directory: ${{ github.workspace }}
- name: Read version from repository using bash shell
id: read-file-bash
shell: bash
run: |
content=`cat version.txt`
echo outputContent=$content >> $GITHUB_OUTPUT
working-directory: ${{ github.workspace }}
- name: Read version from repository using Powershell
id: read-file-ps
shell: powershell
run: |
$content = Get-Content -Path version.txt -Raw
"outputContent=$content" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
working-directory: ${{ github.workspace }}
- name: Read version from repository using Cmd
id: read-file-cmd
shell: cmd
run: |
set /p content=<version.txt
echo outputContent=%content% >> %GITHUB_OUTPUT%
working-directory: ${{ github.workspace }}
- name: Print version from file to console
id: write-content
shell: pwsh
run: |
echo "Pwsh version: ${{ steps.read-file.outputs.outputContent }}"
echo "Bash version: ${{ steps.read-file-bash.outputs.outputContent }}"
echo "Powershell version: ${{ steps.read-file-ps.outputs.outputContent }}"
echo "CMD version: ${{ steps.read-file-cmd.outputs.outputContent }}"
When you always target the same OS, it won't matter much, but if you have multi-platform jobs, matrix jobs, reusable templates, and composite actions, it pays to be explicit. That way your bash script won't suddenly be executed by PowerShell or vice versa.
The documentation on the GitHub documentation page regarding this is not too detailed & can lead to some trial and error before ending up with the right way of passing outputs between steps/jobs.
Note: There is a clear difference between PowerShell Core and Windows Powershell. While Windows Powershell only supports windows kernels, PowerShell Core is a cross-platform version of the same supporting executions in Linux & macOS kernels as well.
This post is just to cover the learnings that I had from my journey while using GitHub actions.