Github Actions, how to share a calculated value between job steps?
Asked Answered
M

3

93

Is there a DRY way to calculate and share a value in multiple job steps with Github Actions?

In the below workflow yml file, echo ${GITHUB_REF} | cut -d'/' -f3`-${GITHUB_SHA} is repeated in multiple steps.

name: Test, Build and Deploy
on:
  push:
    branches:
      - master
jobs:
  build_and_push:
    name: Build and Push
    runs-on: ubuntu-latest
    steps:
      - name: Docker Build
        uses: "actions/docker/cli@master"
        with:
          args: build . --file Dockerfile -t cflynnus/blog:`echo ${GITHUB_REF} | cut -d'/' -f3`-${GITHUB_SHA}
      - name: Docker Tag Latest
        uses: "actions/docker/cli@master"
        with:
          args: tag cflynnus/blog:`echo ${GITHUB_REF} | cut -d'/' -f3`-${GITHUB_SHA} cflynnus/blog:latest
Madwort answered 6/9, 2019 at 9:43 Comment(2)
Relevant: docs.github.com/en/actions/reference/… and: github.blog/changelog/…Pushup
Using outputs with matrix jobs github.com/orgs/community/discussions/25634Pioneer
E
131

set-output can be used to define outputs for steps. The outputs can then be used in later steps and evaluated in with and env input sections. Also, the step returning outputs should have an id, which is referred to by the step consuming the outputs.

The following is what that would look like for your example.

name: Test, Build and Deploy
on:
  push:
    branches:
      - master
jobs:
  build_and_push:
    name: Build and Push
    runs-on: ubuntu-latest
    steps:
      - name: Set tag var
        id: vars
        run: echo "docker_tag=$(echo ${GITHUB_REF} | cut -d'/' -f3)-${GITHUB_SHA}" >> $GITHUB_OUTPUT
      - name: Docker Build
        uses: "actions/docker/cli@master"
        with:
          args: build . --file Dockerfile -t cflynnus/blog:${{ steps.vars.outputs.docker_tag }}
      - name: Docker Tag Latest
        uses: "actions/docker/cli@master"
        with:
          args: tag cflynnus/blog:${{ steps.vars.outputs.docker_tag }} cflynnus/blog:latest

Here is another example showing how to dynamically set multiple variables to be used by an action.

      - name: Set output variables
        id: vars
        run: |
          pr_title="[Test] Add report file $(date +%d-%m-%Y)"
          pr_body="This PR was auto-generated on $(date +%d-%m-%Y) \
            by [create-pull-request](https://github.com/peter-evans/create-pull-request)."
          echo "pr_title=$pr_title" >> $GITHUB_OUTPUT
          echo "pr_body=$pr_body" >> $GITHUB_OUTPUT
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v4
        with:
          title: ${{ steps.vars.outputs.pr_title }}
          body: ${{ steps.vars.outputs.pr_body }}

Alternatively you can create environment variables.

      - name: Set environment variables
        run: |
          echo "PR_TITLE=[Test] Add report file $(date +%d-%m-%Y)" >> $GITHUB_ENV
          echo "PR_BODY=This PR was auto-generated on $(date +%d-%m-%Y) by [create-pull-request](https://github.com/peter-evans/create-pull-request)." >> $GITHUB_ENV
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v4
        with:
          title: ${{ env.PR_TITLE }}
          body: ${{ env.PR_BODY }}

Update: The docker actions in the first example are deprecated. Please see this answer for the latest way to work with docker in GitHub Actions.

Note: For sharing values between different jobs, see this question.

Evenfall answered 18/9, 2019 at 9:9 Comment(6)
Just to be clear, these solutions do not work between steps of different jobsOrchard
Are this solutions deprecated? github.blog/changelog/…Prorogue
@Prorogue No they are not deprecated. These solutions show the current way to create step outputs and environment variables.Evenfall
@Orchard outputs across different jobs also seem to be supported, but you need to forward the step output to the job output: docs.github.com/en/actions/using-workflows/…Colostomy
Thanks! Not using quotes was the answer for me. echo '::set-output $(date +%s) ...' does not work but echo ::set-output $(date +%s)... works for substitute values.Howlyn
@Howlyn This is because (in shells in general) single quotes prevent parameter expansion. Using double quotes ("") would also work.Religious
A
38

set-output has been deprecated and the better way to do this is now:

echo "{name}={value}" >> $GITHUB_OUTPUT

Example from Github docs:

  - name: Set color
    id: random-color-generator
    run: echo "SELECTED_COLOR=green" >> $GITHUB_OUTPUT
  - name: Get color
    run: echo "The selected color is ${{ steps.random-color-generator.outputs.SELECTED_COLOR }}"
Asparagine answered 7/3, 2023 at 7:42 Comment(3)
also notice that it's "SELECTED_COLOR=green" without any space in the beginning, because I was struggling with an output var that has a space in the beginning >" SELECTED_COLOR=green".Deason
how can I read GITHUB_OUTPUT value inside a actions/github-script step?Pissarro
If your var is secret then you need to mask it first: echo "::add-mask::$my_secret" echo "MY_SECRET_VAR=$my_secret" >> $GITHUB_OUTPUTEucharis
W
0

In case anyone cannot set the environment variable on Windows, the syntax is slightly different, I spent a lot of time trying to figure out why I could not get it to work, hopefully it will save time if you have the same case.

How to set environment variable on Windows to be shared between actions:

$date = Get-Date -Format 'yyyy-MM-dd-HH-mm'
$zipFileName = "your_zip_file_$date.zip"
echo "ZIPFILE=$zipFileName" >> $env:GITHUB_ENV

After that in some other action you can access it like:

${{ env.ZIPFILE }}
Wappes answered 13/4 at 2:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.