DEV Community

Rafael
Rafael

Posted on

Github Actions - Output

Introduction

As workflows are built and become more complex, there is a necessity to share information between steps, jobs, and even workflows themselves.

One of the most common ways to share values is by using GitHub outputs, due to their simplicity and being a built-in feature of workflows.

This material aims to explore the usage of outputs, their limitations, and best practices. Even though it's straightforward, caution should be exercised in certain aspects.

Output between Steps

The syntax to generate an output should follow the pattern:

echo "<output_name>=<output_value>" >> $GITHUB_OUTPUT

One of the simplest examples is sharing between steps within the same job.

on: 
   push: 

 jobs: 
   step-outputs: 
     runs-on: ubuntu-latest 
     steps: 
       - name: Get runner name 
         id: runner 
         run: | 
           echo "name=ubuntu-latest" >> $GITHUB_OUTPUT 

       - name: Show output 
         run: echo ${{ steps.runner.outputs.name }}
Enter fullscreen mode Exit fullscreen mode

In the above example, we have two steps: the first generates the output, and the second consumes it.

The first step has the attribute id with the value runner, allowing any other step within the same job to consume the generated output.

We can observe the consumption of the output in the second step using the following syntax:

${{ steps.<id_previous_step>.outputs.<output_name> }}

The result of the created workflow will display the value ubuntu-latest.

share output between steps

Output between Jobs

To share output between jobs, it's necessary to add the output property to the job that will generate the value.

This property should contain the reference to the step (as described above), and the job that will receive the value must have the needs property with the name of the preceding job.

Observe the example:

on:
  push:

jobs:
  job-1:
    runs-on: ubuntu-latest
    outputs:
      runner-name: ${{ steps.runner.outputs.name }}
    steps:
      - name: Set runner name
        id: runner
        run: |
          echo "name=ubuntu-latest" >> $GITHUB_OUTPUT
  job-2:
    runs-on: ubuntu-latest
    needs: job-1
    steps:
      - name: Show job-1 output
        run: |
          echo "Output job-1: ${{ needs.job-1.outputs.runner-name}}"
Enter fullscreen mode Exit fullscreen mode

Output with actions/core

It's also possible to use output through the github-script action.

This action is commonly used when integration with GitHub is required.

on:
  push:

jobs:
  job-actions-core:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/github-script@v6
        id: actions-core
        with:
          script: |
            core.setOutput('result', 'core')
      - name: show output actions-core
        run: |
          echo "${{ steps.actions-core.outputs.result }}"
Enter fullscreen mode Exit fullscreen mode

What Not to Do

Overwriting the GITHUB_OUTPUT Variable

A common mistake to watch out for is overwriting the GITHUB_OUTPUT variable within the same step. If this happens, all previously saved outputs will be lost.

on:
  push:

jobs:
  job-output-overwrite:
    runs-on: ubuntu-latest
    steps:
      - name: Overwrite output
        id: runner
        run: |
          echo "name=ubuntu-latest" >> $GITHUB_OUTPUT
          echo "so=linux" > $GITHUB_OUTPUT
      - name: show output
        run: |
          echo ${{ steps.runner.outputs.name }}
          echo ${{ steps.runner.outputs.so }}
Enter fullscreen mode Exit fullscreen mode

show result overwrite output

This occurs because the GITHUB_OUTPUT variable has a file as a reference.

Similar to the /etc/environment file, the GITHUB_OUTPUT file is loaded with each new step.

Sharing Secrets

Values stored in secrets cannot be shared as output between jobs.

Let's assume there is a secret with the value my-secret. To add a secret, simply follow the path Settings > Secrets and variables > Actions > New repository secret.

saving secret in repository settings

Now let's assign the secret to an output.

jobs:
  job-1-secret:
    runs-on: ubuntu-latest
    outputs:
      value: ${{ steps.step-1.outputs.value }}
    steps:
      - name: Set secret as output
        id: step-1
        run: |
          echo "value=${{ secrets.SECRET_OUTPUT }}" >> $GITHUB_OUTPUT

  job-2-secret:
    runs-on: ubuntu-latest
    needs: job-1-secret
    steps:
      - name: Show output job-1-secret
        run: |
          echo "Output with secret: ${{ needs.job-1-secret.outputs.value}}"
Enter fullscreen mode Exit fullscreen mode

Upon executing the workflow, the following warning will be received.

Warning for sharing secret

Deprecated Output

The syntax below works, but it's deprecated and should not be used as we do not know when it will cease to function.

on:
  push:

jobs:
  job-deprecated-output:
    runs-on: ubuntu-latest
    steps:
      - name: Output deprecated
        id: runner
        run: echo "::set-output name=name::ubuntu-latest"
      - name: show output
        run: echo ${{ steps.runner.outputs.name }}
Enter fullscreen mode Exit fullscreen mode

Upon execution, the following warning can be observed.

deprecated output

For more information, refer to the GitHub post about Deprecating save-state and set-output commands.

Summary

In summary, GitHub workflows allow for sharing information between steps, jobs, and workflows through outputs. However, it's necessary to be mindful of potential syntax errors, value overwrites, and to stay informed about best practices for the tool by following the changelog.

Top comments (2)

Collapse
 
endymion1818 profile image
Ben Read

Thanks for your article, I'm just getting into GitHub Actions so this will come in handy.

Collapse
 
santimars profile image
Santi Rodriguez

I needed this!!! Thank you so much ❤️