Introduction
Hello, DEV World! 😉 Continuing the series of articles on automating routine using the excellent CI/CD tool — GitHub Actions.
It's time to automate the releases of your applications written on Go!
📝 Table of contents
- What will we automate?
- Configure GitHub Action
- Troubleshooting
- Time to release!
- Questions for better understanding
- Exercises for independent execution
🤔 What will we automate?
If you've ever faced the challenge of releasing a project written on Go for different platforms/OS, you already know what kind of problems you may come across. If not, I will bring some of them:
- You need to constantly monitor the features of each OS (for example, specific slashes in the paths).
- You need to create archives manually and upload them to the release page on GitHub.
- You need to look at all the commits to make
CHANGELOG
for a new version. - ...and many more!
So, what if I told you that there is a tool that will allow you to do all this (and more) automatically after creating a tag in your repository?
I'm not kidding, it allows you to do all this with GoReleaser
GitHub action 👇
goreleaser
/
goreleaser-action
:octocat: GitHub Action for GoReleaser
GoReleaser Action
GitHub Action for GoReleaser
Usage
Workflow
name: goreleaser
on:
pull_request:
push:
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
IMPORTANT: note the
fetch-depth: 0
input inCheckout
step. It is required for the changelog to work correctly.
Run on new tag
If you want to run GoReleaser only…
👀 Repository structure
For a short, project will be contain very simple function:
package main
import "fmt"
func main() {
fmt.Println("Hi, DEV World! 😉")
}
And the repository structure will be as simple as that:
.
├── .github
│ └── workflows
│ └── release_build.yml # <-- GitHub Action
└── main.go # <-- main function
🤖 Configure GitHub Action
Let's move on to the main character of our story. Look at the listing of the file release_build.yml
, which already has a lot of familiar elements (if you did read my previous articles about GitHub Action 😏):
name: Release Go project
on:
push:
tags:
- "*" # triggers only if push new tag version, like `0.8.4` or else
jobs:
build:
name: GoReleaser build
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
fetch-depth: 0 # See: https://goreleaser.com/ci/actions/
- name: Set up Go 1.14
uses: actions/setup-go@v2
with:
go-version: 1.14
id: go
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@master
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}
Yes, GitHub automatically creates a GITHUB_TOKEN
secret to use in your workflow, but I recommend to create your own token with repo
scopes here:
And now, create new GitHub secret (GO_RELEASER_GITHUB_TOKEN
in my case):
✅ Troubleshooting
If your file with main()
function is not in the root directory of your repository, GoReleaser will generate an error. Therefore, you will need to specify the correct directory in the step settings, for example like this:
# ...
steps:
# ...
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@master
with:
version: latest
args: release --rm-dist
workdir: ./cmd/myapp # <-- path to directory with main() func
env:
GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}
🚀 Time to release!
Create new release with tag (in my case, it's 0.8.4
) and go to Actions page in order to follow up on the job:
After successfully completing the job, go to release page to see awesome result: CHANGELOG
with all of your commits (between two versions), checksums.txt
file and uploaded archives with compiled apps for all platforms!
That's it! Just like that! 🎉
🎯 Real-life example
If the screenshots above are not enough, I invite you to look at the one of my projects, where I use GoReleaser
action in real-life:
create-go-app
/
cli
✨ Create a new production-ready project with backend, frontend and deploy automation by running one CLI command!

Create Go App CLI
Create a new production-ready project with backend (Golang), frontend (JavaScript, TypeScript)
and deploy automation (Ansible, Docker) by running one CLI command.
Focus on writing code and thinking of business-logic! The CLI will take care of the rest.
⚡️ Quick start
First of all, download and install Go. Version 1.17
or higher is required.
If you're looking for the Create Go App CLI for Go
1.16
, you can find it here.
Installation is done by using the go install
command and rename installed binary in $GOPATH/bin
:
go install github.com/create-go-app/cli/v3/cmd/cgapp@latest
Also, macOS and GNU/Linux users available way to install via Homebrew:
# Tap a new formula:
brew tap create-go-app/cli
# Installation:
brew install create-go-app/cli/cgapp
Let's create a new project via interactive console UI (or CUI for short) in current folder:
cgapp create
Next, open the generated Ansible inventory file (called hosts.ini
) and…
💬 Questions for better understanding
- Which parameter in the GitHub Actions config is triggering job?
- Why we need to define
fetch-depth: 0
foractions/checkout
action? - What does the
-rm-dist
argument mean inRun GoReleaser
step?
✏️ Exercises for independent execution
- Repeat everything you have seen in the article, but with your own Golang project. Please, write about your result & link to your shorter website in the comments below!
- Change the triggering value so that it only works for major versions. Please, read more about software versioning here.
Photos/Images by
P.S.
If you want more — write a comment below & follow me. Thx! 😘
Discussion (5)
I'm curious why you recommend that?
Hi! Thank you for asking.
Now I've reread this place in my article and I don't really understand either :)
Usually, I use several secret variables for various manipulations of the repository. So, I am already used to making a new key.
If you don't need it, you may not follow my recommendation, but I wrote this "as for myself from the past" :D
I was looking into this and I noticed that the README for goreleaser-action says that you may need to generate your own token if you want to publish to an external repo (which you'd need to do if you are publishing your project to homebrew, for example).
Just awesome detailed instructions, love them
I wish you had this blog when i was studying in uni :D
Wow! Glad to hear it. 😘