Search code examples
github-actions

GitHub Action - Define Workflow Level Environment Variable Between Jobs


I'd like to define and set environment variable between jobs inside my Github Actions Workflow. The workflow below is what I've tried but unfortunately the environment variable GIT_PR_SHA_SHORT and E2E_GIT_PR_SHA not working.

Is it possible?

name: Git Pull Request Workflow

on:
  workflow_dispatch:
  pull_request:
    branches:
      - master

env:
  GIT_PR_SHA: ${{github.event.pull_request.head.sha}}
  GIT_PR_SHA_SHORT: "${{ env.GIT_PR_SHA:0:10 }}"
  ENV_NAME: test
  E2E_GIT_PR_SHA: "${{ env.ENV_NAME }}-${{ env.GIT_PR_SHA_SHORT }}"

jobs:
  first-job:
    name: Build Docker Image
    runs-on: ubuntu-latest

    steps:
    - name: First Echo Step
      run: |
            echo "GIT_PR_SHA_SHORT = ${GIT_PR_SHA_SHORT}"
            echo "E2E_GIT_PR_SHA = ${E2E_GIT_PR_SHA}"

  second-job:
    name: Build Docker Image
    runs-on: ubuntu-latest

    steps:
    - name: Second Echo Step
      run: |
            echo "GIT_PR_SHA_SHORT = ${GIT_PR_SHA_SHORT}"
            echo "E2E_GIT_PR_SHA = ${E2E_GIT_PR_SHA}"

Solution

  • You reference a workflow's environment variables with ${{ env.VARIABLE_NAME }} not ${VARIABLE_NAME}. The latter is bash syntax, but these are not shell environment variables, they're workflow environment variables. They're part of the workflow execution, not part of the shell's context.

    To reference a workflow environment variable:

    name: Git Pull Request Workflow
    
    on:
      workflow_dispatch:
      pull_request:
        branches:
          - master
    
    env:
      one: 1
      two: zwei
      three: tres
    
    jobs:
      first-job:
        runs-on: ubuntu-latest
        steps:
        - run: |
            echo "${{ env.one }}"
            echo "${{ env.two }}"
            echo "${{ env.three }}"
    

    (I like to use lower-case for my workflow environment variables, and UPPER_CASE for my shell environment variables, so that it's more obvious to me which is which.)

    Similarly, this won't work:

    env:
      GIT_PR_SHA_SHORT: "${{ env.GIT_PR_SHA:0:10 }}"
    

    This is mixing bash syntax :0:10 with the workflow syntax, but the workflow variables are not run through any shell. No virtual machine has been started when the workflow file is parsed, so there's no shell to run things though.

    If you wanted to use bash expressions to manipulate the environment, you would need to create a step that runs bash to do that, and you would need to use the ::set-env or ::set-output syntax.

    Then you can refer to a step's output using the ${{ steps... }} context.

    Unfortunately, passing things between different jobs is trickier, since they run on different virtual machines. You'll need to set variables on the overall workflow itself. You'll need to first ::set-output so that it's visible to the job, then you can raise the visibility from the job to the workflow.

    name: Demonstration
    on:
      push:
        branches: [master]
    
    jobs:
      first-job:
        runs-on: ubuntu-latest  
        steps:
        - id: identify
          run: |
            # use bash variable expression to get the substring
            export GIT_PR_SHA="${{ github.sha }}"
            export GIT_PR_SHA_SHORT="${GIT_PR_SHA:0:10}"
    
            echo "git_pr_sha=${GIT_PR_SHA}" >> $GITHUB_OUTPUT
            echo "git_pr_sha_short=${GIT_PR_SHA_SHORT}" >> $GITHUB_OUTPUT
        outputs:
          git_pr_sha: ${{ steps.identify.outputs.git_pr_sha }}
          git_pr_sha_short: ${{ steps.identify.outputs.git_pr_sha_short }}
    
      second-job:
        needs: first-job
        runs-on: ubuntu-latest
        steps:
        - run: |
            echo "${{ needs.first-job.outputs.git_pr_sha }}"
            echo "${{ needs.first-job.outputs.git_pr_sha_short }}"