Environments and Reusable Workflows in GitHub Actions


When the need for multiple different environments arises while testing and deploying an app GitHub’s Reusable Workflows and configurable Environment secrets/variables comes in handy.

But getting these two things to work together isn’t as intuitive as expected (at this point). This is how I solved it, after many trial and error loops, learning and tons of googling.

As there are plenty of both blogpots and Youtube videos out there for using reusable workflows and environments (separately mainly) I won’t go into detail of that here.

Scenario

I have a deploy workflow for an Azure Static Website, and since that handles nicely if it’s production or staging I want to reuse it, but with different inputs depending on if the start of the workflow is a PR or push to main.

During this deployment workflow, variables are pulled from the environment to populate the web apps configuration file, thus the need to switch environment depending on if it’s a push to a staging site or production.

Two environments are defined, Stage and Production both have a secret, SECRET_NAME defined along with a variable a_variable.

Solution

Lets look at the deployment yml file first as below.

name: Deploy WebApp to Azure

on:
  workflow_call:
    inputs:
       environment:
        type: string
        description: environment to deploy to
        required: true
    secrets:
      SECRET_NAME:
        required: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
   
    steps:
     - name: Instead of real deployment, just print some variables
        shell: bash
        run: |
          echo "Name: $name"
          echo "environment: $environment"
          echo "a_variable: $a_variable"
        env:
          name: ${{ secrets.SECRET_NAME }}
          environment: ${{ inputs.environment }}
          a_variable: ${{ vars.a_variable }}

Obviously, it’s a placeholder file for the real deployment but I’m sure you are getting it.

Firstly, on the workflow_call there are inputs defined for the environment, that is required. This is wat is used further down the establish what environment to use. There are also secrets defined and required that are used further down. I have found that the secretes didn’t need to be defined when both workflow files are in the same repository, but haven’t experimented further, leaving it open to be provided with in two different ways as shown below.

The calling workflow

The deployment file is called from another workflow, in my case the workflow that checks the PR to verify it should be allowed. With simplify code:

name: Verify Pull-request

on:
  workflow_dispatch:
  pull_request:

jobs:
  deploy-stage:
    uses: ./.github/workflows/deploy.yml
    secrets: inherit
    with:
      environment: Stage
  
  deploy-production:
    uses: ./.github/workflows/deploy.yml
    secrets:
      SECRET_NAME: ${{ secrets.SECRET_NAME }}
    with:
      environment: Production

Here the deployment workflow is called twice (usually with e2e testing in between). First with the staging environment, and the second time with production. This will mean that the deployment workflow will run with separate set of secrets and variables (if defined in environment) the two times.

And that is it, more or less. There are details of how to supply secrets to the reusable workflow, look in on the documentation linked below if it is needed.

Outbound links


Leave a Reply

Your email address will not be published. Required fields are marked *