How to set workflow env variables depending on branch

Viewed 11921

I currently have two GitHub actions workflow files that are pretty much identical, only one is configured to react to push/pull_requests on branch master the other on production.

The staging workflow starts like this:

env:
  GCLOUD_PROJECT: my-project-stg
  VERCEL_TARGET: staging

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

The production workflow starts like:

env:
  GCLOUD_PROJECT: my-project-prd
  VERCEL_TARGET: production

on:
  push:
    branches: [ production ]
  pull_request:
    branches: [ production ]

The rest of the workflow files is the same, so this is clearly not very DRY.

I would like to have 1 single workflow file and somehow switch between two sets of variables based on the branch name. Is there a way to achieve this or am I maybe approach this from the wrong angle?

If it were possible to extend both workflow files on a shared base definition that would also solve it I guess.

4 Answers

It is not possible to set workflow-level environment variables from a job. Each job runs in its own machine and setting an env variable there only affects all of the later steps in that job.

There are currently two ways to share data between jobs; either you create an artifact and use that, or you declare and set job outputs. The latter works for string values.

Here's an example:

name: "Main"

on:
  push:
    branches:
      - master
      - production
  pull_request:
    branches:
      - master
      - production

jobs:
  init:
    runs-on: ubuntu-latest
    outputs:
      gcloud_project: ${{ steps.setvars.outputs.gcloud_project }}
      phase: ${{ steps.setvars.outputs.phase }}

    steps:
      - name: Cancel previous workflow
        uses: styfle/cancel-workflow-action@0.4.0
        with:
          access_token: ${{ github.token }}

      - name: Set variables
        id: setvars
        run: |
          if [[ "${{github.base_ref}}" == "master" || "${{github.ref}}" == "refs/heads/master" ]]; then
            echo "::set-output name=gcloud_project::my-project-dev"
            echo "::set-output name=phase::staging"
          fi

          if [[ "${{github.base_ref}}" == "production" || "${{github.ref}}" == "refs/heads/production" ]]; then
            echo "::set-output name=gcloud_project::my-project-prd"
            echo "::set-output name=phase::production"
          fi

  print:
    runs-on: ubuntu-latest
    needs: init
    steps:
      - name: Print
        run: echo "gcloud_project=${{needs.init.outputs.gcloud_project}}"
       

You can drop the global env statement, combine the event triggers to

on:
  push:
    branches:
      - master
      - production
  pull_request:
    branches:
      - master
      - production

and then add a first step that checks which branch the workflow is running on and set the environment there:

      - name: Set environment for branch
        run: |
          if [[ $GITHUB_REF == 'refs/heads/master' ]]; then
              echo "GLCOUD_PROJECT=my-project-stg" >> "$GITHUB_ENV"
              echo "VERCEL_TARGET=staging" >> "$GITHUB_ENV"
          else
              echo "GLCOUD_PROJECT=my-project-prd" >> "$GITHUB_ENV"
              echo "VERCEL_TARGET=production" >> "$GITHUB_ENV"
          fi

Things could have changed but for anyone still searching for an answer, there is a way to set a variabe visible for the entire workflow.

 jobs:
  weekday_job:
    runs-on: ubuntu-latest
    env:
      DAY_OF_WEEK: Mon

Then access by jobs.<job_id>.steps[*].env

More info in the docs

Related