Using GitHub workflows to automate adding extra commits to Renovate Pull Requests
We've been using Renovate for quite a while now (switching from Dependabot), which scans our GitHub repositories and opens Pull Requests to update dependency versions. It works great, easy to activate, and means we don't have to manually check for updates for all of our dependencies.
There was however one issue we ran into, which is that once Renovate has updated the version of a dependency, there are times that we then need to run other commands to generate more changes to the code. One example is Terraform Docs - which is a tool that generates documentation for Terraform projects and modules.
At first, we dealt with this manually. Just pulled down the renovate branch, ran terraform-docs .
, made an extra commit and pushed it back up. But it got to a point that we were doing it often enough, that I decided to look further into an automated solution. This took me down a road of extra issue ๐ฌ
Renovate settings
I'd not really done much with Renovate settings, just enabling it and letting it do it's thing. So I had a quick search online, to find if there was a way to configure it to run a command once it had made an update.
The only setting that looked like it'd help, was the postUpgradeTasks
... But unfortunately this option was only available for self-hosted Renovate instances ๐
As a last resort, I asked ChatGPT just in case I missed anything - And it spewed out a load of configuration claiming it could do it, but nope ...
Adding a commit using GitHub workflows, but only for Renovate branches
So the Terraform Docs GitHub action does have an option to add a commit if it finds any changes that are needed, however we disabled this by default, and instead just fail the check if Terraform Docs hasn't been ran for the pull request. We decided to do this, because it adds a lot of 'terraform-docs' commits and messages, and can make the git history look a bit horid.
There was no way around having these extra Terraform Docs commits for Renovate PRs, because if you squash commits and push to a Renovate managed branch, it'll just re-run itself and erase the extra code changes. So I looked into a way to only run the Terraform Docs GitHub action with git-push: true
parameter set. Say hello to another issue ...
To get the branch name of a Pull Request, we can use the github.head_ref
property. We can then check to see if it begins with renovate/
and conditionally run a step. However, this is only available on Pull Requests. If it's used on Pushes (eg. after the PR has been merged into main), the workflow will fail. If we use the github.ref
property, this would work for all branches, but on a Pull Request, it returns the format refs/pull/{pull_request_number}/merge
- so we couldn't tell if it was a renovate branch.
So this is what I came up with:
on:
push:
branches: main
pull_request:
env:
GITHUB_PR_BRANCH: ""
jobs:
terraform-docs-validation:
name: Terraform Docs validation
needs: terraform-validate
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Get PR base branch
id: pr-base-branch-name
if: github.event_name == 'pull_request'
run: |
echo "GITHUB_PR_BRANCH=${{ github.head_ref }}" >> $GITHUB_ENV
- name: Generate Terraform docs
uses: terraform-docs/gh-actions@v1.0.0
if: "!startsWith(env.GITHUB_PR_BRANCH, 'renovate/')"
with:
working-dir: .
config-file: .terraform-docs.yml
output-file: README.md
output-method: inject
fail-on-diff: true
- name: Generate Terraform docs for Renovate
uses: terraform-docs/gh-actions@v1.0.0
if: "startsWith(env.GITHUB_PR_BRANCH, 'renovate/')"
with:
working-dir: .
config-file: .terraform-docs.yml
output-file: README.md
output-method: inject
git-push: true
ref: ${{ github.event.pull_request.head.ref }}
What this does is:
- Initiate the
GITHUB_PR_BRANCH
environment variable - Checks out the code
- If the
github.event_name
is 'pull_request', set theGITHUB_PR_BRANCH
environment variable to thegithub.head_ref
value - If the branch name doesn't begin with
renovate/
, it will run terraform-docs without making a commit, but fail by using thefail-on-diff: true
parameter - If the branch name does bein with
renovate/
, it will run terraform-docs with thegit-push: true
parameter, making an extra commit.
At first, it looked like it was working ... But then quickly realised that the GitHub workflows weren't being triggered once the new commit was added ๐
Allowing commits added through GitHub workflows to trigger the GitHub checks
I had a feeling that the checks weren't running due to some permissions issue, as the extra commit is made from within the workflow triggered by Renovate, using the default GITHUB_TOKEN
.
However, thanks to a blog post I stumbled across (which you can find here: https://joht.github.io/johtizen/build/2022/01/20/github-actions-push-into-repository.html ), I found out that it's a feature of GitHub workflows to not allow the GITHUB_TOKEN
to run the checks when making commits - because it could end up causing an infinite loop of workflow runs.
I then found the GitHub documentation that confirms this: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow
When you use the repository's
GITHUB_TOKEN
to perform tasks, events triggered by theGITHUB_TOKEN
, with the exception ofยworkflow_dispatch
andrepository_dispatch
, will not create a new workflow run. This prevents you from accidentally creating recursive workflow runs.
Using a Personal Access Token (PAT) to create the commit
Personal Access Tokens in GitHub projects has always felt a bit funny - They were (until recently) tied to a specific GitHub account. If we had to use one, we would just hope that the person who created it, didn't accidently (or intentionally) delete it, as that could potentially break things. So I was hoping that I wouldn't need to use a PAT.
However, with the new 'Fine-grained' tokens, we can can create tokens, setting the 'Resource Owner' to a GitHub Organisation. These are currently in Beta, and require them to be activated within the Organisation Settings. You can find out more about Fine-grained tokens here: https://github.blog/2022-10-18-introducing-fine-grained-personal-access-tokens-for-github/
I went ahead and created a PAT with our GitHub Organisation as the resource owner (With repository 'Contents' permission set to read/write), and then set the token as an Organisation Secret, so that it can be used across multiple repositories.
Now all I needed to do, was add this to the Checkout github action within the `terraform-validate` job:
steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
token: ${{ secrets.TERRAFORM_DOCS_RENOVATE_WORKFLOW_GITHUB_TOKEN }}
Finally we now had Renovate PRs that would add the commit, and then run the checks again to make sure everything was okay ๐
An example PR for this change can be found here: https://github.com/dxw/terraform-template/pull/15