Quick Guide to Running Sub-Workflows With GitHub Actions

Automation wizard and Cogworks developer Adrian Ochmann talks about two strategies that can help you run effective sub-workflows using GitHub actions.

Introducing GitHub workflow.

GitHub describes its workflow as a configurable automated process made up of one or more jobs. With a plan behind configuration, your GitHub Actions workflow can handle some of the most complex build tasks, automating build, tests and deployment elements of your projects.

Sub Workflows with GitHub Actions.

One of the main issues found with GitHub Actions is how to trigger sub-workflows from the main workflow.  In an ideal world, developers should be able to manage our actions within a single workflow and add responsibilities to each job along with the conditions they depend on. But, as you can imagine, this way of management could grow into a large, unreadable file as GitHub Actions doesn’t currently give the option to split workflow items into template files and include them in the main template file (like you can with Azure DevOps). A similar option is already available in Azure DevOps, so maybe one day teams will transfer this feature to Github too.

GitHub Workflow tutorials:

1) The Personal Access Token strategy.

This strategy is great if you prefer working with built-in git functionalities, it entails that you create workflows that depend on direct repository changes such as given tags or branches.

What are the benefits of a Personal Access Token (PAT) Strategy? 

- It’s simple to use as defining event trigger options, like tag, branch, or push is very easy to handle. 
- Workflows and actions are triggered by the events happening in the Git repository directly, so you only need to rely on creating a tag or branch.

And the cons?

- Misuse can cause looping or recursion and increase costs.
- There isn’t a graph view, which can be used for debugging, browsing, logging and validating the process. It’s not easy to cancel new workflows if there are multiple workflows triggered at the same time (there is no controlled workflows order for the same trigger).
- To achieve a logical and controlled sequence of events, we need to create temporary branches or tags, there is also a need to clean them after.

How to implement the PAT token strategy. 

Create an organisation repository token that allows repo scope permissions and add the token value as your secret repository settings.

 

In the code, all you have to do in the main workflow is create a dedicated trigger event, such as creating a new git tag or branch.

 

 

Assign the PAT token you have created to pass the tag or branch to the repository. To do this, add your PAT token 

- uses: actions/checkout@v2
  with:
   token: ${{ secrets.PAT_TOKEN }}

Push your tag using the PAT token

git push "https://$GITHUB_ACTOR:${{ secrets.PAT_TOKEN }}@github.com/$GITHUB_REPOSITORY.git" tag-pat/work/${{ env.tag }} -f

Examples of the complete set of workflows with the PAT strategy implemented.

Main workflow: tag-pat-main.yml

name: Tag PAT Main
on:
  push:
    tags:
      - tag-pat/main/*
 
jobs:
  work:
    name: Some Work
    runs-on: ubuntu-latest
 
    env:
      tag: ${GITHUB_REF#refs/tags/tag-pat/main/}
 
    steps:
      - uses: actions/checkout@v2
        with:
          token: ${{ secrets.PAT_TOKEN }}
      - run: echo "Some Main work"
      - run: echo "Tag ${{ env.tag }}"
      - run: |
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
 
          git tag -a tag-pat/work/${{ env.tag }} -m "${{ env.tag }}"
 
          git push "https://$GITHUB_ACTOR:${{ secrets.PAT_TOKEN }}@github.com/$GITHUB_REPOSITORY.git" tag-pat/work/${{ env.tag }} -f


Worker workflow: tag-pat-work.yml

 

name: Tag PAT Work
 
on:
  push:
    tags:
      - tag-pat/work/*
 
jobs:
  work:
    name: Some Work
    runs-on: ubuntu-latest
    env:
      tag: ${GITHUB_REF#refs/tags/tag-pat/work/}
    steps:
      - run: echo "Some PAT work"
      - run: echo "Tag ${{ env.tag }}"


Results after completed actions:


The result of pushing a new tag (for example tag-pat/main/1.0.0) will be that the main workflow (Tag PAT Main / tag-pat-main.yml) is executed first and after successfully running then consumer/worker (Tag PAT Work/tag-pat-work.yml) was running.

2) Workflow Run Strategy.

This strategy is based on built-in GitHub Actions functionalities. The strategy allows you to create workflows that depend on a given main workflow by its name.

What are the benefits of the workflow run strategy?


- There’s no need to use a private access token, you can just use the built-in functionality based on the specific workflow names.
- No need to create temporary triggers like tags or branches to execute and trigger another workflow
- It’s easy to define and control the order of the workflows.


Any cons?

- Workflows only have two activity types: completed or requested. You need to create a job condition or expression to check previous workflow conclusions to determine if it was a  “success” or “failure” to allow or skip the specific workflow execution. For example,

github.event.workflow_run.conclusion == 'success'

- By default, the Workflow Run strategy works on the default branch (this is worth customising)
- No graph view - they don’t appear in the same way as in a single file.  
- It can be hard to cancel all new workflows if there are multiple new workflows triggered.
- A strict naming convention should be followed using this strategy. There’s little freedom to freely name your files. 

on:
  workflow_run:
    workflows: [ "Workflow Main" ]
    types:
      - completed

Example of the complete set of workflows with the workflow run strategy implemented.

Main workflow: workflow-main.yml

name: Workflow Main
 
on:
  push:
    tags:
      - workflow/*
 
jobs:
  work:
    name: Some Workflow Main Work
    runs-on: ubuntu-latest
    steps:
      - run: echo "Some Main work"

Example of the Worker workflow: workflow-work.yml

name: Workflow Work
 
on:
  workflow_run:
    workflows: [ "Workflow Main" ]
    types:
      - completed
  workflow_dispatch:
 
jobs:
  work:
    name: Some Workflow Work
    runs-on: ubuntu-latest
    steps:
      - run: echo "Some work"

Results after completed actions:



 

Summary

There are different strategies to run sub-workflows and each of them has pros and cons. Sometimes it is good to have a hybrid approach that can be used altogether: in a single file, tags approach, workflow run.
We’re moving towards a complete token-based approach in Cogworks and divided small, single-responsibility workflows. It allows us to control and maintain the specific workflows separately and apply them accordingly in various projects.

Maybe in the future, we will get similar functionality like in Azure DevOps - templating. For now, it's not built-in.


It's great to hear from our readers. If you have any questions, thoughts, or even requests for more topics like this in the comments box below!

Adrian

  • Image for Keeping Up With Digital Transformation Build

    Keeping Up With Digital Transformation

  • Image for A Frontend Developers Perspective on Headless Architecture Build

    A Frontend Developers Perspective on Headless Architecture

  • Image for Could Website Downtime Be Prevented? Build

    Could Website Downtime Be Prevented?

  • Image for How to Test Accessibility With Axe in Cypress Build

    How to Test Accessibility With Axe in Cypress

Ready to collaborate ?

Get in touch to see how we can transform your digital presence.

Send us a message