CI/CD for a Go CLI Tool with GitHub Actions
Test, cross-compile, and release your Go CLI for every platform with GoReleaser.
A Go CLI ships as cross-compiled binaries for several OS and architecture pairs. GoReleaser automates the build matrix, archives, checksums, and the GitHub Release. This recipe tests on PRs and releases on tags.
What the pipeline does
- set up Go with module caching
- vet and lint
- run tests
- cross-compile with GoReleaser on a tag
- publish archives and checksums to a Release
The workflow
GoReleaser reads .goreleaser.yml for the build matrix and archive config. It runs only on tags and uses GITHUB_TOKEN to create the release.
name: CI
on:
push:
branches: [main]
tags: ['v*']
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true
- run: go vet ./...
- run: go test ./...
release:
needs: test
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- uses: goreleaser/goreleaser-action@v6
with:
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Caching and speed
setup-go caches modules and build output for the test job. The release job cross-compiles for many targets, which is CPU-heavy; cheaper managed runners such as Latchkey (around 69% cheaper than GitHub-hosted) cut release time and auto-retry transient module proxy failures.
Deploying
GoReleaser attaches per-platform archives and a checksums file to the GitHub Release, and can also update a Homebrew tap, push a Docker image, or publish to a Scoop bucket. Users install via the release, brew, or go install.
Key takeaways
- GoReleaser automates the cross-compile matrix and release.
- Set fetch-depth: 0 so GoReleaser sees tags and changelog.
- It can also update Homebrew taps and push Docker images.