---
title: Triggering Reusable Github Actions Workflows
teaser: Tired of updating small details on your Open Source READMEs? Automate the
  process with GitHub Reusable and Dispatch Workflows.
tags: automation,ci,cicd,process
author: Stefanni Brasil
published_on: 2024-03-21
---

We have lots of open source projects. I mean, [hundreds of them].

Besides loving [Open Source], we also love creating and perfecting our processes. We even have a [templates repo]
to streamline some of them.

However, the READMEs tend to get outdated often. For example, lots of repositories had
a broken link to an image, or page.

![OSS READMEs with broken image logos](https://images.thoughtbot.com/1q49hj8mxjagjaa464ks1i8ebw02_broken_logo_image.png)

I saw some colleagues updating the image links, and I even did that myself. Twice.

No way I would do that for about 100 repositories -- and worse: next time the image link was broken,
do it all again.

I realized... there must be another way!

## Automate development processes with GitHub Actions

I asked our [CI specialists] for help. That's when this journey of exploring GitHub Actions (GHA)
reusable workflows and triggering dispatch workflows started.

The idea was to:

- centralize the README template file(s);
- when they get updated, propagate the updates to all the repos using the template file(s).

Looks rad, right?

I have only been using GHA for basic needs such as dependabot, managing labels, etc. I did not know you could
call workflows from different repositories, or even update an external repository using workflow dispatch actions 😎

## Dynamic README GitHub Action

To get started, we used this [Dynamic Readme] GitHub Action (GHA), which is available in GitHub's marketplace. The
difference was that we wanted to make it reusable and future-proof for our > 100 repos.

The first step was to add this reusable action to our [templates repo]:

```yaml
# templates/.github/workflows/dynamic-readme.yaml

name: Dynamic README reusable workflow

env:
  VS_WORKFLOW_TYPE: "dynamic-readme"
on:
  workflow_call:
    secrets:
      token:
        required: true

jobs:
  update_templates:
    name: "Update Templates"
    runs-on: ubuntu-latest
    steps:
      - name: "📥  Fetching Repository Contents"
        uses: actions/checkout@main

      - name: "💾  Github Repository Metadata"
        uses: varunsridharan/action-repository-meta@main
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: "💫  Dynamic Template Render"
        uses: varunsridharan/action-dynamic-readme@main
        with:
          GLOBAL_TEMPLATE_REPOSITORY: thoughtbot/templates
          files: |
            README.md
          committer_name: github-actions[bot]
          committer_email: github-actions[bot]@users.noreply.github.com
          commit_message: "docs: update readme file with markdown templates"
          confirm_and_push: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create pull request
        id: cpr
        uses: peter-evans/create-pull-request@v6
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: "docs: documentation files updated"
          committer: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
          author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
          signoff: false
          branch: github-actions/repository-maintenance-${{ github.sha }}
          delete-branch: true
          title: "Automatically Generated: Update Dynamic Section in README"
          body: |
            This PR was automatically generated to update the dynamic section in the README file.
            Whenever the README is updated, this workflow is triggered to dynamically render the snippet
            used in the README.
```

What makes this action [reusable] is the `workflow_call:` key. It means that external repos can access
this workflow.

Note that the workflow opens a Pull Request with the README changes. This was necessary because
we have [Open Source] projects that had branch protection rules. If you don't need that, you can edit
the steps to push directly to main instead.

Let's see how that works.

## Reusable GitHub Actions Workflows

To call the reusable GHA workflow above in an external repo and generate the README dynamically, we need to:

- create a workflow calling the reusable workflow above;
- add the Dynamic README snippet to the README.

### Calling a Reusable GitHub Workflow

In the new repository, create this workflow:

```yml
# new-repository/.github/workflows/dynamic-readme.yml

name: update-templates

on:
  push:
    branches:
      - main
    paths:
      - README.md
  workflow_dispatch:

jobs:
  update-templates:
    permissions:
      contents: write
      pull-requests: write
      pages: write
    uses: thoughtbot/templates/.github/workflows/dynamic-readme.yaml@main # <----- calls the reusable workflow
    secrets:
      token: ${{ secrets.GITHUB_TOKEN }}
```

As you can see, this workflow is concise. It calls our [reusable gha workflow](#dynamic-readme-github-action)
and handles the necessary permissions.

Whenever we want to change the Dynamic README workflow itself, say change the commit message, we only do it in the [original workflow](#dynamic-readme-github-action).

You might have to make any edits depending on your repo/organization permissions. For our repos, the needed
workflow permissions are satisfied with GitHub's Automatic token authentication.

### Add the Dynamic README snippet

In the new repository's README, add the dynamic README snippet:

```markdown
<!-- START /templates/footer.md -->
<!-- END /templates/footer.md -->
```

With these changes, the README for the new repository is rendered
dynamically by using the content from our [centralized template file].

Now, let's go to the best part: keeping all of our Open Source READMEs up to date by triggering
dispatch workflows.

## Triggering GitHub Actions Dispatch Workflows

Besides avoiding duplication by using a reusable workflow, it would be perfect if, whenever the footer template was updated,
the changes would get propagated to all the repos using the workflow.

It turns out...there is a way! One way is to use a [workflow_dispatch] GHA:

```yml
# templates/.github/workflows/trigger-dynamic-readme-update.yaml

name: trigger-dynamic-readme-update

on:
  push:
    branches:
      - main
    paths:
      - templates/footer.md

jobs:
  trigger-workflow-dispatch:
    permissions:
      actions: write
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Dynamic READMEs to be updated with templates
        uses: benc-uk/workflow-dispatch@v1
        with:
          workflow: update-templates
          repo: thoughtbot/high_voltage
          token: ${{ secrets.PAT_TOKEN }}
          ref: "main"
```

This workflow "listens" to updates on the `templates/footer.md` file.

When there are any,
it triggers the `update-templates` action on the `thoughtbot/high_voltage` repo.

If you have a long list of repos (like we do) to include here, you can use a matrix to list them all:

```yml
# templates/.github/workflows/trigger-dynamic-readme-update.yaml

name: trigger-dynamic-readme-update

on:
  push:
    branches:
      - main
    paths:
      - templates/footer.md

jobs:
  trigger-workflow-dispatch:
    permissions:
      actions: write
    runs-on: ubuntu-latest
    strategy:
      matrix:
        repository:
          - thoughtbot/high_voltage
          - thoughtbot/guides
          - thoughtbot/administrate
          # - and so on
    steps:
      - name: Trigger Dynamic READMEs to be updated with templates
        uses: benc-uk/workflow-dispatch@v1
        with:
          workflow: update-templates
          repo: ${{ matrix.repository }} # iterates through each of the strategy matrix repository list item
          token: ${{ secrets.PAT_TOKEN }}
          ref: "main"
```

"Wait, but how does a repo using this workflow know there was an update?"

Good question! It knows because the workflow added to the [repositories using the template](#calling-a-reusable-github-workflow)
constains a `workflow_dispatch` key.

Whenever we update the footer template, all of the repos listed in the repo matrix will
trigger their `update-templates`, which will render the footer dynamically.

### Workflow dispatch actions and security tokens

The [workflow_dispatch] action requires a Personal access token when using it on external repos.

In the templates repo, we

- created a [personal GitHub access token] (PAT) for thoughtbot's organization;
- pasted it in a Repository secret called `PAT_TOKEN`.

![Adding secrets to a GitHub actions on a repository](https://images.thoughtbot.com/15hu5hkkb9fegcyk1pv3wsyugwxw_github-secrets-repository.png)

## Debugging GitHub Reusable and Dispatch Workflows

Debugging GHA workflows is... annoying. What helped me during this process was to create a repo to get familiar with the flows. I messed up with the git history as much as I needed. Trust me, it took me a few ~~hundred~~ tries to get it working. Hopefully this post will save you from going through some of them ;)

## Automating processes with Reusable workflows

Let's recap. Putting it all together:

- [templates repo]:
  - reusable and workflow dispatch actions
  - footer README template
- [repo using the workflows]:
  - calls the reusable workflow
  - adds the dynamic README snippet to the README

The cool part of all of this journey is that even the [templates repo] itself is using the dynamic README to generate its footer.

What other processes could you explore automating a process like this one? The possibilities are endless. Have fun!

---

Thanks, immensely, to [Akshith Yellapragada], [Mina Slater], and [Nick Charlton] for the pairings, examples, and reviews.

[hundreds of them]: https://github.com/thoughtbot?q=&type=public&language=&sort=
[Open Source]: https://thoughtbot.com/open-source
[templates repo]: https://github.com/thoughtbot/templates
[Dynamic Readme]: https://github.com/marketplace/actions/dynamic-readme
[CI specialists]: https://thoughtbot.com/devops-sre-cloud-platform
[reusable]: https://docs.github.com/en/actions/using-workflows/reusing-workflows
[centralized template file]: https://github.com/thoughtbot/templates/blob/main/templates/footer.md
[workflow_dispatch]: https://github.com/marketplace/actions/workflow-dispatch
[personal GitHub access token]: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
[repo using the workflows]: https://github.com/thoughtbot/laptop
[Akshith Yellapragada]: https://thoughtbot.com/blog/authors/akshith-yellapragada
[Mina Slater]: https://thoughtbot.com/blog/authors/mina-slater
[Nick Charlton]: https://thoughtbot.com/blog/authors/nick-charlton
