1# Copyright 2018 The Prometheus Authors 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13 14 15# A common Makefile that includes rules to be reused in different prometheus projects. 16# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! 17 18# Example usage : 19# Create the main Makefile in the root project directory. 20# include Makefile.common 21# customTarget: 22# @echo ">> Running customTarget" 23# 24 25# Ensure GOBIN is not set during build so that promu is installed to the correct path 26unexport GOBIN 27 28GO ?= go 29GOFMT ?= $(GO)fmt 30FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) 31GOOPTS ?= 32GOHOSTOS ?= $(shell $(GO) env GOHOSTOS) 33GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH) 34 35GO_VERSION ?= $(shell $(GO) version) 36GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) 37PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') 38 39GOVENDOR := 40GO111MODULE := 41ifeq (, $(PRE_GO_111)) 42 ifneq (,$(wildcard go.mod)) 43 # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). 44 GO111MODULE := on 45 46 ifneq (,$(wildcard vendor)) 47 # Always use the local vendor/ directory to satisfy the dependencies. 48 GOOPTS := $(GOOPTS) -mod=vendor 49 endif 50 endif 51else 52 ifneq (,$(wildcard go.mod)) 53 ifneq (,$(wildcard vendor)) 54$(warning This repository requires Go >= 1.11 because of Go modules) 55$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') 56 endif 57 else 58 # This repository isn't using Go modules (yet). 59 GOVENDOR := $(FIRST_GOPATH)/bin/govendor 60 endif 61endif 62PROMU := $(FIRST_GOPATH)/bin/promu 63pkgs = ./... 64 65ifeq (arm, $(GOHOSTARCH)) 66 GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM) 67 GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM) 68else 69 GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH) 70endif 71 72GOTEST := $(GO) test 73GOTEST_DIR := 74ifneq ($(CIRCLE_JOB),) 75ifneq ($(shell which gotestsum),) 76 GOTEST_DIR := test-results 77 GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- 78endif 79endif 80 81PROMU_VERSION ?= 0.12.0 82PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz 83 84GOLANGCI_LINT := 85GOLANGCI_LINT_OPTS ?= 86GOLANGCI_LINT_VERSION ?= v1.42.0 87# golangci-lint only supports linux, darwin and windows platforms on i386/amd64. 88# windows isn't included here because of the path separator being different. 89ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) 90 ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) 91 # If we're in CI and there is an Actions file, that means the linter 92 # is being run in Actions, so we don't need to run it here. 93 ifeq (,$(CIRCLE_JOB)) 94 GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint 95 else ifeq (,$(wildcard .github/workflows/golangci-lint.yml)) 96 GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint 97 endif 98 endif 99endif 100 101PREFIX ?= $(shell pwd) 102BIN_DIR ?= $(shell pwd) 103DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) 104DOCKERFILE_PATH ?= ./Dockerfile 105DOCKERBUILD_CONTEXT ?= ./ 106DOCKER_REPO ?= prom 107 108DOCKER_ARCHS ?= amd64 109 110BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) 111PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) 112TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) 113 114ifeq ($(GOHOSTARCH),amd64) 115 ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows)) 116 # Only supported on amd64 117 test-flags := -race 118 endif 119endif 120 121# This rule is used to forward a target like "build" to "common-build". This 122# allows a new "build" target to be defined in a Makefile which includes this 123# one and override "common-build" without override warnings. 124%: common-% ; 125 126.PHONY: common-all 127common-all: precheck style check_license lint yamllint unused build test 128 129.PHONY: common-style 130common-style: 131 @echo ">> checking code style" 132 @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ 133 if [ -n "$${fmtRes}" ]; then \ 134 echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ 135 echo "Please ensure you are using $$($(GO) version) for formatting code."; \ 136 exit 1; \ 137 fi 138 139.PHONY: common-check_license 140common-check_license: 141 @echo ">> checking license header" 142 @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ 143 awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ 144 done); \ 145 if [ -n "$${licRes}" ]; then \ 146 echo "license header checking failed:"; echo "$${licRes}"; \ 147 exit 1; \ 148 fi 149 150.PHONY: common-deps 151common-deps: 152 @echo ">> getting dependencies" 153ifdef GO111MODULE 154 GO111MODULE=$(GO111MODULE) $(GO) mod download 155else 156 $(GO) get $(GOOPTS) -t ./... 157endif 158 159.PHONY: update-go-deps 160update-go-deps: 161 @echo ">> updating Go dependencies" 162 @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ 163 $(GO) get $$m; \ 164 done 165 GO111MODULE=$(GO111MODULE) $(GO) mod tidy 166ifneq (,$(wildcard vendor)) 167 GO111MODULE=$(GO111MODULE) $(GO) mod vendor 168endif 169 170.PHONY: common-test-short 171common-test-short: $(GOTEST_DIR) 172 @echo ">> running short tests" 173 GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs) 174 175.PHONY: common-test 176common-test: $(GOTEST_DIR) 177 @echo ">> running all tests" 178 GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) 179 180$(GOTEST_DIR): 181 @mkdir -p $@ 182 183.PHONY: common-format 184common-format: 185 @echo ">> formatting code" 186 GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs) 187 188.PHONY: common-vet 189common-vet: 190 @echo ">> vetting code" 191 GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) 192 193.PHONY: common-lint 194common-lint: $(GOLANGCI_LINT) 195ifdef GOLANGCI_LINT 196 @echo ">> running golangci-lint" 197ifdef GO111MODULE 198# 'go list' needs to be executed before staticcheck to prepopulate the modules cache. 199# Otherwise staticcheck might fail randomly for some reason not yet explained. 200 GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null 201 GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) 202else 203 $(GOLANGCI_LINT) run $(pkgs) 204endif 205endif 206 207.PHONY: common-yamllint 208common-yamllint: 209 @echo ">> running yamllint on all YAML files in the repository" 210ifeq (, $(shell which yamllint)) 211 @echo "yamllint not installed so skipping" 212else 213 yamllint . 214endif 215 216# For backward-compatibility. 217.PHONY: common-staticcheck 218common-staticcheck: lint 219 220.PHONY: common-unused 221common-unused: $(GOVENDOR) 222ifdef GOVENDOR 223 @echo ">> running check for unused packages" 224 @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' 225else 226ifdef GO111MODULE 227 @echo ">> running check for unused/missing packages in go.mod" 228 GO111MODULE=$(GO111MODULE) $(GO) mod tidy 229ifeq (,$(wildcard vendor)) 230 @git diff --exit-code -- go.sum go.mod 231else 232 @echo ">> running check for unused packages in vendor/" 233 GO111MODULE=$(GO111MODULE) $(GO) mod vendor 234 @git diff --exit-code -- go.sum go.mod vendor/ 235endif 236endif 237endif 238 239.PHONY: common-build 240common-build: promu 241 @echo ">> building binaries" 242 GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) 243 244.PHONY: common-tarball 245common-tarball: promu 246 @echo ">> building release tarball" 247 $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) 248 249.PHONY: common-docker $(BUILD_DOCKER_ARCHS) 250common-docker: $(BUILD_DOCKER_ARCHS) 251$(BUILD_DOCKER_ARCHS): common-docker-%: 252 docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \ 253 -f $(DOCKERFILE_PATH) \ 254 --build-arg ARCH="$*" \ 255 --build-arg OS="linux" \ 256 $(DOCKERBUILD_CONTEXT) 257 258.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS) 259common-docker-publish: $(PUBLISH_DOCKER_ARCHS) 260$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: 261 docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" 262 263DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION))) 264.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS) 265common-docker-tag-latest: $(TAG_DOCKER_ARCHS) 266$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: 267 docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" 268 docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" 269 270.PHONY: common-docker-manifest 271common-docker-manifest: 272 DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG)) 273 DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" 274 275.PHONY: promu 276promu: $(PROMU) 277 278$(PROMU): 279 $(eval PROMU_TMP := $(shell mktemp -d)) 280 curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP) 281 mkdir -p $(FIRST_GOPATH)/bin 282 cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu 283 rm -r $(PROMU_TMP) 284 285.PHONY: proto 286proto: 287 @echo ">> generating code from proto files" 288 @./scripts/genproto.sh 289 290ifdef GOLANGCI_LINT 291$(GOLANGCI_LINT): 292 mkdir -p $(FIRST_GOPATH)/bin 293 curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh \ 294 | sed -e '/install -d/d' \ 295 | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) 296endif 297 298ifdef GOVENDOR 299.PHONY: $(GOVENDOR) 300$(GOVENDOR): 301 GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor 302endif 303 304.PHONY: precheck 305precheck:: 306 307define PRECHECK_COMMAND_template = 308precheck:: $(1)_precheck 309 310PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) 311.PHONY: $(1)_precheck 312$(1)_precheck: 313 @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ 314 echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ 315 exit 1; \ 316 fi 317endef 318