I am trying to deploy infrastructure as code from main
branch on multiple environments with GitHub environments. I want to deploy whenever there is merge/push to main in development env, but when there is a tag on the commit like r2022-09-07
deploy the code on a staging env. but it fails every time due to the protection rule.
This is the error I get when the code needs to be deployed on staging:
This is the ci.yml
workflow I have for deploying on multiple env from main
branch using GitHub env.
name: Lint, Compile and Deploy
on:
push:
branches: [main]
tags:
- 'r*'
pull_request:
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: install deps
run: yarn --frozen-lockfile
- run: yarn lint
- run: yarn prettier
- run: yarn compile
- run: yarn synth
- run: yarn test
# CD: ci -> dev -> staging -> production
## only deploy to dev from main branch
deploy-dev:
if: ${{ github.ref_name == 'main' }}
needs: ci
runs-on: ubuntu-latest
environment:
name: Dev
url: https://...
env:
STACK: ...
AAD_TENANT: ...
ARM_TENANT_ID: ...
ARM_ACCESS_KEY: ${{ secrets.ARM_ACCESS_KEY }}
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
steps:
- uses: actions/checkout@v3
- run: yarn --frozen-lockfile --production
- run: |
az login --service-principal --tenant $AAD_TENANT \
--username "${{ secrets.AZURE_CLIENT_ID }}" --password "${{ secrets.AZURE_CLIENT_SECRET }}"
yarn deploy $STACK --auto-approve
## deploy to staging only from main branch, if a commit has a tag starting with `r` (for ex. r2022-09-07)
deploy-staging:
if: ${{ startsWith(github.ref, 'refs/tags/r') }}
runs-on: ubuntu-latest
environment:
name: Staging
URL: ....
env:
STACK: ...
AAD_TENANT: ...
ARM_TENANT_ID: ...
ARM_ACCESS_KEY: ${{ secrets.ARM_ACCESS_KEY }}
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
steps:
- uses: actions/checkout@v3
- run: yarn --frozen-lockfile --production
- run: |
az login --service-principal --tenant $AAD_TENANT \
--username "${{ secrets.AZURE_CLIENT_ID }}" --password "${{ secrets.AZURE_CLIENT_SECRET }}"
yarn deploy $STACK --auto-approve
Staging env protection rules configs:
I was following the official GitHub docs but didn't find anything specific for this case, any idea what should be fixed in the above yaml?
Based on your last screenshot, push events on the main
branch are going to be permitted to use the Staging
environment.
I've been playing around with Environments too and had my own question, which lead me to yours!
My suggestion would be to remove branch protections and then use workflow logic to call the specific Environment:
on:
push:
branches: [main]
tags:
- 'r*'
pull_request:
jobs:
ci:
if: startsWith(github.ref_name, 'r*') || github.ref_name == 'main'
runs-on: ubuntu-latest
environment: Staging
steps:
...
If you want to deploy to dev
when you only push to main:
on:
push:
branches: [main]
jobs:
ci-dev-only:
if: github.ref_name == main
runs-on: ubuntu-latest
environment: dev
steps:
...
ci-staging:
if: github.ref_type == tag
runs-on: ubuntu-latest
environment: staging
steps:
...
ci-prod:
if: github.ref_type == tag && startsWith(github.ref_name, 'r*')
runs-on: ubuntu-latest
environment: prod
steps:
...
Keep in mind that tags are branch agnostic. You can't pin them on a branch.
That all being said, I think releasing to dev from your main branch is an anti-pattern. While there are some use cases that use main as a development branch, deployments to dev should be done in a branch. The reason being is that your main branch should be your source of truth. If your code is likely to change between your last push to main to when you tag it, it really should be done in a branch.
A better pattern would be that you push to staging on main, and then production on a tag.
But if you have a business case for your pattern, feel free to ignore me.