-
Notifications
You must be signed in to change notification settings - Fork 42
/
Makefile
286 lines (243 loc) · 12.6 KB
/
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# Copyright 2021 Tetrate
# Licensed under the Apache License, Version 2.0 (the "License")
#
# This script uses automatic variables (ex $<, $(@D)) and substitution references $(<:.signed=)
# Please see GNU make's documentation if unfamiliar: https://www.gnu.org/software/make/manual/html_node/
.PHONY: test build e2e dist clean format lint check site
# Include versions of tools we build on-demand
include Tools.mk
# This should be driven by automation and result in N.N.N, not vN.N.N
VERSION ?= dev
# This selects the goroot to use in the following priority order:
# 1. ${GOROOT} - Ex actions/setup-go
# 2. ${GOROOT_1_17_X64} - Ex GitHub Actions runner
# 3. $(go env GOROOT) - Implicit from the go binary in the path
#
# There may be multiple GOROOT variables, so pick the one matching go.mod.
go_release := $(shell sed -ne 's/^go //gp' go.mod)
# https://github.com/actions/runner/blob/master/src/Runner.Common/Constants.cs
github_runner_arch := $(if $(findstring $(shell uname -m),x86_64),X64,ARM64)
github_goroot_name := GOROOT_$(subst .,_,$(go_release))_$(github_runner_arch)
github_goroot_val := $(value $(github_goroot_name))
goroot_path := $(shell go env GOROOT 2>/dev/null)
goroot := $(firstword $(GOROOT) $(github_goroot_val) $(goroot_path))
ifndef goroot
$(error could not determine GOROOT)
endif
# Ensure POSIX-style GOROOT even in Windows, to support PATH updates in bash.
ifdef COMSPEC
goroot := $(shell cygpath $(goroot))
endif
# We must ensure `go` executes with GOROOT and PATH variables exported:
# * GOROOT ensures versions don't conflict with /usr/local/go or c:\Go
# * PATH ensures tools like golint can fork and execute the correct go binary.
#
# We may be using a very old version of Make (ex. 3.81 on macOS). This means we
# can't re-set GOROOT or PATH via 'export' or use '.ONESHELL' to persist
# variables across lines. Hence, we set variables on one-line.
go := export PATH="$(goroot)/bin:$${PATH}" && export GOROOT="$(goroot)" && go
# Set variables corresponding to the selected goroot and the current host.
goarch := $(shell $(go) env GOARCH)
goexe := $(shell $(go) env GOEXE)
goos := $(shell $(go) env GOOS)
# Build the path to the func-e binary for the current runtime (goos,goarch)
current_binary_path := build/func-e_$(goos)_$(goarch)
current_binary := $(current_binary_path)/func-e$(goexe)
# ANSI escape codes. f_ means foreground, b_ background.
# See https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
b_black := $(shell printf "\33[40m")
f_white := $(shell printf "\33[97m")
f_gray := $(shell printf "\33[37m")
f_dark_gray := $(shell printf "\33[90m")
f_bright_magenta := $(shell printf "\33[95m")
b_bright_magenta := $(shell printf "\33[105m")
ansi_reset := $(shell printf "\33[0m")
ansi_func_e := $(b_black)$(f_white)func-$(b_bright_magenta)e$(ansi_reset)
ansi_format_dark := $(f_gray)$(f_bright_magenta)%-10s$(ansi_reset) $(f_dark_gray)%s$(ansi_reset)\n
ansi_format_bright := $(f_white)$(f_bright_magenta)%-10s$(ansi_reset) $(f_white)$(b_bright_magenta)%s$(ansi_reset)\n
# This formats help statements in ANSI colors. To hide a target from help, don't comment it with a trailing '##'.
help: ## Describe how to use each target
@printf "$(ansi_func_e)$(f_white)\n"
@awk 'BEGIN {FS = ":.*?## "} /^[0-9a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "$(ansi_format_dark)", $$1, $$2}' $(MAKEFILE_LIST)
build: $(current_binary) ## Build the func-e binary
test: ## Run all unit tests
@printf "$(ansi_format_dark)" test "running unit tests"
@$(go) test $(main_packages)
@printf "$(ansi_format_bright)" test "ok"
# replace spaces with commas
coverpkg = $(main_packages: =,)
coverage: ## Generate test coverage
@printf "$(ansi_format_dark)" coverage "running unit tests with coverage"
@$(go) test -coverprofile=coverage.txt -covermode=atomic --coverpkg=$(coverpkg) $(main_packages)
@$(go) tool cover -func coverage.txt
@printf "$(ansi_format_bright)" coverage "ok"
# Tests run one at a time, in verbose mode, so that failures are easy to diagnose.
# Note: -failfast helps as it stops at the first error. However, it is not a cacheable flag, so runs won't cache.
export E2E_FUNC_E_PATH ?= $(current_binary_path)
e2e: $(E2E_FUNC_E_PATH)/func-e$(goexe) ## Run all end-to-end tests
@printf "$(ansi_format_dark)" e2e "running end-to-end tests"
@$(go) test -parallel 1 -v -failfast ./e2e
@printf "$(ansi_format_bright)" e2e "ok"
linux_platforms := linux_amd64 linux_arm64
non_windows_platforms := darwin_amd64 darwin_arm64 $(linux_platforms)
# TODO: arm64 on Windows https://github.com/envoyproxy/envoy/issues/17572
windows_platforms := windows_amd64
# Make 3.81 doesn't support '**' globbing: Set explicitly instead of recursion.
all_sources := $(wildcard *.go */*.go */*/*.go */*/*/*.go */*/*/*.go */*/*/*/*.go)
all_testdata := $(wildcard testdata/* */testdata/* */*/testdata/* */*/*/testdata/*)
all_testutil := $(wildcard internal/test/* internal/test/*/* internal/test/*/*/*)
# main_sources compose the binary, so exclude tests, test utilities and linters
main_sources := $(wildcard $(filter-out %_test.go $(all_testdata) $(all_testutil) $(wildcard lint/*), $(all_sources)))
# main_packages collect the unique main source directories (sort will dedupe).
# Paths need to all start with ./, so we do that manually vs foreach which strips it.
main_packages := $(sort $(foreach f,$(dir $(main_sources)),$(if $(findstring ./,$(f)),./,./$(f))))
build/func-e_%/func-e: $(main_sources)
$(call go-build,$@,$<)
dist/func-e_$(VERSION)_%.tar.gz: build/func-e_%/func-e
@printf "$(ansi_format_dark)" tar.gz "tarring $@"
@mkdir -p $(@D)
@tar -C $(<D) -cpzf $@ $(<F)
@printf "$(ansi_format_bright)" tar.gz "ok"
build/func-e_%/func-e.exe: $(main_sources)
ifeq ($(OS),Windows_NT)
$(call go-build,$@,$<)
endif
dist/func-e_$(VERSION)_%.zip: build/func-e_%/func-e.exe.signed
@printf "$(ansi_format_dark)" zip "zipping $@"
@mkdir -p $(@D)
@zip -qj $@ $(<:.signed=)
@printf "$(ansi_format_bright)" zip "ok"
# Default to a dummy version, which is always lower than a real release
nfpm_version=v$(VERSION:dev=0.0.1)
# It is not precise to put the func-e binary here, but it is easier because the arch pattern matches
# whereas in RPM it won't.
# Note: we are only generating this because the file isn't parameterized.
# See https://github.com/goreleaser/nfpm/issues/362
build/func-e_linux_%/nfpm.yaml: packaging/nfpm/nfpm.yaml build/func-e_linux_%/func-e
@mkdir -p $(@D)
@sed -e 's/amd64/$(*)/g' -e 's/v0.0.1/$(nfpm_version)/g' $< > $@
# We can't use a pattern (%) rule because in RPM amd64 -> x86_64, arm64 -> aarch64
rpm_x86_64 := dist/func-e_$(VERSION)_linux_x86_64.rpm
rpm_aarch64 := dist/func-e_$(VERSION)_linux_aarch64.rpm
rpms := $(rpm_x86_64) $(rpm_aarch64)
man_page := packaging/nfpm/func-e.8
$(rpm_x86_64): build/func-e_linux_amd64/nfpm.yaml $(man_page)
$(call nfpm-pkg,$<,"rpm",$@)
$(rpm_aarch64): build/func-e_linux_arm64/nfpm.yaml $(man_page)
$(call nfpm-pkg,$<,"rpm",$@)
# Debian architectures map goarch for amd64 and arm64
dist/func-e_$(VERSION)_linux_%.deb: build/func-e_linux_%/nfpm.yaml $(man_page)
$(call nfpm-pkg,$<,"deb",$@)
# msi-arch is a macro so we can detect it based on the file naming convention
msi-arch = $(if $(findstring amd64,$1),x64,arm64)
# Default to a dummy version, which is always lower than a real release
msi_version := $(VERSION:dev=0.0.1)
# This builds the Windows installer (MSI) using platform-dependent WIX commands.
dist/func-e_$(VERSION)_%.msi: build/func-e_%/func-e.exe.signed
ifeq ($(OS),Windows_NT) # Windows 10 etc use https://wixtoolset.org
@printf "$(ansi_format_dark)" msi "building $@"
@mkdir -p $(@D)
@candle -nologo -arch $(call msi-arch,$@) -dVersion=$(msi_version) -dBin=$(<:.signed=) packaging/msi/func-e.wxs
@light -nologo func-e.wixobj -o $@ -spdb
@rm func-e.wixobj
$(call codesign,$@)
@printf "$(ansi_format_bright)" msi "ok"
endif
# Archives are tar.gz, except in the case of Windows, which uses zip.
non_windows_archives := $(non_windows_platforms:%=dist/func-e_$(VERSION)_%.tar.gz)
windows_archives := $(windows_platforms:%=dist/func-e_$(VERSION)_%.zip) $(windows_platforms:%=dist/func-e_$(VERSION)_%.msi)
archives := $(non_windows_platforms:%=dist/func-e_$(VERSION)_%.tar.gz) $(windows_platforms:%=dist/func-e_$(VERSION)_%.zip)
checksums := dist/func-e_$(VERSION)_checksums.txt
# Darwin doesn't have sha256sum. See https://github.com/actions/virtual-environments/issues/90
sha256sum := $(if $(findstring darwin,$(goos)),shasum -a 256,sha256sum)
$(checksums): $(non_windows_archives) $(if $(findstring Windows_NT,$(OS)),$(windows_archives),)
@printf "$(ansi_format_dark)" sha256sum "generating $@"
@$(sha256sum) $^ > $@
@printf "$(ansi_format_bright)" sha256sum "ok"
# dist generates the assets that attach to a release
# Ex. https://github.com/tetratelabs/func-e/releases/tag/v$(VERSION)
dist: $(non_windows_archives) $(if $(findstring Windows_NT,$(OS)),$(windows_archives),) $(checksums) ## Generate release assets
clean: ## Ensure a clean build
@printf "$(ansi_format_dark)" clean "deleting temporary files"
@rm -rf dist build coverage.txt
@$(go) clean -testcache
@printf "$(ansi_format_bright)" clean "ok"
# format is a PHONY target, so always runs. This allows skipping when sources didn't change.
build/format: go.mod $(all_sources)
@$(go) mod tidy
@$(go) run $(licenser) apply -r "Tetrate"
@$(go)fmt -s -w $(all_sources)
@# Workaround inconsistent goimports grouping with awk until golang/go#20818 or incu6us/goimports-reviser#50
@for f in $(all_sources); do \
awk '/^import \($$/,/^\)$$/{if($$0=="")next}{print}' $$f > /tmp/fmt; \
mv /tmp/fmt $$f; \
done
@# -local ensures consistent ordering of our module in imports
@$(go) run $(goimports) -local $$(sed -ne 's/^module //gp' go.mod) -w $(all_sources)
@mkdir -p $(@D) && touch $@
format:
@printf "$(ansi_format_dark)" format "formatting project files"
@$(MAKE) build/format
@printf "$(ansi_format_bright)" format "ok"
# lint is a PHONY target, so always runs. This allows skipping when sources didn't change.
build/lint: .golangci.yml $(all_sources)
@$(go) run $(golangci_lint) run --timeout 5m --config $< ./...
@$(go) test ./lint/...
@mkdir -p $(@D) && touch $@
lint:
@printf "$(ansi_format_dark)" lint "Running linters"
@$(MAKE) build/lint
@printf "$(ansi_format_bright)" lint "ok"
# CI blocks merge until this passes. If this fails, run "make check" locally and commit the difference.
# This formats code before running lint, as it is annoying to tell people to format first!
check: ## Verify contents of last commit
@$(MAKE) lint
@$(MAKE) format
@# Make sure the check-in is clean
@if [ ! -z "`git status -s`" ]; then \
echo "The following differences will fail CI until committed:"; \
git diff --exit-code; \
fi
site: ## Serve website content
@git submodule update
@cd site && $(go) run $(hugo) server --minify --disableFastRender --baseURL localhost:1313 --cleanDestinationDir -D
# this makes a marker file ending in .signed to avoid repeatedly calling codesign
%.signed: %
$(call codesign,$<)
@touch $@
# define macros for multi-platform builds. these parse the filename being built
go-arch = $(if $(findstring amd64,$1),amd64,arm64)
go-os = $(if $(findstring .exe,$1),windows,$(if $(findstring linux,$1),linux,darwin))
define go-build
@printf "$(ansi_format_dark)" build "building $1"
@# $(go:go=) removes the trailing 'go', so we can insert cross-build variables
@$(go:go=) CGO_ENABLED=0 GOOS=$(call go-os,$1) GOARCH=$(call go-arch,$1) go build \
-ldflags "-s -w -X main.version=$(VERSION)" \
-o $1 $2
@printf "$(ansi_format_bright)" build "ok"
endef
define nfpm-pkg
@printf "$(ansi_format_dark)" nfpm "packaging $3"
@mkdir -p $(dir $3)
@$(go) run $(nfpm) pkg -f $1 --packager $2 --target $3
@printf "$(ansi_format_bright)" nfpm "ok"
endef
# This requires osslsigncode package (apt or brew) or latest windows release from mtrojnar/osslsigncode
#
# Default is self-signed while production should be a Digicert signing key
#
# Ex.
# ```bash
# keytool -genkey -alias func-e -storetype PKCS12 -keyalg RSA -keysize 2048 -storepass func-e-bunch \
# -keystore func-e.p12 -dname "O=func-e,CN=func-e.io" -validity 3650
# ```
WINDOWS_CODESIGN_P12 ?= packaging/msi/func-e.p12
WINDOWS_CODESIGN_PASSWORD ?= func-e-bunch
define codesign
@printf "$(ansi_format_dark)" codesign "signing $1"
@osslsigncode sign -h sha256 -pkcs12 ${WINDOWS_CODESIGN_P12} -pass "${WINDOWS_CODESIGN_PASSWORD}" \
-n "func-e makes running Envoy® easy" -i https://func-e.io -t http://timestamp.digicert.com \
$(if $(findstring msi,$(1)),-add-msi-dse) -in $1 -out $1-signed
@mv $1-signed $1
@printf "$(ansi_format_bright)" codesign "ok"
endef