My Reusable GitHub Actions Workflows

• 5 min read

As you might know, I'm a big fan of GitHub Actions. I've written a few actions myself and use GitHub's automation platform in all my projects.

A neat but lesser-known feature of GitHub Actions is reusable workflows.

As the name might suggest, you can collect your most-used workflows in a public repository once and reuse them in your other projects – public or private. (Check out this section of a talk I gave in 2023 about this feature to learn more.)

A couple of weeks ago, I set up a reusable-workflows repository for my personal projects and made that repository public: stefanzweifel/reusable-workflows.

In this post, I would like to highlight some of my most cherished workflows and explain why I keep some types of workflows out of the reusable-workflows repository.

Fixing Code Style Issues #

These are the low-hanging fruits of automation: making sure my code is formatted correctly.
I use Laravel Pint or php-cs-fixer in my projects. So, I created a reusable workflow for each of them.

In my PHP projects, I now add a .github/workflows/laravel-pint-fixer.yml file with the following content:

name: Laravel Pint

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  pint:
    uses: stefanzweifel/reusable-workflows/.github/workflows/laravel-pint-fixer.yml@main

This will trigger the workflow on every push to main or when a commit is pushed to a pull request.
If wrongly formatted code has been pushed, the workflow will fix that and push a commit back to the repository.

Under the hood the workflow uses my git-auto-commit-action to detect the changes. The resulting commit won't trigger a re-run of the test suite. In my opinion a differently formatted piece of code should not have an effect on the results of a test suite.

Repository Maintenance & Administration #

Next I would like to highlight the workflows I use in my public and private repositories to keep them up-to-date and automate chores.

My auto-merge-dependabot-pr.yml workflow does what the file-name suggests. It automatically merges a Dependabot pull request when the test-workflow succeeds. (I've written a blog post on how this workflow works before).

The release-drafter.yml and update-changelog.yml workflows are primarily used in my public projects.

With release-drafter.yml I build up my release notes based on pull request labels. (I've written in the past, on how I use labels like changelog:added or changelog:removed to categorize pull requests into the right "changelog category").

update-changelog.yml is triggered, when I create a new release within GitHub. It will take the body of the release and place it in the right spot inside of CHANGELOG.md. Links to compare views will also be updated.


All three workflows automate the tedious admin work of keeping my projects up to date.
And the changelog workflows ensure that all my packages have a great history of all the changes made to them. My part of being a good open source maintainer.

Backup Integrity Checker #

The backup-restore.yml workflow is a recent addition to my collection.

On a schedule, the latest database backup is being downloaded, decrypted and imported into a MySQL database. Checks ensure that the database backup is healthy and complete.

In my project, all I have to do is create this workflow and add variables and secrets to access the database backup from an S3 bucket.

name: backup

on:
  workflow_dispatch:
  schedule:
    - cron: "0 14 1 * *"

jobs:
  restore:
    uses: stefanzweifel/reusable-workflows/.github/workflows/backup-restore.yml@main
    with:
      # Value of `APP_NAME` env variable. Used to locate backup on remote disk.
      app_name: 'My Laravel App'
      php_version: '8.3'
    secrets:
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
      AWS_BACKUP_BUCKET: ${{ secrets.AWS_BACKUP_BUCKET }}
      BACKUP_ARCHIVE_PASSWORD: ${{ secrets.BACKUP_ARCHIVE_PASSWORD }}

You can learn more about the history of this workflow in the "Introducing laravel-backup-restore" blog post.

What about Test Workflows? #

In my reusable-workflows-repository you won't find a generic "run my test suite" workflow.

Running the test suite always differs from project to project. Some apps use MySQL, PostgreSQL or sqlite. Some require specific PHP extensions or software installed on the server.
Creating a workflow that is flexible enough for all these requirements is possible, but would lead to a complex YAML configuration filled with if-clauses and ‌boolean options.

I like to keep things simple and easy to understand. Each project gets its own test workflow.

Outro #

If your organisation or team works with many GitHub repositories and you copy and paste workflows from one repo to the other or you've asked yourself "Where is the most recent version of this workflow?" I suggest you give reusable-workflows a try.

In addition to less duplicated code, you can version your reusable workflows. In the examples shown in this blog post, I always referenced the @main version of a workflow. But you could introduce a basic semantic versioning system, that lets other developers in your organisation use @v1 or @v2 of your workflows.


My collection of workflows still grows.

Next up on my list is adding Duncan McClean's post-release-comments action to a workflow, so folks get notified, when the changes from their pull request was released.