3 minute read

Use matrix to reduce duplication of steps

To repeat the same job with different environment variables in a GitHub Actions workflow and run the jobs in parallel, you can use the strategy and matrix keywords.

Here is an example of how to use these keywords in a workflow:

name: Deploy

on:
  push:
  workflow_dispatch:

jobs:
  deploy:
    name: deploy
    runs-on: ubuntu-latest
    strategy:
      matrix:
        stage: ['dev', 'prod']
      fail-fast: true
      max-parallel: 1
    env:
      TF_VAR_env: $
      TF_VAR_website_callback_urls: '["http://localhost/callback"]'
      TF_VAR_website_signout_urls: '["http://localhost/signout"]'
    steps:
    - name: Checkout
      uses: actions/checkout@v3
    - uses: actions/setup-node@v3
      with:
        node-version: 16
    - name: yarn build
      run: |
        yarn
        yarn build
    - name: Set up Terraform
      uses: hashicorp/setup-terraform@v1
    - name: Terraform Init
      working-directory: ./terraforms
      run: terraform init
      id: init
    - name: Terraform Plan
      working-directory: ./terraforms
      id: plan
      run: terraform plan -no-color -input=false
      continue-on-error: true
    - name: Terraform Plan Status
      if: steps.plan.outcome == 'failure'
      run: exit 1
    - name: Terraform Apply
      working-directory: ./terraforms
      id: apply
      if: github.ref == 'refs/heads/main' && github.event_name == 'push'
      run: terraform apply -auto-approve -input=false

In this example, the deploy job is defined with a strategy that creates a matrix of possible values for the env variable. The deploy job will be run once for each value in the matrix, with the corresponding env value set as an environment variable. In this case, the deploy job will be run twice, once with TF_VAR_env=dev and once with TF_VAR_env=prod.

Run a step conditionally based on a git branch name

To run a step in a GitHub Actions workflow conditionally based on the branch, you can use the if and unless keywords.

Here is an example of how to use these keywords in a workflow:

name: CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Use Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 14.x
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm test
      - name: Deploy to staging
        run: npm run deploy-staging
        if: $
      - name: Deploy to production
        run: npm run deploy-production
        if: $

In this example, the Deploy to staging step will be run only if the branch being pushed is staging, and the Deploy to production step will be run only if the branch being pushed is production.

You can also use the unless keyword to specify conditions that should be negated. For example:

      - name: Deploy to staging
        run: npm run deploy-staging
        unless: github.ref == 'refs/heads/main'

This step will be run unless the branch being pushed is production.

Run matrix job sequentially

The matrix feature allows you to execute jobs concurrently, eliminating the need to repeat common steps. However, I often need to run these jobs sequentially, particularly when deploying to dev and prod. In these situations, setting max-parallel to 1 is very useful.

jobs:
  deploy:
    name: deploy
    runs-on: ubuntu-latest
    strategy:
      matrix:
        stage: ['dev', 'prod']
      fail-fast: true
      max-parallel: 1
    env:
      TF_VAR_env: $
      TF_VAR_website_callback_urls: '["http://localhost/callback"]'
      TF_VAR_website_signout_urls: '["http://localhost/signout"]'

Trigger a workflow at a scheduled time

Cron syntax has five fields separated by a space, and each field represents a unit of time.

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
│ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
* * * * *

You can use these operators in any of the five fields:

Operator Description Example
* Any value 15 * * * * runs at every minute 15 of every hour of every day.
, Value list separator 2,10 4,5 * * * runs at minute 2 and 10 of the 4th and 5th hour of every day.
- Range of values 30 4-6 * * * runs at minute 30 of the 4th, 5th, and 6th hour.
/ Step values 20/15 * * * * runs every 15 minutes starting from minute 20 through 59 (minutes 20, 35, and 50).
name: Hourly Summary

on:
  schedule:
    - cron: '0 8-23 * * 1,2,3,4,5'
    - cron: '0 22,23 * * 0'

  workflow_dispatch:

You can validate your cron expression with cron tab.

Comments