Mastering GitHub Actions with Reusable Workflows: Simplifying Your YAML

Joël AZÉMAR
2 min readJun 14, 2023

--

How to DRYup your GA with Workflows!

While GitHub Actions (GA) provides powerful automation using YAML, there’s always room for improvement.

Many hoped for the YAML Anchor feature to keep our files DRY (Don’t Repeat Yourself). But two years on, GitHub Actions still doesn’t support this.

Instead, GitHub introduces Reusable Workflows and Composite Actions to ensure a neat workspace.

What Are YAML Anchors?

For the uninitiated, YAML Anchors allow for the definition of common sections, which can then be reused elsewhere within the same YAML file. For instance:

default: &default
adapter: mysql2
encoding: utf8mb4

development:
<<: *default
database: dummy_project_development

Such a feature aids in eliminating redundancy. In my prior article, [Speed Up Your CI With Docker (Github Actions)], the lack of Anchors led to repetitions that reduced readability and maintainability.

To demonstrate, consider this basic example:

name: Use Reusable Workflow

on: [push]

jobs:
prepare:
runs-on: ubuntu-latest
steps:
-
run: echo Prepare!
shell: bash

test-alpha:
needs: prepare
runs-on: ubuntu-latest
steps:
-
run: echo Test A!
shell: bash

test-beta:
needs: prepare
runs-on: ubuntu-latest
steps:
-
run: echo Test B!
shell: bash

Here, the ‘prepare’ section needs execution every time. The ‘test-*’ sections contain the repetitions we aim to DRY up.

The Power of Reusable Workflows

By harnessing Reusable Workflows, the repetitive ‘test-*’ sections can be refactored into another file:

name: The Reusable Workflow

on:
workflow_call:
inputs:
test-name:
required: true
type: string

jobs:
test:
name: "Test ${{ inputs.test-name }}"
runs-on: ubuntu-latest
steps:
-
run: echo Test ${{ inputs.test-name }}.
shell: bash

Even if there aren’t any inputs/outputs, it’s essential to declare on: [workflow_call].

Then, the primary section gets streamlined as:

name: Use Reusable Workflow

on: [push]

jobs:
prepare:
runs-on: ubuntu-latest
steps:
-
run: echo Prepare!
shell: bash
test-alpha:
needs: prepare
uses: <github-name>/<repositoy-name>/.github/workflows/reusable-workflow.yml@main
with:
test-name: "Alpha"

test-beta:
needs: prepare
uses: <github-name>/<repositoy-name>/.github/workflows/reusable-workflow.yml@main
with:
test-name: "Beta"

Just ensure that the ‘prepare’ job runs initially and passes the necessary inputs to the reusable job. Voila! Your workflow is now cleaner and more efficient.

--

--