TLDR: https://github.com/marketplace/actions/consecutive-workflow-action
This article assumes some basic experience with GitHub Actions/Workflows.
When you work with GitHub Actions, you have almost infinite flexibility at your disposal and you can do almost anything. But sometimes you have to be a bit creative to achieve what you want.
Within a workflow, jobs are executed in parallel but you can create dependencies between jobs so that they run consecutively. Steps within a job always run one after another.
Workflows themselves always run independently of each other. You can trigger the same workflow multiple times and there will be multiple parallel runs. That’s perfectly fine in many common scenarios. When there are two new pull requests, submitted at almost the same time, your automated tests can run for both pull requests at the same time.
But there are situations where this actually leads to problems. I like to make my workflows not just perform some checks but actually update the repository. I use a repository kind of as a database. Automatically fixing code formatting issues is probably a more relatable use case. :D
The problem now with parallelism is of course this:
Updates were rejected because the remote contains work that you do not have locally.
This is usually caused by another repository pushing to the same ref.You may want to first integrate the remote changes (e.g., 'git pull ...') before pushing again.
See the 'Note about fast-forwards' in 'git push --help' for details.
Two workflow runs pushing to the same repository at almost the same time will most likely fail. Pulling changes right before pushing is the first thing that comes to mind but that can lead to merge conflicts that your workflow will not be able to resolve on its own.
So you need to make sure that workflow run B only clones the repository once workflow run A is done with pushing. They need to run consecutively. GitHub does not offer that out of the box but a sufficiently comprehensive API to implement it yourself. I’ll not cover the implementation in detail but this is the general, fairly simple idea:
As I mentioned before, you can create dependencies between jobs within a workflow. So the first job of the workflow is simply to look at its previous run and wait for it to complete. I don’t care about its result, whether it failed or succeeded or whatever, I just want to make sure it’s not running anymore. As long as that’s not the case, wait a bit and then check again. So there’s a nice little while loop involved to make sure this first job in our workflow blocks the rest of it until the previous run is completed.
I just published this as a GitHub Action that is super easy to use, in case I’m not the only one with the problem.
jobs:
consecutiveness:
runs-on: ubuntu-latest
steps:
- uses: mktcode/consecutive-workflow-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
# your other jobs
something:
runs-on: ubuntu-latest
needs: [ consecutiveness ]
steps:
# ...
One word about the GITHUB_TOKEN
... The token is needed to avoid rate limitation issues when performing API calls. Make sure you read the security note in the repository’s Readme.
That’s it! Hope its useful for some. If you leave a like for the article you make me feel more comfortable about writing articles like this. Follow me on GitHub if you are interested in what I’m working on. Thanks for reading! :)
Top comments (0)