123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- # +--------------------------------------------------------------+
- # | * * * moul.io/rules.mk |
- # +--------------------------------------------------------------+
- # | |
- # | ++ ______________________________________ |
- # | ++++ / \ |
- # | ++++ | | |
- # | ++++++++++ | https://moul.io/rules.mk is a set | |
- # | +++ | | of common Makefile rules that can | |
- # | ++ | | be configured from the Makefile | |
- # | + -== ==| | or with environment variables. | |
- # | ( <*> <*> | | |
- # | | | /| Manfred Touron | |
- # | | _) / | manfred.life | |
- # | | +++ / \______________________________________/ |
- # | \ =+ / |
- # | \ + |
- # | |\++++++ |
- # | | ++++ ||// |
- # | ___| |___ _||/__ __|
- # | / --- \ \| ||| __ _ ___ __ __/ /|
- # |/ | | \ \ / / ' \/ _ \/ // / / |
- # || | | | | | /_/_/_/\___/\_,_/_/ |
- # +--------------------------------------------------------------+
- .PHONY: _default_entrypoint
- _default_entrypoint: help
- ##
- ## Common helpers
- ##
- rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
- check-program = $(foreach exec,$(1),$(if $(shell PATH="$(PATH)" which $(exec)),,$(error "No $(exec) in PATH")))
- my-filter-out = $(foreach v,$(2),$(if $(findstring $(1),$(v)),,$(v)))
- novendor = $(call my-filter-out,vendor/,$(1))
- ##
- ## rules.mk
- ##
- ifneq ($(wildcard rules.mk),)
- .PHONY: rulesmk.bumpdeps
- rulesmk.bumpdeps:
- wget -O rules.mk https://raw.githubusercontent.com/moul/rules.mk/master/rules.mk
- BUMPDEPS_STEPS += rulesmk.bumpdeps
- endif
- ##
- ## Maintainer
- ##
- ifneq ($(wildcard .git/HEAD),)
- .PHONY: generate.authors
- generate.authors: AUTHORS
- AUTHORS: .git/
- echo "# This file lists all individuals having contributed content to the repository." > AUTHORS
- echo "# For how it is generated, see 'https://github.com/moul/rules.mk'" >> AUTHORS
- echo >> AUTHORS
- git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf >> AUTHORS
- GENERATE_STEPS += generate.authors
- endif
- ##
- ## Golang
- ##
- ifndef GOPKG
- ifneq ($(wildcard go.mod),)
- GOPKG = $(shell sed '/module/!d;s/^omdule\ //' go.mod)
- endif
- endif
- ifdef GOPKG
- GO ?= go
- GOPATH ?= $(HOME)/go
- GO_INSTALL_OPTS ?=
- GO_TEST_OPTS ?= -test.timeout=30s
- GOMOD_DIRS ?= $(sort $(call novendor,$(dir $(call rwildcard,*,*/go.mod go.mod))))
- GOCOVERAGE_FILE ?= ./coverage.txt
- GOTESTJSON_FILE ?= ./go-test.json
- GOBUILDLOG_FILE ?= ./go-build.log
- GOINSTALLLOG_FILE ?= ./go-install.log
- ifdef GOBINS
- .PHONY: go.install
- go.install:
- ifeq ($(CI),true)
- @rm -f /tmp/goinstall.log
- @set -e; for dir in $(GOBINS); do ( set -xe; \
- cd $$dir; \
- $(GO) install -v $(GO_INSTALL_OPTS) .; \
- ); done 2>&1 | tee $(GOINSTALLLOG_FILE)
- else
- @set -e; for dir in $(GOBINS); do ( set -xe; \
- cd $$dir; \
- $(GO) install $(GO_INSTALL_OPTS) .; \
- ); done
- endif
- INSTALL_STEPS += go.install
- .PHONY: go.release
- go.release:
- $(call check-program, goreleaser)
- goreleaser --snapshot --skip-publish --rm-dist
- @echo -n "Do you want to release? [y/N] " && read ans && \
- if [ $${ans:-N} = y ]; then set -xe; goreleaser --rm-dist; fi
- RELEASE_STEPS += go.release
- endif
- .PHONY: go.unittest
- go.unittest:
- ifeq ($(CI),true)
- @echo "mode: atomic" > /tmp/gocoverage
- @rm -f $(GOTESTJSON_FILE)
- @set -e; for dir in $(GOMOD_DIRS); do (set -e; (set -euf pipefail; \
- cd $$dir; \
- (($(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race -json && touch $@.ok) | tee -a $(GOTESTJSON_FILE) 3>&1 1>&2 2>&3 | tee -a $(GOBUILDLOG_FILE); \
- ); \
- rm $@.ok 2>/dev/null || exit 1; \
- if [ -f /tmp/profile.out ]; then \
- cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \
- rm -f /tmp/profile.out; \
- fi)); done
- @mv /tmp/gocoverage $(GOCOVERAGE_FILE)
- else
- @echo "mode: atomic" > /tmp/gocoverage
- @set -e; for dir in $(GOMOD_DIRS); do (set -e; (set -xe; \
- cd $$dir; \
- $(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race); \
- if [ -f /tmp/profile.out ]; then \
- cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \
- rm -f /tmp/profile.out; \
- fi); done
- @mv /tmp/gocoverage $(GOCOVERAGE_FILE)
- endif
- .PHONY: go.checkdoc
- go.checkdoc:
- go doc $(first $(GOMOD_DIRS))
- .PHONY: go.coverfunc
- go.coverfunc: go.unittest
- go tool cover -func=$(GOCOVERAGE_FILE) | grep -v .pb.go: | grep -v .pb.gw.go:
- .PHONY: go.lint
- go.lint:
- @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
- cd $$dir; \
- golangci-lint run --verbose ./...; \
- ); done
- .PHONY: go.tidy
- go.tidy:
- @# tidy dirs with go.mod files
- @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
- cd $$dir; \
- $(GO) mod tidy; \
- ); done
- .PHONY: go.depaware-update
- go.depaware-update: go.tidy
- @# gen depaware for bins
- @set -e; for dir in $(GOBINS); do ( set -xe; \
- cd $$dir; \
- $(GO) run github.com/tailscale/depaware --update .; \
- ); done
- @# tidy unused depaware deps if not in a tools_test.go file
- @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
- cd $$dir; \
- $(GO) mod tidy; \
- ); done
- .PHONY: go.depaware-check
- go.depaware-check: go.tidy
- @# gen depaware for bins
- @set -e; for dir in $(GOBINS); do ( set -xe; \
- cd $$dir; \
- $(GO) run github.com/tailscale/depaware --check .; \
- ); done
- .PHONY: go.build
- go.build:
- @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
- cd $$dir; \
- $(GO) build ./...; \
- ); done
- .PHONY: go.bump-deps
- go.bumpdeps:
- @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
- cd $$dir; \
- $(GO) get -u ./...; \
- ); done
- .PHONY: go.bump-deps
- go.fmt:
- @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
- cd $$dir; \
- $(GO) run golang.org/x/tools/cmd/goimports -w `go list -f '{{.Dir}}' ./...` \
- ); done
- VERIFY_STEPS += go.depaware-check
- BUILD_STEPS += go.build
- BUMPDEPS_STEPS += go.bumpdeps go.depaware-update
- TIDY_STEPS += go.tidy
- LINT_STEPS += go.lint
- UNITTEST_STEPS += go.unittest
- FMT_STEPS += go.fmt
- # FIXME: disabled, because currently slow
- # new rule that is manually run sometimes, i.e. `make pre-release` or `make maintenance`.
- # alternative: run it each time the go.mod is changed
- #GENERATE_STEPS += go.depaware-update
- endif
- ##
- ## Gitattributes
- ##
- ifneq ($(wildcard .gitattributes),)
- .PHONY: _linguist-ignored
- _linguist-kept:
- @git check-attr linguist-vendored $(shell git check-attr linguist-generated $(shell find . -type f | grep -v .git/) | grep unspecified | cut -d: -f1) | grep unspecified | cut -d: -f1 | sort
- .PHONY: _linguist-kept
- _linguist-ignored:
- @git check-attr linguist-vendored linguist-ignored `find . -not -path './.git/*' -type f` | grep '\ set$$' | cut -d: -f1 | sort -u
- endif
- ##
- ## Node
- ##
- ifndef NPM_PACKAGES
- ifneq ($(wildcard package.json),)
- NPM_PACKAGES = .
- endif
- endif
- ifdef NPM_PACKAGES
- .PHONY: npm.publish
- npm.publish:
- @echo -n "Do you want to npm publish? [y/N] " && read ans && \
- @if [ $${ans:-N} = y ]; then \
- set -e; for dir in $(NPM_PACKAGES); do ( set -xe; \
- cd $$dir; \
- npm publish --access=public; \
- ); done; \
- fi
- RELEASE_STEPS += npm.publish
- endif
- ##
- ## Docker
- ##
- docker_build = docker build \
- --build-arg VCS_REF=`git rev-parse --short HEAD` \
- --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
- --build-arg VERSION=`git describe --tags --always` \
- -t "$2" -f "$1" "$(dir $1)"
- ifndef DOCKERFILE_PATH
- DOCKERFILE_PATH = ./Dockerfile
- endif
- ifndef DOCKER_IMAGE
- ifneq ($(wildcard Dockerfile),)
- DOCKER_IMAGE = $(notdir $(PWD))
- endif
- endif
- ifdef DOCKER_IMAGE
- ifneq ($(DOCKER_IMAGE),none)
- .PHONY: docker.build
- docker.build:
- $(call check-program, docker)
- $(call docker_build,$(DOCKERFILE_PATH),$(DOCKER_IMAGE))
- BUILD_STEPS += docker.build
- endif
- endif
- ##
- ## Common
- ##
- TEST_STEPS += $(UNITTEST_STEPS)
- TEST_STEPS += $(LINT_STEPS)
- TEST_STEPS += $(TIDY_STEPS)
- ifneq ($(strip $(TEST_STEPS)),)
- .PHONY: test
- test: $(PRE_TEST_STEPS) $(TEST_STEPS)
- endif
- ifdef INSTALL_STEPS
- .PHONY: install
- install: $(PRE_INSTALL_STEPS) $(INSTALL_STEPS)
- endif
- ifdef UNITTEST_STEPS
- .PHONY: unittest
- unittest: $(PRE_UNITTEST_STEPS) $(UNITTEST_STEPS)
- endif
- ifdef LINT_STEPS
- .PHONY: lint
- lint: $(PRE_LINT_STEPS) $(FMT_STEPS) $(LINT_STEPS)
- endif
- ifdef TIDY_STEPS
- .PHONY: tidy
- tidy: $(PRE_TIDY_STEPS) $(TIDY_STEPS)
- endif
- ifdef BUILD_STEPS
- .PHONY: build
- build: $(PRE_BUILD_STEPS) $(BUILD_STEPS)
- endif
- ifdef VERIFY_STEPS
- .PHONY: verify
- verify: $(PRE_VERIFY_STEPS) $(VERIFY_STEPS)
- endif
- ifdef RELEASE_STEPS
- .PHONY: release
- release: $(PRE_RELEASE_STEPS) $(RELEASE_STEPS)
- endif
- ifdef BUMPDEPS_STEPS
- .PHONY: bumpdeps
- bumpdeps: $(PRE_BUMDEPS_STEPS) $(BUMPDEPS_STEPS)
- endif
- ifdef FMT_STEPS
- .PHONY: fmt
- fmt: $(PRE_FMT_STEPS) $(FMT_STEPS)
- endif
- ifdef GENERATE_STEPS
- .PHONY: generate
- generate: $(PRE_GENERATE_STEPS) $(GENERATE_STEPS)
- endif
- .PHONY: help
- help::
- @echo "General commands:"
- @[ "$(BUILD_STEPS)" != "" ] && echo " build" || true
- @[ "$(BUMPDEPS_STEPS)" != "" ] && echo " bumpdeps" || true
- @[ "$(FMT_STEPS)" != "" ] && echo " fmt" || true
- @[ "$(GENERATE_STEPS)" != "" ] && echo " generate" || true
- @[ "$(INSTALL_STEPS)" != "" ] && echo " install" || true
- @[ "$(LINT_STEPS)" != "" ] && echo " lint" || true
- @[ "$(RELEASE_STEPS)" != "" ] && echo " release" || true
- @[ "$(TEST_STEPS)" != "" ] && echo " test" || true
- @[ "$(TIDY_STEPS)" != "" ] && echo " tidy" || true
- @[ "$(UNITTEST_STEPS)" != "" ] && echo " unittest" || true
- @[ "$(VERIFY_STEPS)" != "" ] && echo " verify" || true
- @# FIXME: list other commands
- print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
|