Having build many Golang projects I came with a minimalist makefile that might work for you.
by Ciro S. Costa , Nov 11 - 2017
Most of the time I see myself creating a Golang project: be it a one-file single-purpose thing or a more complex project.
In order to facilitate that process, I try to always keep the structure the same such that there’s no need to put much thought into the process of bootstrapping a new project.
The file structure usually looks like this:
│ ├── foo.go
│ ├── foo_test.go
│ ├── something.go
│ └── something_test.go
Some things to pay attention:
editorconfigis a real deal - I use vim with
set shiftwidth=2; set tabstop=2, that is, 2 as the indentation. For
go, tabwith 8 spaces as indentation.
be it a cli tool or a library, I always make use of a
main.goin the root so that’s it’s obvious how to fetch it -
go get -u <repo>.
Given the filestructure described above, below is the Makefile. In this case I extracted the Makefile from a test project I started some time ago (a “load-balancer” that makes use of fasthttp: cirocosta/l7).
# I usually keep a `VERSION` file in the root so that anyone
# can clearly check what's the VERSION of `master` or any
# branch at any time by checking the `VERSION` in that git
VERSION := $(shell cat ./VERSION)
IMAGE_NAME := cirocosta/l7
# As a call to `make` without any arguments leads to the execution
# of the first target found I really prefer to make sure that this
# first one is a non-destructive one that does the most simple
# desired installation. It's very common to people set it as `all`
# but it could be anything like `a`.
# Install just performs a normal `go install` which builds the source
# files from the package at `./` (I like to keep a `main.go` in the root
# that imports other subpackages). As I always commit `vendor` to `git`
# a `go install` will typically always work - except if there's an OS
# limitation in the build flags (e.g, a linux-only project).
go install -v
# keeping `./main.go` with just a `cli` and `./lib/*.go` with actual
# logic, `tests` usually reside under `./lib` (or some other subdirectories).
# Here we could do something like `find . -name "*" -type d -exec ...` but IMO
# that's unnecessary. Just `cd`ing to what matters to you is fine - no need to
# handle the case of directories that you don't want to execute a command.
cd ./lib && go test -v
# Just like `test`, formatting what matters. As `main.go` is in the root,
# `go fmt` the root package. Then just `cd` to what matters to you (`vendor`
# doesn't matter).
cd ./lib && go fmt
# This target is only useful if you plan to also create a Docker image at
# the end. I have a separate `gist` with a sample Dockerfile tailored for
# golang that you can check out at <TODO>.
# I really like publishing a Docker image together with the GitHub release
# because Docker makes it very simple to someone run your binary without
# having to worry about the retrieval of the binary and execution of it
# - docker already provides the necessary boundaries.
docker build -t cirocosta/l7 .
# This is pretty much an optional thing that I tend to always include.
# Goreleaser is a tool that allows anyone to integrate a binary releasing
# process to their pipelines. Here in this target With just a simple
# `make release` you can have a `tag` created in GitHub with multiple
# builds if you wish.
# See more at `gorelease` github repo.
git tag -a $(VERSION) -m "Release" || true
git push origin $(VERSION)
.PHONY: install test fmt release
Save that content in the Makefile file in root directory of the project, create a
VERSION file with something like
0.0.1 (semver) and you’re ready to go.
I think it’s very useful to keep a standard way of performing basic operations across multiple repositories. In my experience this reduces the friction of moving from one project to another. Having a common flow of how to build, create an image and publish a project using a Makefile has helped me in such area.
Do you think the same? What are your thoughts?
Reach me on Twitter at any time @cirowrc and subscribe to the list if you’re a Golang developer or simply likes software stuff!