Painless Github releases with Drone and GoReleaser

Štěpán Vraný
Mar 30, 2019 · 5 min read

A few days ago, I’ve joined Golang community @ and I’ve found there an interesting tool GoReleaser, what a coincidence! Same day I was about to move CI/CD for one of my repository to, so a decision was made: I’m gonna switch to these tools at the same time.


If it is not obvious, I’m gonna provide you a brief summary. Manual releases are way too time consuming, boring and no one cares about those extra 10 minutes you have invested in this pointless manual procedure.

This short post will show you how to setup CI/CD pipeline which does all this stuff automatically based on git tags and SemVer versioning.

Installation of GoReleaser

You know Golang ecosystem, right? Everything there is just plug & play, download and profit. GoReleaser is not any different, download it, extract it and use it!

Simple application

Now let’s create our Golang application.

package mainimport "fmt"func main() {
fmt.Println(" Hello! My name is Elder Price, and I would like to share with you the most amazing book!")

Then we can initialize GoReleaser with goreleaser initcommand, this step will create a new .goreleaser.yml with following content:

# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at
# you may remove this if you don't use vgo
- go mod download
# you may remove this if you don't need go generate
- go generate ./...
- env:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
name_template: 'checksums.txt'
name_template: "{{ .Tag }}-next"
sort: asc
- '^docs:'
- '^test:'

As we don’t do anything special now we’re good to go for now. Let’s try to build the first release locally.

goreleaser --snapshot --skip-publish --rm-dist

In GOPATH/src you can get error message about disabled modules. There are two solutions for this issue. Remove hooks from .goreleaser.yaml or set GO111MODULEenvironment variable to on

This command will create a snapshot version in the dist directory. Let’s see the actual output.

goreleaser-demo tree dist 
├── checksums.txt
├── config.yaml
├── darwin_386
├── darwin_amd64
├── linux_386
├── linux_amd64
├── _v0.0.0-next_Darwin_i386.tar.gz
├── _v0.0.0-next_Darwin_x86_64.tar.gz
├── _v0.0.0-next_Linux_i386.tar.gz
└── _v0.0.0-next_Linux_x86_64.tar.gz

As you can see — we have binaries for all major platforms. Cool. Now we can create our first SemVer release. Let’s do this!

git add .goreleaser.yml main.go
git commit -m "initial release"
git tag -a v0.0.1 -m "initial release"
git remote add origin
git push origin master -f --tags
goreleaser --skip-publish --rm-dist

Now we should see the correct version in the dist directory. Let’s quickly check it.

├── checksums.txt
├── config.yaml
├── darwin_386
│ └── goreleaser-demo
├── darwin_amd64
│ └── goreleaser-demo
├── goreleaser-demo_0.0.1_Darwin_i386.tar.gz
├── goreleaser-demo_0.0.1_Darwin_x86_64.tar.gz
├── goreleaser-demo_0.0.1_Linux_i386.tar.gz
├── goreleaser-demo_0.0.1_Linux_x86_64.tar.gz
├── linux_386
│ └── goreleaser-demo
└── linux_amd64
└── goreleaser-demo

Here we go!

CI/CD integration

As I’ve said before — I’m lazy bastard. And this state does not make the whole thing any easier. I want to run these tasks automatically but in a collaborative way!

You can publish your releases directly from your computer by omitting --skip-publish flag but such process smells a bit …

As GoReleaser is just single binary — we can integrate it with in CI/CD tooling. Now I’m gonna show you basic pipeline but the release process looks the same way on other CI/CD platforms.

So this is my .drone.ymlfile:

base: /go
image: docker:git
- git fetch --tags

- tag
image: golang:latest
secrets: [github_token]
- curl -sL | bash

As my dummy program does pretty much nothing I have skipped testing and linting. Make sure you have configured testing and linting pipeline in the real life scenarios!

Now we just need to enable for this project, add Github API key to the project’s secrets and push our changes to the CVS.

git add .drone.yml
git commit -m "setup cd"
git tag -a v0.0.2 -m "dummy release"
git push origin master --tags

Push to master will immediately trigger process defined in .drone.yml file. You can check all logs in interface.

Everything is just perfect here so we can check releases page in the Github project and see if everything works as expected.

Damn yes! This is just perfect. All the future releases will be published automatically so I don’t have to think about the correct sequence of steps in the release process anymore.


It seems that GoReleaser generates some sort of automatic Changelog based on the commit history. According to SemVer, this is not 100% correct approach so you should use this automatic behaviour with some caution.

Thankfully, this behaviour can be overridden with --release-notes flag so you can publish release notes which are just silky smooth 😂

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store