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
- https://colinsalmcorner.com/consuming-environment-secrets-in-reusable-workflows. This blogpost finally gave me the insight I needed and is very much what I use as the end result.
- https://docs.github.com/en/actions/using-workflows/reusing-workflows
- https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment