« Back to Index

Make: Makefile help output

View original Gist on GitHub

Tags: #make #makefile #help #docs

1.Makefile

# See also: https://gist.github.com/Integralist/d61a365912576bcef88b29bd11207df3

.DEFAULT_GOAL := run  ## Default make target
TOOLS = ""            ## List of dev tools
TOOLS = \
	github.com/mgechev/revive \
	golang.org/x/lint/golint \
	golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness \
	golang.org/x/vuln/cmd/govulncheck \
	honnef.co/go/tools/cmd/staticcheck \
	mvdan.cc/gofumpt

# .PHONY: help
# help: ## Displays list of Makefile targets and documented variables
# 	@echo "Targets:"
# 	@grep -h -E '^[0-9a-zA-Z_.-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2}'
# 	@echo ""
# 	@echo "Variables:"
# 	@grep -h -E '^[0-9a-zA-Z_.-]+\s[?:]?=.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = "[?:]?=.*?## "}; {printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2}'
# 	@echo ""
# 	@echo "Default target:"
# 	@printf "  \033[36m%s\033[0m\n" $(.DEFAULT_GOAL)

# 
# The following implementation of `help` uses the length of the longest target name.
# Where as the above, earlier, implementation used a hardcoded length of 20.
# The problem with the above implementation is a long target name will then push out the 'columns'.
# 


.PHONY: help
help: ## Displays list of Makefile targets and documented variables
	@echo "Targets:"
	@MAX_LEN_TARGET=$$(grep -h -E '^[0-9a-zA-Z_.-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "; max=0} {len=length($$1); if (len>max) max=len} END {print max}'); \
	grep -h -E '^[0-9a-zA-Z_.-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
	awk -v max_len="$$MAX_LEN_TARGET" 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-" max_len "s\033[0m %s\n", $$1, $$2}'
	@echo ""
	@echo "Variables:"
	@MAX_LEN_VAR=$$(grep -h -E '^[0-9a-zA-Z_.-]+\s[?:]?=.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = "[?:]?=.*?## "; max=0} {len=length($$1); if (len>max) max=len} END {print max}'); \
	grep -h -E '^[0-9a-zA-Z_.-]+\s[?:]?=.*?## .*$$' $(MAKEFILE_LIST) | sort | \
	awk -v max_len="$$MAX_LEN_VAR" 'BEGIN {FS = "[?:]?=.*?## "}; {printf "  \033[36m%-" max_len "s\033[0m %s\n", $$1, $$2}'
	@echo ""
	@echo "Default target:"
	@printf "  \033[36m%s\033[0m\n" $(.DEFAULT_GOAL)

.PHONY: api-update
api-update: ## Update all API application dependencies
	go get -u -t ./...
	go mod tidy
	if [ -d "vendor" ]; then go mod vendor; fi

.PHONY: fmt
fmt: ## Format all Go files using gofumpt
	go tool -modfile=tools.mod gofumpt -w .

.PHONY: lint-all
lint-all: lint-golint lint-govet lint-govul lint-nilness lint-revive lint-staticcheck ## Lint project using all linters

.PHONY: lint-golint
lint-golint: ## Lint project using golint
	go tool -modfile=tools.mod golint -set_exit_status $(shell go list -f '{{.Dir}}' ./... )

.PHONY: lint-govet
lint-govet: ## Lint project using go vet
	go vet ./...

.PHONY: lint-govul
lint-govul: ## Lint project using govulncheck
	go tool -modfile=tools.mod govulncheck ./...

.PHONY: lint-nilness
lint-nilness: ## Lint project using nilness
	go tool -modfile=tools.mod nilness ./...

.PHONY: lint-revive
lint-revive: ## Lint project using revive
	go tool -modfile=tools.mod revive -config revive.toml ./...

.PHONY: lint-staticcheck
lint-staticcheck: ## Lint project using staticcheck
	go tool -modfile=tools.mod staticcheck ./...

.PHONY: run
run: ## Run the API server (opts: HUMANLOG=true)
	@# humanlog doesn't sort keys lexicographically.
	@# to do that we must set `--sort-longest=false`
	@# this causes the key sorting we want (as a side effect)
	@# while at the same time avoiding humanlog from trying to sort by key length
	go run ./cmd/api/main.go $(if \
		$(filter true,$(HUMANLOG)),| \
			humanlog \
				--message-fields=event \
				--sort-longest=false \
				--truncate=false, \
	)

.PHONY: test
test: ## Run the Go test suite
	go test ./...

.PHONY: tools-install
tools-install: ## Install dev tools
	@if [ ! -f tools.mod ]; then \
		echo "Initializing tools.mod"; \
		go mod init -modfile=tools.mod github.com/fastly/ascerta/tools; \
	fi
	@$(foreach tool,$(TOOLS), \
		if ! go tool -modfile=tools.mod | grep "$(tool)" >/dev/null; then \
			echo "installing $(tool)"; \
			go get -modfile=tools.mod -tool "$(tool)"@latest; \
		fi; \
	)
	@[ -x "$(shell which humanlog)" ] || curl -sSL "https://humanlog.io/install.sh" | NONINTERACTIVE=true bash

.PHONY: tools-update
tools-update: ## Update dev tools
	go get -u -modfile=tools.mod tool
	go mod tidy

# checkmake (https://github.com/mrtazz/checkmake) requires these targets be set
.PHONY: all clean test

2.Makefile

# IF YOU NEED TO EXCLUDE TARGETS FROM A PARENT MAKEFILE!

include base.mk

# Regex pattern of targets to omit from the help output (`make h`).
OMIT_TARGETS := (help|lint):

.PHONY: h
h:  ## Filtered version of `help` target from base.mk
	@printf "Targets\n"
	@grep -h -E '^[0-9a-zA-Z_.-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | grep -vE '$(OMIT_TARGETS)' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}'
	@printf "\nDefault target\n"
	@printf "\033[36m%s\033[0m" $(.DEFAULT_GOAL)
	@printf "\n\nMake Variables\n"
	@grep -h -E '^[0-9a-zA-Z_.-]+\s:=.*?## .*$$' $(MAKEFILE_LIST) || true | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}'