Github Actions - Matrix Build with sequential deployments!

Intro

Github Actions Matrix Builds are a powerful way to parallelize build steps and thus significantly improve feedback loops in the CI pipeline. But did you know that you can use Matrix Builds not only for parallel build steps, but also for sequential ones?

This can save many lines of YAML, as long as the build steps are the same for all stages. As soon as one of the steps from the previous workflow fails, the whole pipeline will fail.

Example

The trick is to use a matrix build, limit concurrent executions to one and set fail-fast (to fail the whole workflow when a single step fails) to roll out deployments to different stages (for example a development environment, integration environment, production environment, …)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
...
jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        stage: ['development', 'integration', 'production']
      fail-fast: true
      max-parallel: 1
    steps:
      - name: do some stuff
        uses: ...
        with: ...

The magic happens rigt here:

1
2
3
4
5
6
matrix:
    stage: ['development', 'integration', 'production']
    # When set to true, GitHub cancels all in-progress jobs if any matrix job fails.
    fail-fast: true
    # The maximum number of jobs that can run simultaneously
    max-parallel: 1

It will be even cooler if we additionally use Github Environments to use stage specific secrets for each workflow run.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        stage: ['development', 'integration', 'production']
      fail-fast: true
      max-parallel: 1
    # set the environment to use (environment must exist and be named the same as the stage here)
    environment:
      name: ${{ matrix.stage }}
    steps:
    # use environment specific secrets here for each stage
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
          aws-region: wonderland-central-1
      - name: do some stuff
        uses: ...
        with: ...

Not only are the individual matrix builds executed sequentially, but also the secrets (here for example credentials to assume an AWS role within your workflow) for the respective stage are obtained from the environments!

That means the workflow does not change, because the build steps are the same. But they are parameterized differently by the secrets depending on the matrix build run taken from Github Environments. Sweet!