@@ -18,10 +18,14 @@ default: help
1818# - Test your changes with `make -d ...`! It should be reasonable!
1919
2020# temporary build products and book-keeping targets that are always good to / safe to clean.
21- BUILD := .build
22- # less-than-temporary build products, e.g. tools.
23- # usually unnecessary to clean, and may require downloads to restore, so this folder is not automatically cleaned.
24- BIN := .bin
21+ #
22+ # the go version is embedded in the path, so changing Go's version or arch triggers rebuilds.
23+ # other things can be added if necessary, but hopefully only go's formatting behavior matters?
24+ # converts: "go version go1.19.5 darwin/arm64" -> "go1.19.5_darwin_arm64"
25+ BUILD := .build/$(shell go version | cut -d' ' -f3- | sed 's/[^a-zA-Z0-9.]/_/g')
26+ # tools that can be easily re-built on demand, and may be sensitive to dependency or go versions.
27+ # currently this covers all needs. if not, consider STABLE_BIN like github.com/uber/cadence has.
28+ BIN := $(BUILD ) /bin
2529
2630# current (when committed) version of Go used in CI, and ideally also our docker images.
2731# this generally does not matter, but can impact goimports or formatting output.
@@ -45,14 +49,14 @@ endif
4549# recipes and any other prerequisites are defined only once, further below.
4650# ====================================
4751
48- # all bins depend on: $(BUILD)/lint
49- # note that vars that do not yet exist are empty, so any prerequisites defined below are ineffective here.
52+ # note that vars that do not yet exist are empty, so stick to BUILD/BIN and probably nothing else.
5053$(BUILD ) /lint : $(BUILD ) /fmt $(BUILD ) /dummy # lint will fail if fmt or dummy fails, so run them first
5154$(BUILD ) /dummy : $(BUILD ) /fmt # do a build after fmt-ing
5255$(BUILD ) /fmt : $(BUILD ) /copyright # formatting must occur only after all other go-file-modifications are done
5356$(BUILD ) /copyright : $(BUILD ) /codegen # must add copyright to generated code
5457$(BUILD ) /codegen : $(BUILD ) /thrift # thrift is currently the only codegen, but this way it's easier to extend
55- $(BUILD ) /thrift :
58+ $(BUILD ) /thrift : $(BUILD ) /go_mod_check
59+ $(BUILD ) /go_mod_check : | $(BUILD ) $(BIN )
5660
5761# ====================================
5862# helper vars
@@ -67,6 +71,30 @@ BIN_PATH := PATH="$(abspath $(BIN)):$$PATH"
6771# default test args, easy to override
6872TEST_ARG ?= -v -race
6973
74+ # set a V=1 env var for verbose output. V=0 (or unset) disables.
75+ # this is used to make two verbose flags:
76+ # - $Q, to replace ALL @ use, so CI can be reliably verbose
77+ # - $(verbose), to forward verbosity flags to commands via `$(if $(verbose),-v)` or similar
78+ #
79+ # SHELL='bash -x' is useful too, but can be more confusing to understand.
80+ V ?= 0
81+ ifneq (0,$(V ) )
82+ verbose := 1
83+ Q :=
84+ else
85+ verbose :=
86+ Q := @
87+ endif
88+
89+ # and enforce ^ that rule: grep the makefile for line-starting @ use, error if any exist.
90+ # limit to one match because multiple look too weird.
91+ _BAD_AT_USE =$(shell grep -n -m1 '^\s* @' $(MAKEFILE_LIST ) )
92+ ifneq (,$(_BAD_AT_USE ) )
93+ $(warning Makefile cannot use @ to silence commands, use $$Q instead :)
94+ $(warning found on line $(_BAD_AT_USE))
95+ $(error fix that line and try again)
96+ endif
97+
7098# automatically gather all source files that currently exist.
7199# works by ignoring everything in the parens (and does not descend into matching folders) due to `-prune`,
72100# and everything else goes to the other side of the `-o` branch, which is `-print`ed.
@@ -96,33 +124,49 @@ LINT_SRC := $(filter-out %_test.go ./.gen/% ./mock% ./tools.go ./internal/compat
96124# $(BIN) targets
97125# ====================================
98126
127+ # builds a go-gettable tool, versioned by internal/tools/go.mod, and installs it into
128+ # the build folder, named the same as the last portion of the URL or the second arg.
129+ define go_build_tool
130+ $Q echo "building $(or $(2 ) , $(notdir $(1 ) ) ) from internal/tools/go.mod..."
131+ $Q go build -mod=readonly -modfile=internal/tools/go.mod -o $(BIN ) /$(or $(2 ) , $(notdir $(1 ) ) ) $(1 )
132+ endef
133+
99134# utility target.
100135# use as an order-only prerequisite for targets that do not implicitly create these folders.
101136$(BIN ) $(BUILD ) :
102- @mkdir -p $@
137+ $Q mkdir -p $@
138+
139+ $(BIN ) /thriftrw : internal/tools/go.mod
140+ $(call go_build_tool,go.uber.org/thriftrw)
103141
104- $(BIN ) /thriftrw: go.mod
105- go build -mod=readonly -o $@ go.uber.org/thriftrw
142+ $(BIN ) /thriftrw-plugin-yarpc : internal/tools/ go.mod
143+ $( call go_build_tool, go.uber.org/yarpc/encoding/thrift/ thriftrw-plugin-yarpc)
106144
107- $(BIN ) /thriftrw-plugin-yarpc : go.mod
108- go build -mod=readonly -o $@ go.uber. org/yarpc/encoding/thrift/thriftrw-plugin-yarpc
145+ $(BIN ) /golint : internal/tools/ go.mod
146+ $( call go_build_tool,golang. org/x/lint/golint)
109147
110- $(BIN ) /golint : go.mod
111- go build -mod=readonly -o $@ golang.org/x/lint/golint
148+ $(BIN ) /staticcheck : internal/tools/ go.mod
149+ $( call go_build_tool,honnef.co/go/tools/cmd/staticcheck)
112150
113- $(BIN ) /staticcheck : go.mod
114- go build -mod=readonly -o $@ honnef.co/go/tools/cmd/staticcheck
151+ $(BIN ) /errcheck : internal/tools/ go.mod
152+ $( call go_build_tool,github.com/kisielk/errcheck)
115153
116- $(BIN ) /errcheck : go.mod
117- go build -mod=readonly -o $@ github.com/kisielk/errcheck
154+ $(BIN ) /goveralls : internal/tools/ go.mod
155+ $( call go_build_tool, github.com/mattn/goveralls)
118156
119157# copyright header checker/writer. only requires stdlib, so no other dependencies are needed.
120- $(BIN ) /copyright : internal/cmd/tools/copyright/licensegen.go go.mod
158+ $(BIN ) /copyright : internal/cmd/tools/copyright/licensegen.go
121159 go build -mod=readonly -o $@ ./internal/cmd/tools/copyright/licensegen.go
122160
123161# dummy binary that ensures most/all packages build, without needing to wait for tests.
124- $(BUILD ) /dummy : $(ALL_SRC ) go.mod
125- go build -o $@ internal/cmd/dummy/dummy.go
162+ $(BUILD ) /dummy : $(ALL_SRC ) $(BUILD ) /go_mod_check
163+ go build -mod=readonly -o $@ internal/cmd/dummy/dummy.go
164+
165+ # ensures mod files are in sync for critical packages
166+ $(BUILD ) /go_mod_check : go.mod internal/tools/go.mod
167+ $Q # ensure both have the same apache/thrift replacement
168+ $Q ./scripts/check-gomod-version.sh go.uber.org/thriftrw $(if $(verbose ) ,-v)
169+ $Q touch $@
126170
127171# ====================================
128172# Codegen targets
@@ -139,35 +183,35 @@ endef
139183
140184# codegen is done when thrift is done (it's just a naming-convenience, $(BUILD)/thrift would be fine too)
141185$(BUILD ) /codegen : $(BUILD ) /thrift | $(BUILD )
142- @ touch $@
186+ $Q touch $@
143187
144188THRIFT_FILES := idls/thrift/cadence.thrift idls/thrift/shadower.thrift
145189# book-keeping targets to build. one per thrift file.
146- # idls/thrift/thing.thrift -> .build/thing.thrift
190+ # idls/thrift/thing.thrift -> .build/go_version/ thing.thrift
147191# the reverse is done in the recipe.
148- THRIFT_GEN := $(subst idls/thrift/,.build/ ,$(THRIFT_FILES ) )
192+ THRIFT_GEN := $(subst idls/thrift, $( BUILD ) ,$(THRIFT_FILES ) )
149193
150194# dummy targets to detect when the idls submodule does not exist, to provide a better error message
151195$(THRIFT_FILES ) :
152196 $(call ensure_idl_submodule)
153197
154198# thrift is done when all sub-thrifts are done.
155- $(BUILD ) /thrift : $(THRIFT_GEN ) | $( BUILD )
156- @ touch $@
199+ $(BUILD ) /thrift : $(THRIFT_GEN )
200+ $Q touch $@
157201
158202# how to generate each thrift book-keeping file.
159203#
160204# note that each generated file depends on ALL thrift files - this is necessary because they can import each other.
161205# ideally this would --no-recurse like the server does, but currently that produces a new output file, and parallel
162206# compiling appears to work fine. seems likely it only risks rare flaky builds.
163- $(THRIFT_GEN ) : $(THRIFT_FILES ) $(BIN ) /thriftrw $(BIN ) /thriftrw-plugin-yarpc | $( BUILD )
164- @ echo ' thriftrw for $(subst .build/ ,idls/thrift/ ,$@)...'
165- @ $(BIN_PATH ) $(BIN ) /thriftrw \
207+ $(THRIFT_GEN ) : $(THRIFT_FILES ) $(BIN ) /thriftrw $(BIN ) /thriftrw-plugin-yarpc
208+ $Q echo ' thriftrw for $(subst $(BUILD) ,idls/thrift,$@)...'
209+ $Q $(BIN_PATH ) $(BIN ) /thriftrw \
166210 --plugin=yarpc \
167211 --pkg-prefix=$(PROJECT_ROOT ) /.gen/go \
168212 --out=.gen/go \
169- $(subst .build/ ,idls/thrift/ ,$@ )
170- @ touch $@
213+ $(subst $( BUILD ) ,idls/thrift,$@ )
214+ $Q touch $@
171215
172216# ====================================
173217# other intermediates
@@ -190,7 +234,7 @@ endef
190234# TODO: replace this with revive, like the server.
191235# keep in sync with `lint`
192236$(BUILD ) /lint : $(BIN ) /golint $(ALL_SRC )
193- @ $(foreach pkg, \
237+ $Q $(foreach pkg, \
194238 $(sort $(dir $(LINT_SRC ) ) ) , \
195239 $(call lint_if_present,$(filter $(wildcard $(pkg ) * .go) ,$(LINT_SRC ) ) ) || ERR=1; \
196240 ) test -z " $$ ERR" ; touch $@ ; exit $$ ERR
@@ -209,20 +253,18 @@ $(BUILD)/lint: $(BIN)/golint $(ALL_SRC)
209253MAYBE_TOUCH_COPYRIGHT =
210254
211255# TODO: switch to goimports, so we can pin the version
212- $(BUILD ) /fmt : $(ALL_SRC ) | $( BUILD )
213- @ echo " gofmt..."
214- @ # use FRESH_ALL_SRC so it won't miss any generated files produced earlier
215- @ gofmt -w $(ALL_SRC )
216- @ # ideally, mimic server: $(BIN)/goimports -local "go.uber.org/cadence" -w $(FRESH_ALL_SRC)
217- @ touch $@
218- @ $(MAYBE_TOUCH_COPYRIGHT )
219-
220- $(BUILD ) /copyright : $(ALL_SRC ) $(BIN ) /copyright | $( BUILD )
256+ $(BUILD ) /fmt : $(ALL_SRC )
257+ $Q echo " gofmt..."
258+ $Q # use FRESH_ALL_SRC so it won't miss any generated files produced earlier
259+ $Q gofmt -w $(ALL_SRC )
260+ $Q # ideally, mimic server: $(BIN)/goimports -local "go.uber.org/cadence" -w $(FRESH_ALL_SRC)
261+ $Q touch $@
262+ $Q $(MAYBE_TOUCH_COPYRIGHT )
263+
264+ $(BUILD ) /copyright : $(ALL_SRC ) $(BIN ) /copyright
221265 $(BIN ) /copyright --verifyOnly
222- @$(eval MAYBE_TOUCH_COPYRIGHT=touch $@ )
223- @touch $@
224-
225- $(BUILD ) /dummy : $(ALL_SRC ) go.mod
266+ $Q $(eval MAYBE_TOUCH_COPYRIGHT=touch $@ )
267+ $Q touch $@
226268
227269# ====================================
228270# developer-oriented targets
@@ -239,8 +281,8 @@ build: $(BUILD)/dummy ## ensure all packages build
239281# useful to actually re-run to get output again, as the intermediate will not be run unless necessary.
240282# dummy is used only because it occurs before $(BUILD)/lint, fmt would likely be sufficient too.
241283# keep in sync with `$(BUILD)/lint`
242- lint : $(BUILD ) /dummy # # (re)run golint
243- @ $(foreach pkg, \
284+ lint : $(BUILD ) /dummy $( BIN ) /golint # # (re)run golint
285+ $Q $(foreach pkg, \
244286 $(sort $(dir $(LINT_SRC ) ) ) , \
245287 $(call lint_if_present,$(filter $(wildcard $(pkg ) * .go) ,$(LINT_SRC ) ) ) || ERR=1; \
246288 ) test -z " $$ ERR" ; touch $(BUILD ) /lint; exit $$ ERR
@@ -253,7 +295,7 @@ fmt: $(BUILD)/fmt ## run gofmt
253295# not identical to the intermediate target, but does provide the same codegen (or more).
254296copyright : $(BIN ) /copyright # # update copyright headers
255297 $(BIN ) /copyright
256- @ touch $(BUILD ) /copyright
298+ $Q touch $(BUILD ) /copyright
257299
258300.PHONY : staticcheck
259301staticcheck : $(BIN ) /staticcheck $(BUILD ) /fmt # # (re)run staticcheck
@@ -268,9 +310,10 @@ all: $(BUILD)/lint ## refresh codegen, lint, and ensure the dummy binary builds,
268310
269311.PHONY : clean
270312clean :
271- rm -Rf $(BUILD ) .gen
272- @# remove old things (no longer in use). this can be removed "eventually", when we feel like they're unlikely to exist.
273- rm -Rf .bins dummy
313+ $Q # intentionally not using $(BUILD) as that covers only a single version
314+ rm -Rf .build .gen
315+ $Q # remove old things (no longer in use). this can be removed "eventually", when we feel like they're unlikely to exist.
316+ rm -Rf .bin
274317
275318# broken up into multiple += so I can interleave comments.
276319# this all becomes a single line of output.
@@ -295,20 +338,20 @@ JQ_DEPS_ONLY_DIRECT = | select(has("Indirect") | not)
295338
296339.PHONY : deps
297340deps : # # Check for dependency updates, for things that are directly imported
298- @ make --no-print-directory DEPS_FILTER=' $(JQ_DEPS_ONLY_DIRECT)' deps-all
341+ $Q make --no-print-directory DEPS_FILTER=' $(JQ_DEPS_ONLY_DIRECT)' deps-all
299342
300343.PHONY : deps-all
301344deps-all : # # Check for all dependency updates
302- @ go list -u -m -json all \
345+ $Q go list -u -m -json all \
303346 | $(JQ_DEPS_AGE ) \
304347 | sort -n
305348
306349.PHONY : help
307350help :
308- @ # print help first, so it's visible
309- @ printf " \033[36m%-20s\033[0m %s\n" ' help' ' Prints a help message showing any specially-commented targets'
310- @ # then everything matching "target: ## magic comments"
311- @ cat $(MAKEFILE_LIST ) | grep -e " ^[a-zA-Z_\-]*:.* ## .*" | awk ' BEGIN {FS = ":.*? ## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' | sort
351+ $Q # print help first, so it's visible
352+ $Q printf " \033[36m%-20s\033[0m %s\n" ' help' ' Prints a help message showing any specially-commented targets'
353+ $Q # then everything matching "target: ## magic comments"
354+ $Q cat $(MAKEFILE_LIST ) | grep -e " ^[a-zA-Z_\-]*:.* ## .*" | awk ' BEGIN {FS = ":.*? ## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' | sort
312355
313356# v==================== not yet cleaned up =======================v
314357
@@ -325,9 +368,9 @@ UT_DIRS := $(filter-out $(INTEG_TEST_ROOT)%, $(sort $(dir $(filter %_test.go,$(A
325368test : unit_test integ_test_sticky_off integ_test_sticky_on # # run all tests (requires a running cadence instance)
326369
327370unit_test : $(ALL_SRC ) # # run all unit tests
328- @ mkdir -p $(COVER_ROOT )
329- @ echo " mode: atomic" > $(UT_COVER_FILE )
330- @ failed=0; \
371+ $Q mkdir -p $(COVER_ROOT )
372+ $Q echo " mode: atomic" > $(UT_COVER_FILE )
373+ $Q failed=0; \
331374 for dir in $( UT_DIRS) ; do \
332375 mkdir -p $(COVER_ROOT ) /" $$ dir" ; \
333376 go test " $$ dir" $(TEST_ARG ) -coverprofile=$(COVER_ROOT ) /" $$ dir" /cover.out || failed=1; \
@@ -336,26 +379,31 @@ unit_test: $(ALL_SRC) ## run all unit tests
336379 exit $$ failed
337380
338381integ_test_sticky_off : $(ALL_SRC )
339- @ mkdir -p $(COVER_ROOT )
382+ $Q mkdir -p $(COVER_ROOT )
340383 STICKY_OFF=true go test $(TEST_ARG ) ./test -coverprofile=$(INTEG_STICKY_OFF_COVER_FILE ) -coverpkg=./...
341384
342385integ_test_sticky_on : $(ALL_SRC )
343- @ mkdir -p $(COVER_ROOT )
386+ $Q mkdir -p $(COVER_ROOT )
344387 STICKY_OFF=false go test $(TEST_ARG ) ./test -coverprofile=$(INTEG_STICKY_ON_COVER_FILE ) -coverpkg=./...
345388
346389integ_test_grpc : $(ALL_SRC )
347- @ mkdir -p $(COVER_ROOT )
390+ $Q mkdir -p $(COVER_ROOT )
348391 STICKY_OFF=false go test $(TEST_ARG ) ./test -coverprofile=$(INTEG_GRPC_COVER_FILE ) -coverpkg=./...
349392
393+ # intermediate product, ci needs a stable output, so use coverage_report.
394+ # running this target requires coverage files to have already been created, e.g. run ^ the above by hand, which happens in ci.
350395$(COVER_ROOT ) /cover.out : $(UT_COVER_FILE ) $(INTEG_STICKY_OFF_COVER_FILE ) $(INTEG_STICKY_ON_COVER_FILE ) $(INTEG_GRPC_COVER_FILE )
351- @ echo " mode: atomic" > $(COVER_ROOT ) /cover.out
396+ $Q echo " mode: atomic" > $(COVER_ROOT ) /cover.out
352397 cat $(UT_COVER_FILE ) | grep -v " mode: atomic" | grep -v " .gen" >> $(COVER_ROOT ) /cover.out
353398 cat $(INTEG_STICKY_OFF_COVER_FILE ) | grep -v " mode: atomic" | grep -v " .gen" >> $(COVER_ROOT ) /cover.out
354399 cat $(INTEG_STICKY_ON_COVER_FILE ) | grep -v " mode: atomic" | grep -v " .gen" >> $(COVER_ROOT ) /cover.out
355400 cat $(INTEG_GRPC_COVER_FILE ) | grep -v " mode: atomic" | grep -v " .gen" >> $(COVER_ROOT ) /cover.out
356401
402+ coverage_report : $(COVER_ROOT ) /cover.out
403+ cp $< $@
404+
357405cover : $(COVER_ROOT ) /cover.out
358406 go tool cover -html=$(COVER_ROOT ) /cover.out;
359407
360- cover_ci : $(COVER_ROOT ) /cover.out
361- goveralls -coverprofile=$(COVER_ROOT ) /cover.out -service=buildkite || echo -e " \x1b[31mCoveralls failed\x1b[m" ;
408+ cover_ci : $(COVER_ROOT ) /cover.out $( BIN ) /goveralls
409+ $( BIN ) / goveralls -coverprofile=$(COVER_ROOT ) /cover.out -service=buildkite || echo -e " \x1b[31mCoveralls failed\x1b[m" ;
0 commit comments