...
1# Copyright The OpenTelemetry Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15TOOLS_MOD_DIR := ./internal/tools
16
17ALL_DOCS := $(shell find . -name '*.md' -type f | sort)
18ALL_GO_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort)
19OTEL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(ALL_GO_MOD_DIRS))
20ALL_COVERAGE_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | grep -E -v '^./example|^$(TOOLS_MOD_DIR)' | sort)
21
22GO = go
23TIMEOUT = 60
24
25.DEFAULT_GOAL := precommit
26
27.PHONY: precommit ci
28precommit: generate dependabot-generate license-check misspell go-mod-tidy golangci-lint-fix test-default
29ci: generate dependabot-check license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage
30
31# Tools
32
33TOOLS = $(CURDIR)/.tools
34
35$(TOOLS):
36 @mkdir -p $@
37$(TOOLS)/%: | $(TOOLS)
38 cd $(TOOLS_MOD_DIR) && \
39 $(GO) build -o $@ $(PACKAGE)
40
41MULTIMOD = $(TOOLS)/multimod
42$(TOOLS)/multimod: PACKAGE=go.opentelemetry.io/build-tools/multimod
43
44SEMCONVGEN = $(TOOLS)/semconvgen
45$(TOOLS)/semconvgen: PACKAGE=go.opentelemetry.io/build-tools/semconvgen
46
47CROSSLINK = $(TOOLS)/crosslink
48$(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/build-tools/crosslink
49
50SEMCONVKIT = $(TOOLS)/semconvkit
51$(TOOLS)/semconvkit: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/semconvkit
52
53DBOTCONF = $(TOOLS)/dbotconf
54$(TOOLS)/dbotconf: PACKAGE=go.opentelemetry.io/build-tools/dbotconf
55
56GOLANGCI_LINT = $(TOOLS)/golangci-lint
57$(TOOLS)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint
58
59MISSPELL = $(TOOLS)/misspell
60$(TOOLS)/misspell: PACKAGE=github.com/client9/misspell/cmd/misspell
61
62GOCOVMERGE = $(TOOLS)/gocovmerge
63$(TOOLS)/gocovmerge: PACKAGE=github.com/wadey/gocovmerge
64
65STRINGER = $(TOOLS)/stringer
66$(TOOLS)/stringer: PACKAGE=golang.org/x/tools/cmd/stringer
67
68PORTO = $(TOOLS)/porto
69$(TOOLS)/porto: PACKAGE=github.com/jcchavezs/porto/cmd/porto
70
71GOJQ = $(TOOLS)/gojq
72$(TOOLS)/gojq: PACKAGE=github.com/itchyny/gojq/cmd/gojq
73
74GOTMPL = $(TOOLS)/gotmpl
75$(GOTMPL): PACKAGE=go.opentelemetry.io/build-tools/gotmpl
76
77GORELEASE = $(TOOLS)/gorelease
78$(GORELEASE): PACKAGE=golang.org/x/exp/cmd/gorelease
79
80GOVULNCHECK = $(TOOLS)/govulncheck
81$(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck
82
83.PHONY: tools
84tools: $(CROSSLINK) $(DBOTCONF) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
85
86# Virtualized python tools via docker
87
88# The directory where the virtual environment is created.
89VENVDIR := venv
90
91# The directory where the python tools are installed.
92PYTOOLS := $(VENVDIR)/bin
93
94# The pip executable in the virtual environment.
95PIP := $(PYTOOLS)/pip
96
97# The directory in the docker image where the current directory is mounted.
98WORKDIR := /workdir
99
100# The python image to use for the virtual environment.
101PYTHONIMAGE := python:3.11.3-slim-bullseye
102
103# Run the python image with the current directory mounted.
104DOCKERPY := docker run --rm -v "$(CURDIR):$(WORKDIR)" -w $(WORKDIR) $(PYTHONIMAGE)
105
106# Create a virtual environment for Python tools.
107$(PYTOOLS):
108# The `--upgrade` flag is needed to ensure that the virtual environment is
109# created with the latest pip version.
110 @$(DOCKERPY) bash -c "python3 -m venv $(VENVDIR) && $(PIP) install --upgrade pip"
111
112# Install python packages into the virtual environment.
113$(PYTOOLS)/%: | $(PYTOOLS)
114 @$(DOCKERPY) $(PIP) install -r requirements.txt
115
116CODESPELL = $(PYTOOLS)/codespell
117$(CODESPELL): PACKAGE=codespell
118
119# Generate
120
121.PHONY: generate
122generate: go-generate vanity-import-fix
123
124.PHONY: go-generate
125go-generate: $(OTEL_GO_MOD_DIRS:%=go-generate/%)
126go-generate/%: DIR=$*
127go-generate/%: | $(STRINGER) $(GOTMPL)
128 @echo "$(GO) generate $(DIR)/..." \
129 && cd $(DIR) \
130 && PATH="$(TOOLS):$${PATH}" $(GO) generate ./...
131
132.PHONY: vanity-import-fix
133vanity-import-fix: | $(PORTO)
134 @$(PORTO) --include-internal -w .
135
136# Generate go.work file for local development.
137.PHONY: go-work
138go-work: | $(CROSSLINK)
139 $(CROSSLINK) work --root=$(shell pwd)
140
141# Build
142
143.PHONY: build
144
145build: $(OTEL_GO_MOD_DIRS:%=build/%) $(OTEL_GO_MOD_DIRS:%=build-tests/%)
146build/%: DIR=$*
147build/%:
148 @echo "$(GO) build $(DIR)/..." \
149 && cd $(DIR) \
150 && $(GO) build ./...
151
152build-tests/%: DIR=$*
153build-tests/%:
154 @echo "$(GO) build tests $(DIR)/..." \
155 && cd $(DIR) \
156 && $(GO) list ./... \
157 | grep -v third_party \
158 | xargs $(GO) test -vet=off -run xxxxxMatchNothingxxxxx >/dev/null
159
160# Tests
161
162TEST_TARGETS := test-default test-bench test-short test-verbose test-race
163.PHONY: $(TEST_TARGETS) test
164test-default test-race: ARGS=-race
165test-bench: ARGS=-run=xxxxxMatchNothingxxxxx -test.benchtime=1ms -bench=.
166test-short: ARGS=-short
167test-verbose: ARGS=-v -race
168$(TEST_TARGETS): test
169test: $(OTEL_GO_MOD_DIRS:%=test/%)
170test/%: DIR=$*
171test/%:
172 @echo "$(GO) test -timeout $(TIMEOUT)s $(ARGS) $(DIR)/..." \
173 && cd $(DIR) \
174 && $(GO) list ./... \
175 | grep -v third_party \
176 | xargs $(GO) test -timeout $(TIMEOUT)s $(ARGS)
177
178COVERAGE_MODE = atomic
179COVERAGE_PROFILE = coverage.out
180.PHONY: test-coverage
181test-coverage: | $(GOCOVMERGE)
182 @set -e; \
183 printf "" > coverage.txt; \
184 for dir in $(ALL_COVERAGE_MOD_DIRS); do \
185 echo "$(GO) test -coverpkg=go.opentelemetry.io/otel/... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" $${dir}/..."; \
186 (cd "$${dir}" && \
187 $(GO) list ./... \
188 | grep -v third_party \
189 | grep -v 'semconv/v.*' \
190 | xargs $(GO) test -coverpkg=./... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" && \
191 $(GO) tool cover -html=coverage.out -o coverage.html); \
192 done; \
193 $(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt
194
195# Adding a directory will include all benchmarks in that direcotry if a filter is not specified.
196BENCHMARK_TARGETS := sdk/trace
197.PHONY: benchmark
198benchmark: $(BENCHMARK_TARGETS:%=benchmark/%)
199BENCHMARK_FILTER = .
200# You can override the filter for a particular directory by adding a rule here.
201benchmark/sdk/trace: BENCHMARK_FILTER = SpanWithAttributes_8/AlwaysSample
202benchmark/%:
203 @echo "$(GO) test -timeout $(TIMEOUT)s -run=xxxxxMatchNothingxxxxx -bench=$(BENCHMARK_FILTER) $*..." \
204 && cd $* \
205 $(foreach filter, $(BENCHMARK_FILTER), && $(GO) test -timeout $(TIMEOUT)s -run=xxxxxMatchNothingxxxxx -bench=$(filter))
206
207.PHONY: golangci-lint golangci-lint-fix
208golangci-lint-fix: ARGS=--fix
209golangci-lint-fix: golangci-lint
210golangci-lint: $(OTEL_GO_MOD_DIRS:%=golangci-lint/%)
211golangci-lint/%: DIR=$*
212golangci-lint/%: | $(GOLANGCI_LINT)
213 @echo 'golangci-lint $(if $(ARGS),$(ARGS) ,)$(DIR)' \
214 && cd $(DIR) \
215 && $(GOLANGCI_LINT) run --allow-serial-runners $(ARGS)
216
217.PHONY: crosslink
218crosslink: | $(CROSSLINK)
219 @echo "Updating intra-repository dependencies in all go modules" \
220 && $(CROSSLINK) --root=$(shell pwd) --prune
221
222.PHONY: go-mod-tidy
223go-mod-tidy: $(ALL_GO_MOD_DIRS:%=go-mod-tidy/%)
224go-mod-tidy/%: DIR=$*
225go-mod-tidy/%: | crosslink
226 @echo "$(GO) mod tidy in $(DIR)" \
227 && cd $(DIR) \
228 && $(GO) mod tidy -compat=1.20
229
230.PHONY: lint-modules
231lint-modules: go-mod-tidy
232
233.PHONY: lint
234lint: misspell lint-modules golangci-lint govulncheck
235
236.PHONY: vanity-import-check
237vanity-import-check: | $(PORTO)
238 @$(PORTO) --include-internal -l . || ( echo "(run: make vanity-import-fix)"; exit 1 )
239
240.PHONY: misspell
241misspell: | $(MISSPELL)
242 @$(MISSPELL) -w $(ALL_DOCS)
243
244.PHONY: govulncheck
245govulncheck: $(OTEL_GO_MOD_DIRS:%=govulncheck/%)
246govulncheck/%: DIR=$*
247govulncheck/%: | $(GOVULNCHECK)
248 @echo "govulncheck ./... in $(DIR)" \
249 && cd $(DIR) \
250 && $(GOVULNCHECK) ./...
251
252.PHONY: codespell
253codespell: | $(CODESPELL)
254 @$(DOCKERPY) $(CODESPELL)
255
256.PHONY: license-check
257license-check:
258 @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './.git/*' ) ; do \
259 awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \
260 done); \
261 if [ -n "$${licRes}" ]; then \
262 echo "license header checking failed:"; echo "$${licRes}"; \
263 exit 1; \
264 fi
265
266DEPENDABOT_CONFIG = .github/dependabot.yml
267.PHONY: dependabot-check
268dependabot-check: | $(DBOTCONF)
269 @$(DBOTCONF) verify $(DEPENDABOT_CONFIG) || ( echo "(run: make dependabot-generate)"; exit 1 )
270
271.PHONY: dependabot-generate
272dependabot-generate: | $(DBOTCONF)
273 @$(DBOTCONF) generate > $(DEPENDABOT_CONFIG)
274
275.PHONY: check-clean-work-tree
276check-clean-work-tree:
277 @if ! git diff --quiet; then \
278 echo; \
279 echo 'Working tree is not clean, did you forget to run "make precommit"?'; \
280 echo; \
281 git status; \
282 exit 1; \
283 fi
284
285SEMCONVPKG ?= "semconv/"
286.PHONY: semconv-generate
287semconv-generate: | $(SEMCONVGEN) $(SEMCONVKIT)
288 [ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry semantic-conventions tag"; exit 1 )
289 [ "$(OTEL_SEMCONV_REPO)" ] || ( echo "OTEL_SEMCONV_REPO unset: missing path to opentelemetry semantic-conventions repo"; exit 1 )
290 $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=span -p conventionType=trace -f trace.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
291 $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=attribute_group -p conventionType=trace -f attribute_group.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
292 $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=event -p conventionType=event -f event.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
293 $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=resource -p conventionType=resource -f resource.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
294 $(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)"
295
296.PHONY: gorelease
297gorelease: $(OTEL_GO_MOD_DIRS:%=gorelease/%)
298gorelease/%: DIR=$*
299gorelease/%:| $(GORELEASE)
300 @echo "gorelease in $(DIR):" \
301 && cd $(DIR) \
302 && $(GORELEASE) \
303 || echo ""
304
305.PHONY: prerelease
306prerelease: | $(MULTIMOD)
307 @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
308 $(MULTIMOD) verify && $(MULTIMOD) prerelease -m ${MODSET}
309
310COMMIT ?= "HEAD"
311.PHONY: add-tags
312add-tags: | $(MULTIMOD)
313 @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
314 $(MULTIMOD) verify && $(MULTIMOD) tag -m ${MODSET} -c ${COMMIT}
315
316.PHONY: lint-markdown
317lint-markdown:
318 docker run -v "$(CURDIR):$(WORKDIR)" docker://avtodev/markdown-lint:v1 -c $(WORKDIR)/.markdownlint.yaml $(WORKDIR)/**/*.md
View as plain text