In this post I will show you how you can deploy to different environments (think dev, staging, prod) using Github Actions.
The core problem we are solving is that the deployment must use specific AWS keys to access our dev, staging and prod environments. In my case, Github Environments aren't available yet. This means that Environment specific secrets can't be used. Since we need to set the correct AWS keys as environment variables for our deploy step, a work around was needed.
How we are going to solve this problem is that we will extract the branch name in our build job and place it in the outputs of that job. Then using that output value, we can add an if statement to our environment specific jobs.
In our build job, we do the following:
jobs:
build:
runs-on: ubuntu-latest
outputs:
branch: ${{ steps.extract_branch.outputs.branch }}
steps:
- uses: actions/checkout@v2
- name: Extract branch name
shell: bash
run: echo "::set-output name=branch::$(echo ${GITHUB_REF#refs/heads/})"
id: extract_branch
The outputs section declares an output called branch that is the output of a step. (Output Inception!). In the step extract_branch, we use the set-output operator to set the value of the step output. So basically the output value goes from step -> output -> job -> output.
Next we can reference the output of the build job in the declaration of the other jobs:
deploy-dev:
needs: build
runs-on: ubuntu-latest
if: ${{ needs.build.outputs.branch == 'dev' }}
The if statement in the job declaration will cause the job to be skipped if the branch name doesn't equal the required branch name for that job. This way you can make the job dependent on the branch you pushed.
For your reference, here is the complete yaml declaration of the workflow. I modified one of my workflows to remove identifiable information, this might not work in a simple copy-paste.
name: Build and deploy our application
on:
push:
branches: [ dev, staging, prod]
jobs:
build:
runs-on: ubuntu-latest
outputs:
branch: ${{ steps.extract_branch.outputs.branch }}
steps:
- uses: actions/checkout@v2
- name: Extract branch name
shell: bash
run: echo "::set-output name=branch::$(echo ${GITHUB_REF#refs/heads/})"
id: extract_branch
- run: my-custom-build-script.sh
- name: Upload built frontend files
uses: actions/upload-artifact@v2
with:
name: app-build
path: dist
retention-days: 1
deploy-dev:
needs: build
runs-on: ubuntu-latest
if: ${{ needs.build.outputs.branch == 'dev' }}
steps:
- name: Download built frontend files
uses: actions/download-artifact@v2
with:
name: app-build
path: dist
- run: aws s3 sync . s3://app-${{ needs.build.outputs.branch}}-bucket
working-directory: dist
env:
AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_KEY }}
AWS_DEFAULT_REGION: "eu-central-1"
deploy-staging:
needs: build
runs-on: ubuntu-latest
if: ${{ needs.build.outputs.branch == 'staging' }}
steps:
- name: Download built frontend files
uses: actions/download-artifact@v2
with:
name: app-build
path: dist
- run: aws s3 sync . s3://app-${{ needs.build.outputs.branch}}-bucket
working-directory: dist
env:
AWS_ACCESS_KEY_ID: ${{ secrets.STAGING_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.STAGING_AWS_SECRET_KEY }}
AWS_DEFAULT_REGION: "eu-central-1"
deploy-prod:
needs: build
runs-on: ubuntu-latest
if: ${{ needs.build.outputs.branch == 'prod' }}
steps:
- name: Download built frontend files
uses: actions/download-artifact@v2
with:
name: app-build
path: dist
- run: aws s3 sync . s3://app-${{ needs.build.outputs.branch}}-bucket
working-directory: dist
env:
AWS_ACCESS_KEY_ID: ${{ secrets.PROD_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.PROD_AWS_SECRET_KEY }}
AWS_DEFAULT_REGION: "eu-central-1"