Makefile raw

   1  # Copyright The OpenTelemetry Authors
   2  # SPDX-License-Identifier: Apache-2.0
   3  
   4  TOOLS_MOD_DIR := ./internal/tools
   5  
   6  ALL_DOCS := $(shell find . -name '*.md' -type f | sort)
   7  ALL_GO_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort)
   8  OTEL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(ALL_GO_MOD_DIRS))
   9  ALL_COVERAGE_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | grep -E -v '^./example|^$(TOOLS_MOD_DIR)' | sort)
  10  
  11  GO = go
  12  TIMEOUT = 60
  13  
  14  # User to run as in docker images.
  15  DOCKER_USER=$(shell id -u):$(shell id -g)
  16  DEPENDENCIES_DOCKERFILE=./dependencies.Dockerfile
  17  
  18  .DEFAULT_GOAL := precommit
  19  
  20  .PHONY: precommit ci
  21  precommit: generate toolchain-check license-check misspell go-mod-tidy golangci-lint-fix verify-readmes verify-mods test-default
  22  ci: generate toolchain-check license-check lint vanity-import-check verify-readmes verify-mods build test-default check-clean-work-tree test-coverage
  23  
  24  # Tools
  25  
  26  TOOLS = $(CURDIR)/.tools
  27  
  28  $(TOOLS):
  29  	@mkdir -p $@
  30  $(TOOLS)/%: $(TOOLS_MOD_DIR)/go.mod | $(TOOLS)
  31  	cd $(TOOLS_MOD_DIR) && \
  32  	$(GO) build -o $@ $(PACKAGE)
  33  
  34  MULTIMOD = $(TOOLS)/multimod
  35  $(TOOLS)/multimod: PACKAGE=go.opentelemetry.io/build-tools/multimod
  36  
  37  CROSSLINK = $(TOOLS)/crosslink
  38  $(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/build-tools/crosslink
  39  
  40  SEMCONVKIT = $(TOOLS)/semconvkit
  41  $(TOOLS)/semconvkit: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/semconvkit
  42  
  43  VERIFYREADMES = $(TOOLS)/verifyreadmes
  44  $(TOOLS)/verifyreadmes: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/verifyreadmes
  45  
  46  GOLANGCI_LINT = $(TOOLS)/golangci-lint
  47  $(TOOLS)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/v2/cmd/golangci-lint
  48  
  49  MISSPELL = $(TOOLS)/misspell
  50  $(TOOLS)/misspell: PACKAGE=github.com/client9/misspell/cmd/misspell
  51  
  52  GOCOVMERGE = $(TOOLS)/gocovmerge
  53  $(TOOLS)/gocovmerge: PACKAGE=github.com/wadey/gocovmerge
  54  
  55  STRINGER = $(TOOLS)/stringer
  56  $(TOOLS)/stringer: PACKAGE=golang.org/x/tools/cmd/stringer
  57  
  58  PORTO = $(TOOLS)/porto
  59  $(TOOLS)/porto: PACKAGE=github.com/jcchavezs/porto/cmd/porto
  60  
  61  GOTMPL = $(TOOLS)/gotmpl
  62  $(GOTMPL): PACKAGE=go.opentelemetry.io/build-tools/gotmpl
  63  
  64  GORELEASE = $(TOOLS)/gorelease
  65  $(GORELEASE): PACKAGE=golang.org/x/exp/cmd/gorelease
  66  
  67  GOVULNCHECK = $(TOOLS)/govulncheck
  68  $(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck
  69  
  70  .PHONY: tools
  71  tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(VERIFYREADMES) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
  72  
  73  # Virtualized python tools via docker
  74  
  75  # The directory where the virtual environment is created.
  76  VENVDIR := venv
  77  
  78  # The directory where the python tools are installed.
  79  PYTOOLS := $(VENVDIR)/bin
  80  
  81  # The pip executable in the virtual environment.
  82  PIP := $(PYTOOLS)/pip
  83  
  84  # The directory in the docker image where the current directory is mounted.
  85  WORKDIR := /workdir
  86  
  87  # The python image to use for the virtual environment.
  88  PYTHONIMAGE := $(shell awk '$$4=="python" {print $$2}' $(DEPENDENCIES_DOCKERFILE))
  89  
  90  # Run the python image with the current directory mounted.
  91  DOCKERPY := docker run --rm -u $(DOCKER_USER) -v "$(CURDIR):$(WORKDIR)" -w $(WORKDIR) $(PYTHONIMAGE)
  92  
  93  # Create a virtual environment for Python tools.
  94  $(PYTOOLS):
  95  # The `--upgrade` flag is needed to ensure that the virtual environment is
  96  # created with the latest pip version.
  97  	@$(DOCKERPY) bash -c "python3 -m venv $(VENVDIR) && $(PIP) install --upgrade --cache-dir=$(WORKDIR)/.cache/pip pip"
  98  
  99  # Install python packages into the virtual environment.
 100  $(PYTOOLS)/%: $(PYTOOLS)
 101  	@$(DOCKERPY) $(PIP) install --cache-dir=$(WORKDIR)/.cache/pip -r requirements.txt
 102  
 103  CODESPELL = $(PYTOOLS)/codespell
 104  $(CODESPELL): PACKAGE=codespell
 105  
 106  # Generate
 107  
 108  .PHONY: generate
 109  generate: go-generate vanity-import-fix
 110  
 111  .PHONY: go-generate
 112  go-generate: $(OTEL_GO_MOD_DIRS:%=go-generate/%)
 113  go-generate/%: DIR=$*
 114  go-generate/%: $(STRINGER) $(GOTMPL)
 115  	@echo "$(GO) generate $(DIR)/..." \
 116  		&& cd $(DIR) \
 117  		&& PATH="$(TOOLS):$${PATH}" $(GO) generate ./...
 118  
 119  .PHONY: vanity-import-fix
 120  vanity-import-fix: $(PORTO)
 121  	@$(PORTO) --include-internal -w .
 122  
 123  # Generate go.work file for local development.
 124  .PHONY: go-work
 125  go-work: $(CROSSLINK)
 126  	$(CROSSLINK) work --root=$(shell pwd) --go=1.22.7
 127  
 128  # Build
 129  
 130  .PHONY: build
 131  
 132  build: $(OTEL_GO_MOD_DIRS:%=build/%) $(OTEL_GO_MOD_DIRS:%=build-tests/%)
 133  build/%: DIR=$*
 134  build/%:
 135  	@echo "$(GO) build $(DIR)/..." \
 136  		&& cd $(DIR) \
 137  		&& $(GO) build ./...
 138  
 139  build-tests/%: DIR=$*
 140  build-tests/%:
 141  	@echo "$(GO) build tests $(DIR)/..." \
 142  		&& cd $(DIR) \
 143  		&& $(GO) list ./... \
 144  		| grep -v third_party \
 145  		| xargs $(GO) test -vet=off -run xxxxxMatchNothingxxxxx >/dev/null
 146  
 147  # Tests
 148  
 149  TEST_TARGETS := test-default test-bench test-short test-verbose test-race test-concurrent-safe
 150  .PHONY: $(TEST_TARGETS) test
 151  test-default test-race: ARGS=-race
 152  test-bench:   ARGS=-run=xxxxxMatchNothingxxxxx -test.benchtime=1ms -bench=.
 153  test-short:   ARGS=-short
 154  test-verbose: ARGS=-v -race
 155  test-concurrent-safe: ARGS=-run=ConcurrentSafe -count=100 -race
 156  test-concurrent-safe: TIMEOUT=120
 157  $(TEST_TARGETS): test
 158  test: $(OTEL_GO_MOD_DIRS:%=test/%)
 159  test/%: DIR=$*
 160  test/%:
 161  	@echo "$(GO) test -timeout $(TIMEOUT)s $(ARGS) $(DIR)/..." \
 162  		&& cd $(DIR) \
 163  		&& $(GO) list ./... \
 164  		| grep -v third_party \
 165  		| xargs $(GO) test -timeout $(TIMEOUT)s $(ARGS)
 166  
 167  COVERAGE_MODE    = atomic
 168  COVERAGE_PROFILE = coverage.out
 169  .PHONY: test-coverage
 170  test-coverage: $(GOCOVMERGE)
 171  	@set -e; \
 172  	printf "" > coverage.txt; \
 173  	for dir in $(ALL_COVERAGE_MOD_DIRS); do \
 174  	  echo "$(GO) test -coverpkg=go.opentelemetry.io/otel/... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" $${dir}/..."; \
 175  	  (cd "$${dir}" && \
 176  	    $(GO) list ./... \
 177  	    | grep -v third_party \
 178  	    | grep -v 'semconv/v.*' \
 179  	    | xargs $(GO) test -coverpkg=./... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" && \
 180  	  $(GO) tool cover -html=coverage.out -o coverage.html); \
 181  	done; \
 182  	$(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt
 183  
 184  .PHONY: benchmark
 185  benchmark: $(OTEL_GO_MOD_DIRS:%=benchmark/%)
 186  benchmark/%:
 187  	@echo "$(GO) test -run=xxxxxMatchNothingxxxxx -bench=. $*..." \
 188  		&& cd $* \
 189  		&& $(GO) list ./... \
 190  		| grep -v third_party \
 191  		| xargs $(GO) test -run=xxxxxMatchNothingxxxxx -bench=.
 192  
 193  .PHONY: golangci-lint golangci-lint-fix
 194  golangci-lint-fix: ARGS=--fix
 195  golangci-lint-fix: golangci-lint
 196  golangci-lint: $(OTEL_GO_MOD_DIRS:%=golangci-lint/%)
 197  golangci-lint/%: DIR=$*
 198  golangci-lint/%: $(GOLANGCI_LINT)
 199  	@echo 'golangci-lint $(if $(ARGS),$(ARGS) ,)$(DIR)' \
 200  		&& cd $(DIR) \
 201  		&& $(GOLANGCI_LINT) run --allow-serial-runners $(ARGS)
 202  
 203  .PHONY: crosslink
 204  crosslink: $(CROSSLINK)
 205  	@echo "Updating intra-repository dependencies in all go modules" \
 206  		&& $(CROSSLINK) --root=$(shell pwd) --prune
 207  
 208  .PHONY: go-mod-tidy
 209  go-mod-tidy: $(ALL_GO_MOD_DIRS:%=go-mod-tidy/%)
 210  go-mod-tidy/%: DIR=$*
 211  go-mod-tidy/%: crosslink
 212  	@echo "$(GO) mod tidy in $(DIR)" \
 213  		&& cd $(DIR) \
 214  		&& $(GO) mod tidy -compat=1.21
 215  
 216  .PHONY: lint
 217  lint: misspell go-mod-tidy golangci-lint govulncheck
 218  
 219  .PHONY: vanity-import-check
 220  vanity-import-check: $(PORTO)
 221  	@$(PORTO) --include-internal -l . || ( echo "(run: make vanity-import-fix)"; exit 1 )
 222  
 223  .PHONY: misspell
 224  misspell: $(MISSPELL)
 225  	@$(MISSPELL) -w $(ALL_DOCS)
 226  
 227  .PHONY: govulncheck
 228  govulncheck: $(OTEL_GO_MOD_DIRS:%=govulncheck/%)
 229  govulncheck/%: DIR=$*
 230  govulncheck/%: $(GOVULNCHECK)
 231  	@echo "govulncheck ./... in $(DIR)" \
 232  		&& cd $(DIR) \
 233  		&& $(GOVULNCHECK) ./...
 234  
 235  .PHONY: codespell
 236  codespell: $(CODESPELL)
 237  	@$(DOCKERPY) $(CODESPELL)
 238  
 239  .PHONY: toolchain-check
 240  toolchain-check:
 241  	@toolchainRes=$$(for f in $(ALL_GO_MOD_DIRS); do \
 242  	           awk '/^toolchain/ { found=1; next } END { if (found) print FILENAME }' $$f/go.mod; \
 243  	done); \
 244  	if [ -n "$${toolchainRes}" ]; then \
 245  			echo "toolchain checking failed:"; echo "$${toolchainRes}"; \
 246  			exit 1; \
 247  	fi
 248  
 249  .PHONY: license-check
 250  license-check:
 251  	@licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './.git/*' ) ; do \
 252  	           awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \
 253  	   done); \
 254  	   if [ -n "$${licRes}" ]; then \
 255  	           echo "license header checking failed:"; echo "$${licRes}"; \
 256  	           exit 1; \
 257  	   fi
 258  
 259  .PHONY: check-clean-work-tree
 260  check-clean-work-tree:
 261  	@if ! git diff --quiet; then \
 262  	  echo; \
 263  	  echo 'Working tree is not clean, did you forget to run "make precommit"?'; \
 264  	  echo; \
 265  	  git status; \
 266  	  exit 1; \
 267  	fi
 268  
 269  # The weaver docker image to use for semconv-generate.
 270  WEAVER_IMAGE := $(shell awk '$$4=="weaver" {print $$2}' $(DEPENDENCIES_DOCKERFILE))
 271  
 272  SEMCONVPKG ?= "semconv/"
 273  .PHONY: semconv-generate
 274  semconv-generate: $(SEMCONVKIT)
 275  	[ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry semantic-conventions tag"; exit 1 )
 276  	# Ensure the target directory for source code is available.
 277  	mkdir -p $(PWD)/$(SEMCONVPKG)/${TAG}
 278  	# Note: We mount a home directory for downloading/storing the semconv repository.
 279  	# Weaver will automatically clean the cache when finished, but the directories will remain.
 280  	mkdir -p ~/.weaver
 281  	docker run --rm \
 282  		-u $(DOCKER_USER) \
 283  		--env HOME=/tmp/weaver \
 284  		--mount 'type=bind,source=$(PWD)/semconv/templates,target=/home/weaver/templates,readonly' \
 285  		--mount 'type=bind,source=$(PWD)/semconv/${TAG},target=/home/weaver/target' \
 286  		--mount 'type=bind,source=$(HOME)/.weaver,target=/tmp/weaver/.weaver' \
 287  		$(WEAVER_IMAGE) registry generate \
 288  		--registry=https://github.com/open-telemetry/semantic-conventions/archive/refs/tags/$(TAG).zip[model] \
 289  		--templates=/home/weaver/templates \
 290  		--param tag=$(TAG) \
 291  		go \
 292  		/home/weaver/target
 293  	$(SEMCONVKIT) -semconv "$(SEMCONVPKG)" -tag "$(TAG)"
 294  
 295  .PHONY: gorelease
 296  gorelease: $(OTEL_GO_MOD_DIRS:%=gorelease/%)
 297  gorelease/%: DIR=$*
 298  gorelease/%:| $(GORELEASE)
 299  	@echo "gorelease in $(DIR):" \
 300  		&& cd $(DIR) \
 301  		&& $(GORELEASE) \
 302  		|| echo ""
 303  
 304  .PHONY: verify-mods
 305  verify-mods: $(MULTIMOD)
 306  	$(MULTIMOD) verify
 307  
 308  .PHONY: prerelease
 309  prerelease: verify-mods
 310  	@[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
 311  	$(MULTIMOD) prerelease -m ${MODSET}
 312  
 313  COMMIT ?= "HEAD"
 314  .PHONY: add-tags
 315  add-tags: verify-mods
 316  	@[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
 317  	$(MULTIMOD) tag -m ${MODSET} -c ${COMMIT}
 318  
 319  MARKDOWNIMAGE := $(shell awk '$$4=="markdown" {print $$2}' $(DEPENDENCIES_DOCKERFILE))
 320  .PHONY: lint-markdown
 321  lint-markdown:
 322  	docker run --rm -u $(DOCKER_USER) -v "$(CURDIR):$(WORKDIR)" $(MARKDOWNIMAGE) -c $(WORKDIR)/.markdownlint.yaml $(WORKDIR)/**/*.md
 323  
 324  .PHONY: verify-readmes
 325  verify-readmes: $(VERIFYREADMES)
 326  	$(VERIFYREADMES)
 327