Skip to content

Commit dbd50f4

Browse files
authored
Modernize makefile like server, split tools into their own module (#1215)
Long needed, should help stabilize some things. And make it easier to keep them in sync. I'm fairly sure adding this go-version info to the build path will solve a couple things: 1. Our fmt-thrashing around 1.19, and probably future fmt changes, because tools won't be able to "leak" across Go versions. 2. In-docker-container architecture conflicts (maybe only an issue in server?). Next up: switch to some of the better tools, like revive, and update them where possible.
1 parent 1be195b commit dbd50f4

File tree

9 files changed

+561
-85
lines changed

9 files changed

+561
-85
lines changed

.buildkite/pipeline.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ steps:
1010
docker: "*"
1111
command: "make unit_test"
1212
artifact_paths:
13-
- ".build/coverage/*.out"
13+
- ".build/*/coverage/*.out"
1414
plugins:
1515
- docker-compose#v3.0.0:
1616
run: unit-test
@@ -22,7 +22,7 @@ steps:
2222
docker: "*"
2323
command: "make integ_test_sticky_off"
2424
artifact_paths:
25-
- ".build/coverage/*.out"
25+
- ".build/*/coverage/*.out"
2626
retry:
2727
automatic:
2828
limit: 1
@@ -37,7 +37,7 @@ steps:
3737
docker: "*"
3838
command: "make integ_test_sticky_on"
3939
artifact_paths:
40-
- ".build/coverage/*.out"
40+
- ".build/*/coverage/*.out"
4141
retry:
4242
automatic:
4343
limit: 1
@@ -52,7 +52,7 @@ steps:
5252
docker: "*"
5353
command: "make integ_test_grpc"
5454
artifact_paths:
55-
- ".build/coverage/*.out"
55+
- ".build/*/coverage/*.out"
5656
retry:
5757
automatic:
5858
limit: 1

.buildkite/scripts/gocov.sh

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@
22

33
set -ex
44

5-
# fetch codecov reporting tool
6-
go get github.com/mattn/goveralls
7-
8-
# download cover files from all the tests
9-
mkdir -p .build/coverage
10-
buildkite-agent artifact download ".build/coverage/unit_test_cover.out" . --step ":golang: unit-test" --build "$BUILDKITE_BUILD_ID"
11-
buildkite-agent artifact download ".build/coverage/integ_test_sticky_off_cover.out" . --step ":golang: integration-test-sticky-off" --build "$BUILDKITE_BUILD_ID"
12-
buildkite-agent artifact download ".build/coverage/integ_test_sticky_on_cover.out" . --step ":golang: integration-test-sticky-on" --build "$BUILDKITE_BUILD_ID"
13-
buildkite-agent artifact download ".build/coverage/integ_test_grpc_cover.out" . --step ":golang: integration-test-grpc-adapter" --build "$BUILDKITE_BUILD_ID"
5+
buildkite-agent artifact download ".build/*/coverage/unit_test_cover.out" . --step ":golang: unit-test" --build "$BUILDKITE_BUILD_ID"
6+
buildkite-agent artifact download ".build/*/coverage/integ_test_sticky_off_cover.out" . --step ":golang: integration-test-sticky-off" --build "$BUILDKITE_BUILD_ID"
7+
buildkite-agent artifact download ".build/*/coverage/integ_test_sticky_on_cover.out" . --step ":golang: integration-test-sticky-on" --build "$BUILDKITE_BUILD_ID"
8+
buildkite-agent artifact download ".build/*/coverage/integ_test_grpc_cover.out" . --step ":golang: integration-test-grpc-adapter" --build "$BUILDKITE_BUILD_ID"
149

1510
echo "download complete"
1611

Makefile

Lines changed: 114 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -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
6872
TEST_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

144188
THRIFT_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)
209253
MAYBE_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).
254296
copyright: $(BIN)/copyright ## update copyright headers
255297
$(BIN)/copyright
256-
@touch $(BUILD)/copyright
298+
$Q touch $(BUILD)/copyright
257299

258300
.PHONY: staticcheck
259301
staticcheck: $(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
270312
clean:
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
297340
deps: ## 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
301344
deps-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
307350
help:
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
325368
test: unit_test integ_test_sticky_off integ_test_sticky_on ## run all tests (requires a running cadence instance)
326369

327370
unit_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

338381
integ_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

342385
integ_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

346389
integ_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+
357405
cover: $(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";

docker/buildkite/docker-compose-local.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ services:
137137
- -e
138138
- -c
139139
- |
140-
make .build/coverage/cover.out
140+
make coverage_report
141141
environment:
142142
- "GO111MODULE=on"
143143
volumes:

0 commit comments

Comments
 (0)