go.sdls.io/sin@v0.0.9/Makefile (about) 1 # @ SUDOLESS SRL <contact@sudoless.org> 2 # This Source Code Form is subject to the 3 # terms of the Mozilla Public License, v. 4 # 2.0. If a copy of the MPL was not 5 # distributed with this file, You can 6 # obtain one at 7 # http://mozilla.org/MPL/2.0/. 8 9 THIS_MAKEFILE_VERSION = v0.1.7 10 THIS_MAKEFILE_UPDATE = master 11 THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) 12 THIS_MAKEFILE_URL := https://raw.githubusercontent.com/sudoless/make/$(THIS_MAKEFILE_UPDATE)/golang.mk 13 14 15 # PATH 16 export PATH := $(abspath bin/):${PATH} 17 18 # META 19 ifneq ("$(wildcard go.mod/)","") # check go.mod exists 20 PROJECT_MOD_NAME := $(shell go list -m -mod=readonly) 21 PROJECT_NAME := $(notdir $(PROJECT_MOD_NAME)) 22 endif 23 24 # META - FMT 25 FMT_MISC := \033[90;1m 26 FMT_INFO := \033[94;1m 27 FMT_OK := \033[92;1m 28 FMT_WARN := \033[33;1m 29 FMT_END := \033[0m 30 FMT_PRFX := $(FMT_MISC)=>$(FMT_END) 31 32 # GO 33 export CGO_ENABLED ?= 0 34 GO ?= GO111MODULE=on go 35 GO_TAGS ?= timetzdata 36 37 # OUTPUT 38 DIR_OUT := out 39 FILE_COV := $(DIR_OUT)/cover.out 40 41 # GIT 42 ifneq ("$(wildcard .git/)","") # check .git/ exists 43 GIT_TAG_HASH := $(shell git rev-list --abbrev-commit --tags --max-count=1) 44 GIT_TAG := $(shell git describe --abbrev=0 --tags ${GIT_TAG_HASH} 2>/dev/null || true) 45 GIT_VERSION := $(GIT_TAG) 46 GIT_LATEST_HASH := $(shell git rev-parse --short HEAD) 47 GIT_LATEST_COMMIT_DATE := $(shell git log -1 --format=%cd --date=format:"%Y%m%d") 48 GIT_CHANGES := $(shell git rev-list $(GIT_TAG)..HEAD --count) 49 50 ifneq ($(GIT_LATEST_HASH),$(GIT_TAG_HASH)) 51 GIT_VERSION := $(GIT_VERSION)-wip$(GIT_CHANGES).$(GIT_LATEST_HASH) 52 endif 53 ifeq ($(GIT_VERSION),) 54 GIT_VERSION := -new.$(GIT_LATEST_HASH).$(GIT_LATEST_COMMIT_DATE) 55 endif 56 ifneq ($(shell git status --porcelain),) 57 GIT_VERSION := $(GIT_VERSION)-dirty.$(GIT_LATEST_COMMIT_DATE).$$(whoami) 58 endif 59 endif 60 61 # BUILD 62 BUILD_HASH ?= $(GIT_LATEST_HASH) 63 BUILD_TIME ?= $$(date +%s) 64 BUILD_VERSION ?= $(GIT_VERSION) 65 66 # SOURCE 67 SOURCE_FILES?=$$(find . -name '*.go' | grep -v pb.go | grep -v vendor) 68 69 # DEV - EXTERNAL TOOLS 70 DEV_EXTERNAL_TOOLS=\ 71 github.com/golangci/golangci-lint/cmd/golangci-lint@v1.39.0 \ 72 github.com/securego/gosec/v2/cmd/gosec@v2.7.0 \ 73 github.com/client9/misspell/cmd/misspell@v0.3.4 \ 74 github.com/fzipp/gocyclo/cmd/gocyclo@v0.3.1 \ 75 github.com/jstemmer/go-junit-report@v0.9.1 \ 76 golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@v0.1.0 \ 77 mvdan.cc/gofumpt@v0.1.1 \ 78 gotest.tools/gotestsum@v1.6.4 79 80 # DOCKER 81 THIS_DOCKER_BUILD_FLAGS ?= 82 THIS_DOCKER_DIR ?= ./deployment/docker 83 THIS_DOCKER_FILE ?= $(THIS_DOCKER_DIR)/Dockerfile 84 THIS_DOCKER_TAG ?= $(BUILD_VERSION) 85 THIS_DOCKER_IMAGE ?= $(PROJECT_MOD_NAME)/$* 86 THIS_DOCKER_ARTIFACT ?= $(THIS_DOCKER_IMAGE):$(THIS_DOCKER_TAG) 87 88 89 all: clean align spelling check lint test 90 91 92 .PHONY: info 93 info: ## display project information 94 @printf "$(FMT_PRFX) printing info\n" 95 @printf "$(FMT_PRFX) project mod name $(FMT_INFO)$(PROJECT_MOD_NAME)$(FMT_END)\n" 96 @printf "$(FMT_PRFX) project name $(FMT_INFO)$(PROJECT_NAME)$(FMT_END)\n" 97 @printf "$(FMT_PRFX) makefile $(FMT_INFO)$(THIS_MAKEFILE)$(FMT_END)\n" 98 @printf "$(FMT_PRFX) makefile version $(FMT_INFO)$(THIS_MAKEFILE_VERSION)$(FMT_END)\n" 99 @printf "$(FMT_PRFX) build hash $(FMT_INFO)$(BUILD_HASH)$(FMT_END)\n" 100 @printf "$(FMT_PRFX) build current version $(FMT_INFO)$(BUILD_VERSION)$(FMT_END)\n" 101 @printf "$(FMT_PRFX) git tag commit $(FMT_INFO)$(GIT_TAG_HASH)$(FMT_END)\n" 102 @printf "$(FMT_PRFX) git tag $(FMT_INFO)$(GIT_TAG)$(FMT_END)\n" 103 @printf "$(FMT_PRFX) git version $(FMT_INFO)$(GIT_VERSION)$(FMT_END)\n" 104 @printf "$(FMT_PRFX) git latest commit $(FMT_INFO)$(GIT_LATEST_HASH)$(FMT_END)\n" 105 @printf "$(FMT_PRFX) git latest commit date $(FMT_INFO)$(GIT_LATEST_COMMIT_DATE)$(FMT_END)\n" 106 @printf "$(FMT_PRFX) git commit changes $(FMT_INFO)$(GIT_CHANGES)$(FMT_END)\n" 107 108 .PHONY: init 109 init: ## setup a barebones Go project 110 @mkdir -p cmd/ pkg/ docs/ scripts/ data/ deployment/ internal/ 111 @touch deployment/.netrc 112 @echo "deployment/.netrc\n**/.env.*" > .gitignore 113 114 .PHONY: info-version 115 info-version: ## prints the BUILD_VERSION and nothing else 116 @printf "$(BUILD_VERSION)" 117 118 .PHONY: run-% 119 run-%: build-% ## run the specified target 120 @printf "$(FMT_PRFX) running $(FMT_INFO)$*$(FMT_END) from $(FMT_INFO)$(DIR_OUT)/dist/$*_$$(go env GOOS)_$$(go env GOARCH)$(FMT_END)\n" 121 @$(DIR_OUT)/dist/$*_$$(go env GOOS)_$$(go env GOARCH) 122 123 .PHONY: build-% 124 build-%: APP_OUT ?= $*_$$(go env GOOS)_$$(go env GOARCH) 125 build-%: ## build a specific cmd/$(TARGET)/... into $(DIR_OUT)/dist/$(TARGET)... 126 @printf "$(FMT_PRFX) building $(FMT_INFO)$*$(FMT_END) version=$(FMT_INFO)$(BUILD_VERSION)$(FMT_END)\ 127 buildhash=$(FMT_INFO)$(BUILD_HASH)$(FMT_END)\n" 128 @printf "$(FMT_PRFX) using $(FMT_INFO)$$(go version)$(FMT_END)\n" 129 @$(GO) build -trimpath -tags "$(GO_TAGS)" \ 130 -ldflags="-w -s \ 131 -X main._serviceName=$* \ 132 -X main._version=$(BUILD_VERSION) \ 133 -X main._buildTime=$(BUILD_TIME) \ 134 -X main._buildHash=$(BUILD_HASH)" \ 135 -o $(DIR_OUT)/dist/$(APP_OUT) \ 136 ./cmd/$*/... 137 @printf "$(FMT_PRFX) built binary $(FMT_INFO)$(DIR_OUT)/dist/$(APP_OUT)$(FMT_END)\n" 138 139 .PHONY: install-% 140 install-%: APP_OUT ?= $*_$$(go env GOOS)_$$(go env GOARCH) 141 install-%: GOBIN ?= $(GOPATH)/bin 142 install-%: build-% ## install the built binary to $GOBIN 143 @printf "$(FMT_PRFX) installing $(FMT_INFO)$*$(FMT_END) ($(FMT_WARN)$(APP_OUT)$(FMT_END)) at $(FMT_INFO)$(GOBIN)/$*$(FMT_END)\n" 144 @cp $(DIR_OUT)/dist/$(APP_OUT) $(GOBIN)/$* 145 @printf "$(FMT_PRFX) $(FMT_OK)ok$(FMT_END) (which=$(FMT_INFO)$(shell which $*)$(FMT_END))\n" 146 147 .PHONY: clean 148 clean: ## remove build time generated files 149 @printf "$(FMT_PRFX) removing output directory\n" 150 @rm -rf $(DIR_OUT)/ 151 152 .PHONY: purge 153 purge: clean ## remove everything that could cause environment issues 154 @printf "$(FMT_PRFX) deleting system32\n" 155 $(GO) clean -cache 156 $(GO) clean -testcache 157 $(GO) clean -modcache 158 159 $(DIR_OUT): 160 @mkdir -p $(DIR_OUT) 161 162 .PHONY: test 163 test: export CGO_ENABLED=1 164 test: $(DIR_OUT) ## run unit tests 165 @printf "$(FMT_PRFX) running tests\n" 166 @gotestsum \ 167 --junitfile $(FILE_COV).xml \ 168 --format short -- \ 169 -race \ 170 -timeout=30s -parallel=20 -failfast \ 171 -covermode=atomic -coverpkg=./... -coverprofile=$(FILE_COV).txt \ 172 ./... 173 174 .PHONY: test-deps 175 test-deps: ## run tests with dependencies 176 @printf "$(FMT_PRFX) running all tests\n" 177 $(GO) test all 178 179 .PHONY: bench 180 bench: ## run benchmarks 181 @printf "$(FMT_PRFX) running benchmarks\n" 182 $(GO) test -exclude-dir=vendor -exclude-dir=.cache -bench=. -benchmem -benchtime=10s ./... 183 184 .PHONY: cover 185 cover: ## open coverage file in browser 186 @printf "$(FMT_PRFX) opening coverage file in browser\n" 187 $(GO) tool cover -html=$(FILE_COV).txt 188 189 .PHONY: tidy 190 tidy: ## tidy and verify go modules 191 @printf "$(FMT_PRFX) tidying go modules\n" 192 $(GO) mod tidy 193 $(GO) mod verify 194 195 .PHONY: download 196 download: ## download go modules 197 @printf "$(FMT_PRFX) downloading dependencies as modules\n" 198 @$(GO) mod $(GO_MOD) download -x 199 200 .PHONY: vendor 201 vendor: ## tidy, vendor and verify dependencies 202 @printf "$(FMT_PRFX) downloading and creating vendor dependencies\n" 203 $(GO) mod tidy -v 204 $(GO) mod vendor -v 205 $(GO) mod verify 206 207 .PHONY: updates 208 updates: ## display outdated direct dependencies 209 @printf "$(FMT_PRFX) checking for direct dependencies updates\n" 210 @$(GO) list -u -m -mod=readonly -json all | go-mod-outdated -direct 211 212 .PHONY: lint 213 lint: ## run golangci linter 214 @printf "$(FMT_PRFX) running golangci-lint\n" 215 @golangci-lint run -v --timeout 10m --skip-dirs=".cache/|vendor/|scripts/|docs/|deployment/" ./... 216 217 .PHONY: check 218 check: ## run cyclic, security, performance, etc checks 219 @printf "$(FMT_PRFX) running cyclic analysis\n" 220 @gocyclo -over 16 -ignore ".cache/|vendor/|scripts/|docs/|deployment/" . 221 @printf "$(FMT_PRFX) running static security analysis\n" 222 @gosec -tests -fmt=json -quiet -exclude-dir=vendor -exclude-dir=.cache -exclude-dir=scripts -exclude-dir=docs -exclude-dir=deployment ./... 223 224 .PHONY: align 225 align: ## align struct fields to use less memory 226 @printf "$(FMT_PRFX) checking struct field memory alignment\n" 227 @$(GO) list -f '{{.Dir}}' ./... | grep -v /vendor/ | \ 228 xargs fieldalignment ; if [[ $$? -eq 1 ]]; then \ 229 printf "$(FMT_PRFX) $(FMT_WARN)unaligned struct fields detected$(FMT_END), check above output\n"; \ 230 printf "$(FMT_PRFX) to auto-fix run $(FMT_INFO)make align-fix$(FMT_END)\n"; \ 231 fi 232 @printf "$(FMT_PRFX) $(FMT_OK)ok$(FMT_END)\n"; \ 233 234 .PHONY: align-fix 235 align-fix: ## autofix misaligned struct fields 236 @printf "$(FMT_PRFX) fixing struct field memory alignment\n" 237 @$(GO) list -f '{{.Dir}}' ./... | grep -v /vendor/ | xargs fieldalignment -fix || exit 0; 238 @printf "$(FMT_PRFX) aligned above files\n" 239 @printf "$(FMT_PRFX) re-running $(FMT_INFO)make align$(FMT_END) to check for stragglers\n" 240 @make align 241 242 .PHONY: fmt 243 fmt: ## format source files using gofumpt 244 @printf "$(FMT_PRFX) formatting go files\n" 245 @gofumpt -w $(SOURCE_FILES) 246 247 .PHONY: spelling 248 spelling: ## run misspell check 249 @printf "$(FMT_PRFX) checking for spelling errors\n" 250 @misspell -error pkg/ 251 @misspell -error cmd/ 252 253 .PHONY: dev-deps 254 dev-deps: ## pull developer/ci dependencies 255 @printf "$(FMT_PRFX) pulling development/CI dependencies\n" 256 @for tool in $(DEV_EXTERNAL_TOOLS) ; do \ 257 printf "$(FMT_PRFX) installing/updating: $(FMT_INFO)$$tool$(FMT_END)\n" ; \ 258 $(GO) install $$tool; \ 259 done 260 261 .PHONY: docker-list 262 docker-list: ## list docker images for the current project 263 @printf "$(FMT_PRF) listing images for $(FMT_INFO)$(PROJECT_NAME)$(FMT_END) project\n" 264 @docker images -f label=project=$(PROJECT_NAME) 265 266 .PHONY: docker-build-% 267 docker-build-%: ## build docker image 268 @printf "$(FMT_PRFX) building with docker $(FMT_INFO)$$(docker version -f 'server: {{.Server.Version}}, client: {{.Client.Version}}')$(FMT_END)\n" 269 @printf "$(FMT_PRFX) docker on host $(FMT_WARN)$(DOCKER_HOST)$(FMT_END)\n" 270 @printf "$(FMT_PRFX) docker file $(FMT_INFO)$(THIS_DOCKER_FILE)$(FMT_END)\n" 271 @printf "$(FMT_PRFX) docker artifact output $(FMT_INFO)$(THIS_DOCKER_ARTIFACT)$(FMT_END)\n" 272 @DOCKER_BUILDKIT=1 docker build $(THIS_DOCKER_BUILD_FLAGS) \ 273 --secret id=netrc,src=./deployment/.netrc \ 274 --build-arg APP_NAME=$* \ 275 --build-arg BUILD_VERSION=$(BUILD_VERSION) \ 276 --build-arg BUILD_HASH=$(BUILD_HASH) \ 277 -f $(THIS_DOCKER_FILE) -t $(THIS_DOCKER_ARTIFACT) \ 278 --label "project=$(PROJECT_NAME)" \ 279 --label "build_hash=$(BUILD_HASH)" \ 280 --label "build_time=$(BUILD_TIME)" \ 281 --label "build_machine=$$(whoami)@$$(hostname)" . 282 @printf "$(FMT_PRFX) docker artifact output $(FMT_INFO)$(THIS_DOCKER_ARTIFACT)$(FMT_END)\n" 283 @printf "$(FMT_PRFX) run $(FMT_INFO)docker tag $(THIS_DOCKER_ARTIFACT) ...$(FMT_END) to change name\n" 284 285 .PHONY: docker-tag-% 286 docker-tag-%: ## tags the last built docker image for the given package using its version and $IMAGE_BASE 287 @printf "$(FMT_PRFX) tagging $(FMT_INFO)$(THIS_DOCKER_ARTIFACT)$(FMT_END)\n" 288 @printf "$(FMT_PRFX) as $(FMT_INFO)$(IMAGE_BASE)/$*:$(THIS_DOCKER_TAG)$(FMT_END)\n" 289 @docker tag $(THIS_DOCKER_ARTIFACT) $(IMAGE_BASE)/$*:$(THIS_DOCKER_TAG) 290 291 .PHONY: docker-push-% 292 docker-push-%: ## pushes the last tagged docker image for the given package using its version and $IMAGE_BASE 293 @printf "$(FMT_PRFX) pushing $(FMT_INFO)$(IMAGE_BASE)/$*:$(THIS_DOCKER_TAG)$(FMT_END)\n" 294 @docker push $(IMAGE_BASE)/$*:$(THIS_DOCKER_TAG) 295 296 .PHONY: mk-update 297 mk-update: ## update this Makefile, use THIS_MAKEFILE_UPDATE=... to specify version 298 @printf "$(FMT_PRFX) updating this makefile from $(FMT_INFO)$(THIS_MAKEFILE_VERSION)$(FMT_END) to $(FMT_INFO)$(THIS_MAKEFILE_UPDATE)$(FMT_END)\n" 299 @curl -s $(THIS_MAKEFILE_URL) > $(THIS_MAKEFILE).new 300 @awk '/^#### CUSTOM/,0' Makefile | tail -n +2 >> $(THIS_MAKEFILE).new 301 @mv -f Makefile.new Makefile 302 303 .PHONY: help 304 help: 305 @grep -h -E '^[a-zA-Z_-]+%?:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 306 307 308 #### CUSTOM # Anything under the CUSTOM line is migrated by the mk-update command to the new Makefile version