Automation wizard and Cogworks developer Adrian Ochmann talks about two strategies that can help you run effective sub-workflows using GitHub actions.
Hello, youve stumbled into the old Cogblog archives
We've switched our blogging focus to our new Innerworks content, where tech community members can share inspiring stories, content, and top tips. Because of this, old Cogworks blogs will soon be deleted from the site, so enjoy it while you can. A few of these might refer to images in the text, but those have been deleted already sorry. Some of these subjects will return, some aren't relevant anymore, and some just don't fit the unbiased community initiative of Innerworks.
If you'd like to take on this subject yourself please submit a new blog!
Farewell Cogworks Blog 💚
Introducing GitHub workflow.
GitHub describes its workflow as a 'configurable automated process comprising one or more jobs'. With a plan behind configuration, your GitHub Actions workflow can handle some of the most complex build tasks, automating your projects' build, tests and deployment elements.
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 their 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). Although you can find a similar workflow option available in Azure DevOps, 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 creating 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 in the Git repository directly, so you only need to create 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 workflow 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 Mainon: 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 }}"
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.
Cons of a workflow-run strategy.
- 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 the same way as in a single file.
- It can be hard to cancel all new workflows if multiple new workflows are 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:
Take the approach that suits you.
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, or workflow run.
We’re moving towards a complete token-based approach in Cogworks and divided small, single-responsibility workflows because 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 as 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
Innerworks and Cogworks are proud to partner with Community TechAid who aim to enable sustainable access to technology and skills needed to ensure digital inclusion for all. Any support you can give is hugely appreciated.