Skip to content

Instantly share code, notes, and snippets.

@thomasvincent
Created June 12, 2024 22:23
Show Gist options
  • Save thomasvincent/03440b6a82a772aa24158b09356cc1ec to your computer and use it in GitHub Desktop.
Save thomasvincent/03440b6a82a772aa24158b09356cc1ec to your computer and use it in GitHub Desktop.
Modern Go Makefile
# --- Project Configuration ---
PACKAGE := hellogopher
DATE ?= $(shell date +%FT%T%z)
VERSION ?= $(shell git describe --tags --always --dirty --match=v* 2> /dev/null || echo v0)
# --- Go Configuration ---
BIN := ./bin # Binary output directory
PKGS := $(shell go list ./... | grep -v /vendor/)
TESTPKGS := $(shell go list -f '{{ if or .TestGoFiles .XTestGoFiles }}{{ .ImportPath }}{{ end }}' ./...)
GO := go
# --- Build Options ---
TIMEOUT := 15
V := 0 # Verbosity level (0 = quiet, 1 = verbose)
Q := $(if $(filter 1,$V),,@)
M := $(shell printf "\033[34;1m▶\033[0m") # Blue arrow for output
# --- Build Targets ---
.PHONY: all
all: fmt lint | $(BIN)
$(info $(M) Building executable...)
$Q $(GO) build -tags release -ldflags '-X main.Version=$(VERSION) -X main.BuildDate=$(DATE)' -o $(BIN)/$(PACKAGE) .
$(BIN)/%: # Ensure the bin directory exists
mkdir -p $(BIN)
# --- Tools ---
$(BIN)/%: # Generic rule for installing Go tools in BIN
$(GO) install $(subst $(BIN)/,,$@)@latest # Extracts package name and installs with 'go install'
GOLANGCI_LINT = $(BIN)/golangci-lint
$(GOLANGCI_LINT): # Install golangci-lint if not found
$(info $(M) Installing golangci-lint...)
$Q $(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# --- Tests ---
TEST_TARGETS := test-default test-bench test-short test-verbose test-race
.PHONY: $(TEST_TARGETS) test-xml check test tests
test-bench: ARGS=-run=__absolutelynothing__ -bench=. ## Run benchmarks
test-short: ARGS=-short ## Run only short tests
test-verbose: ARGS=-v ## Run tests in verbose mode
test-race: ARGS=-race ## Run tests with race detector
$(TEST_TARGETS): test
check test tests: fmt lint ; $(info $(M) running $(NAME:%=% )tests…) @ ## Run tests
$Q $(GO) test -timeout $(TIMEOUT)s $(ARGS) $(TESTPKGS)
test-xml: fmt lint
$(info $(M) running $(NAME:%=% )tests…)
$Q mkdir -p test
$Q $(GO) test -json $(TESTPKGS) | tee test/tests.output | $(GO2XUNIT) -output test/tests.xml
# --- Lint ---
lint: | $(GOLANGCI_LINT)
$(info $(M) running golangci-lint...)
$Q $(GOLANGCI_LINT) run
# --- Format ---
fmt:
$(info $(M) running gofmt...)
@ret=0 && for d in $$($(GO) list -f '{{.Dir}}' ./... | grep -v /vendor/); do \
$(GOFMT) -l -w $$d/*.go || ret=$$? ; \
done ; exit $$ret
# --- Misc ---
.PHONY: clean
clean: ; $(info $(M) cleaning…) @ ## Cleanup everything
@rm -rf $(BIN)
@rm -rf test/tests.* test/coverage.*
.PHONY: help
help:
@grep -E '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
.PHONY: version
version:
@echo $(VERSION)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment