Using GitHub Actions to add Go binaries to a Release
Shortly after building a script to create binaries for Rodeo, my command line Flickr uploader, I realised that I could use a Github Actions workflow to run it and attach the created binaries to the Release page once I had created it.
This is what I did.
Trigger on release
A GitHub Actions workflow is a YAML file and each workflow has to be triggered. For Continuous Integration, it’s common to trigger when new PR is opened or a new commit is pushed and then run tests on the code. In this case, I want to trigger when a new release is created.
This is done in the on section:
.github/workflows/build-release-binaries.yml
name: Build Release Binaries
on:
release:
types:
- created
GitHUb documents the list of events that trigger workflows and there’s many. For each event (such as release) there are a number of activity types so you can be quite selective on exactly when you want the workflow to run. In this case, I want to bulid the binaries when the release is created.
The workflow steps
I have one job which is imaginatively named build.
Set up
Each job has a set of steps and the first few are set up ones:
jobs:
build:
name: Build Release Assets
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.20
- name: Display the version of go that we have installed
run: go version
- name: Display the release tag
run: echo ${{ github.event.release.tag_name }}
The workflow runs inside a container, so firstly we checkout the code and install Go. I then display the version of Go and the tag name to check that all is okay. This is mostly useful when something goes wrong.
Build the binaries
We already know how to build release binaries, so we can just run a script that does that:
- name: Build the Rodeo executables
run: ./build-executables.sh ${{ github.event.release.tag_name }}
- name: List the Rodeo executables
run: ls -l ./release
I’ve written build-executables.sh to take the version number as the first argument so that we can pass in the tag name. We then list what has been built to ensure that it is as we expect.
Upload the binaries
Finally we need to upload the binaries to the release. We use Sven-Hendrik Haase’s upload-release-action to do this.
- name: Upload the Rodeo binaries
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
file: ./release/rodeo-*
file_glob: true
A really nice feature of this action is that it can upload multiple binaries in a single step. This is incredibly useful as GitHub Actions workflows do not support looping of steps, just looping of jobs via the matrix property. Using matrix is wastegul for us as it creates a whole new container for each iteration. We do not need this as with Go one container can build all the binaries.
By setting the file_glob property to true, we can set the file property to a glob pattern and so reference all the files in the release directory.
and done
This workflow runs automatically whenever I create a new release on GitHub, automatically building the binaries against that version of the code and attaching them so that people can download them without needing to build themselves.
Automations like this are what CI/CD pipelines are for.
What do you think about goreleaser? https://goreleaser.com/