3

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:
enter image description here

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:
enter image description here

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?

2 Answers2

1

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:
      ...

Edit based on comments made by OP on 10/12/2022

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.

scuba_mike
  • 360
  • 3
  • 12
  • Thanks for the answer, we tried this but it didn't work for our case. The idea is to Skip staging and production workflow when we have committed a push to the main branch, with this idea you mentioned above the deployment is always starting the staging ci workflow. We only want it when there is a release tag on a commit to deploy the code to staging and production from the main branch, and only in that case, the Staging and Production workflow should be triggered (tag release and deploy the code from main) otherwise skip the jobs for staging and prod and deploy only on Dev. – cloudlearner Oct 03 '22 at 09:50
  • There are a couple of run-on sentences in your comment but I think I know what you're saying: When `push`ing to main, only deploy to dev. When there is a tagged release on main, it should deploy to staging and prod correct? – scuba_mike Oct 10 '22 at 22:21
  • yes, correct. Atm, we just decline each deployment for staging triggered from each push on main branch. Once we decide to deploy to staging we just approve the latest commit to deploy to staging. – cloudlearner Oct 12 '22 at 09:29
  • I've edited my answer and hope that helps you. – scuba_mike Oct 14 '22 at 00:54
1

You can just add a branch protection rule for the tag. In your use case for r*

I follow semantic versioning and added a simple rule for v* like this: enter image description here

Now the deployments work.

EDIT: this per comment no longer works as of August 2023.

Bjoern Urban
  • 328
  • 4
  • 14
  • this is not working i tried because from github they stop supporting this https://github.com/orgs/community/discussions/62991#discussioncomment-6718696 – Jayendran Aug 30 '23 at 09:51
  • yes, they stopped supporting this after i answered the question, just two weeks ago. – Bjoern Urban Aug 31 '23 at 10:16
  • Also really don't understand why someone would downvote this. At the time of answer this worked perfectly well and the discussion on github tells us a lot of people disagree with this change. – Bjoern Urban Aug 31 '23 at 10:32