Using $GITHUB_OUTPUT to write output parameters from GitHub action jobs & steps

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:

ShellOutput syntax
bashecho {name}={value} >> $GITHUB_OUTPUT
pwshecho {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.

ShellOutput syntax
bashecho {name}={value} >> $GITHUB_OUTPUT
pwshecho {name}={value} >> $env:GITHUB_OUTPUT
windows powershell"{name}={value}" >> Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
cmdecho {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.