# In order to ensure make instructions fail if there is command that fails a pipe (ie: `go test ... | tee -a ./test_results.txt`) # the value `-o pipefail` (or `set -o pipefail`) is added to each shell command that make runs # otherwise in the example command pipe, only the exit code of `tee` is recorded instead of `go test` which can cause # test to pass in CI when they should not. SHELL = /bin/bash .SHELLFLAGS = -o pipefail -c SHELL_CASE_EXP = case "$$(uname -s)" in CYGWIN*|MINGW*|MSYS*) echo "true";; esac; UNIX_SHELL_ON_WINDOWS := $(shell $(SHELL_CASE_EXP)) ifeq ($(UNIX_SHELL_ON_WINDOWS),true) # The "sed" transformation below is needed on Windows, since commands like `go list -f '{{ .Dir }}'` # return Windows paths and such paths are incompatible with other *nix tools, like `find`, # used by the Makefile shell. # The backslash needs to be doubled so its passed correctly to the shell. NORMALIZE_DIRS = sed -e 's/^/\\//' -e 's/://' -e 's/\\\\/\\//g' | sort else NORMALIZE_DIRS = sort endif # SRC_ROOT is the top of the source tree. SRC_ROOT := $(shell git rev-parse --show-toplevel) # SRC_PARENT_DIR is the absolute path of source tree's parent directory SRC_PARENT_DIR := $(shell dirname $(SRC_ROOT)) # build tags required by any component should be defined as an independent variables and later added to GO_BUILD_TAGS below GO_BUILD_TAGS="" # These ldflags allow the build tool to omit the symbol table, debug information, and the DWARF symbol table to downscale binary size. GO_BUILD_LDFLAGS="-s -w" GOTEST_TIMEOUT?= 600s GOTEST_OPT?= -race -timeout $(GOTEST_TIMEOUT) -parallel 4 --tags=$(GO_BUILD_TAGS) GOTEST_INTEGRATION_OPT?= -race -timeout 360s -parallel 4 GOTEST_OPT_WITH_COVERAGE = $(GOTEST_OPT) -coverprofile=coverage.txt -covermode=atomic GOTEST_OPT_WITH_INTEGRATION=$(GOTEST_INTEGRATION_OPT) -tags=integration,$(GO_BUILD_TAGS) GOTEST_OPT_WITH_INTEGRATION_COVERAGE=$(GOTEST_OPT_WITH_INTEGRATION) -coverprofile=integration-coverage.txt -covermode=atomic GOCMD?= go GOOS=$(shell $(GOCMD) env GOOS) GOARCH=$(shell $(GOCMD) env GOARCH) GOTESTARCH?=$(GOARCH) DOCKERCMD ?= docker # In order to help reduce toil related to managing tooling for the open telemetry collector # this section of the makefile looks at only requiring command definitions to be defined # as part of $(TOOLS_MOD_DIR)/tools.go, following the existing practice. # Modifying the tools' `go.mod` file will trigger a rebuild of the tools to help # ensure that all contributors are using the most recent version to make builds repeatable everywhere. TOOLS_MOD_DIR := $(SRC_ROOT)/internal/tools TOOLS_MOD_REGEX := "\s+_\s+\".*\"" TOOLS_PKG_NAMES := $(shell grep -E $(TOOLS_MOD_REGEX) < $(TOOLS_MOD_DIR)/tools.go | tr -d " _\"") TOOLS_BIN_DIR := $(SRC_ROOT)/.tools TOOLS_BIN_NAMES := $(addprefix $(TOOLS_BIN_DIR)/, $(notdir $(TOOLS_PKG_NAMES))) CHLOGGEN_CONFIG := .chloggen/config.yaml .PHONY: install-tools install-tools: $(TOOLS_BIN_NAMES) $(TOOLS_BIN_DIR): mkdir -p $@ $(TOOLS_BIN_NAMES): $(TOOLS_BIN_DIR) $(TOOLS_MOD_DIR)/go.mod cd $(TOOLS_MOD_DIR) && GOOS="" GOARCH="" $(GOCMD) build -o $@ -trimpath $(filter %/$(notdir $@),$(TOOLS_PKG_NAMES)) ADDLICENSE := $(TOOLS_BIN_DIR)/addlicense MDLINKCHECK := $(TOOLS_BIN_DIR)/markdown-link-check MISSPELL := $(TOOLS_BIN_DIR)/misspell -error MISSPELL_CORRECTION := $(TOOLS_BIN_DIR)/misspell -w LINT := $(TOOLS_BIN_DIR)/golangci-lint MULTIMOD := $(TOOLS_BIN_DIR)/multimod CHLOGGEN := $(TOOLS_BIN_DIR)/chloggen GITHUBGEN := $(TOOLS_BIN_DIR)/githubgen GOIMPORTS := $(TOOLS_BIN_DIR)/goimports PORTO := $(TOOLS_BIN_DIR)/porto CHECKFILE := $(TOOLS_BIN_DIR)/checkfile CROSSLINK := $(TOOLS_BIN_DIR)/crosslink GOJUNIT := $(TOOLS_BIN_DIR)/go-junit-report BUILDER := $(TOOLS_BIN_DIR)/builder GOFUMPT := $(TOOLS_BIN_DIR)/gofumpt GOVULNCHECK := $(TOOLS_BIN_DIR)/govulncheck GCI := $(TOOLS_BIN_DIR)/gci GOTESTSUM := $(TOOLS_BIN_DIR)/gotestsum TESTIFYLINT := $(TOOLS_BIN_DIR)/testifylint GOTESTSUM_OPT?= --rerun-fails=1 TESTIFYLINT_OPT?= --enable-all --disable=float-compare,require-error,suite-subtest-run,encoded-compare # BUILD_TYPE should be one of (dev, release). BUILD_TYPE?=release ALL_PKG_DIRS := $(shell $(GOCMD) list -f '{{ .Dir }}' ./... | $(NORMALIZE_DIRS)) ALL_SRC := $(shell find $(ALL_PKG_DIRS) -name '*.go' \ -not -path '*/third_party/*' \ -not -path '*/local/*' \ -type f | sort) ALL_SRC_AND_SHELL := find . -type f \( -iname '*.go' -o -iname "*.sh" \) ! -path '**/third_party/*' | sort # All source code and documents. Used in spell check. ALL_SRC_AND_DOC_CMD := find $(ALL_PKG_DIRS) -name "*.md" -o -name "*.go" -o -name "*.yaml" -not -path '*/third_party/*' -type f | sort ifeq ($(UNIX_SHELL_ON_WINDOWS),true) # Windows has a low limit, 8192 chars, to create a process. Workaround it by breaking it in smaller commands. MISSPELL_CMD := $(ALL_SRC_AND_DOC_CMD) | xargs -n 20 $(MISSPELL) MISSPELL_CORRECTION_CMD := $(ALL_SRC_AND_DOC_CMD) | xargs -n 20 $(MISSPELL_CORRECTION) else ALL_SRC_AND_DOC := $(shell $(ALL_SRC_AND_DOC_CMD)) MISSPELL_CMD := $(MISSPELL) $(ALL_SRC_AND_DOC) MISSPELL_CORRECTION_CMD := $(MISSPELL_CORRECTION) $(ALL_SRC_AND_DOC) endif # ALL_PKGS is used with 'go cover' ALL_PKGS := $(shell $(GOCMD) list $(sort $(dir $(ALL_SRC)))) ADDLICENSE_CMD := $(ADDLICENSE) -s=only -y "" -c "The OpenTelemetry Authors" pwd: @pwd all-pkgs: @echo $(ALL_PKGS) | tr ' ' '\n' | sort all-srcs: @echo $(ALL_SRC) | tr ' ' '\n' | sort all-pkg-dirs: @echo $(ALL_PKG_DIRS) | tr ' ' '\n' | sort .DEFAULT_GOAL := common .PHONY: common common: lint test .PHONY: test test: $(GOTESTSUM) $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT) .PHONY: test-with-cover test-with-cover: $(GOTESTSUM) mkdir -p $(PWD)/coverage/unit $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT) -cover -covermode=atomic -args -test.gocoverdir="$(PWD)/coverage/unit" .PHONY: do-unit-tests-with-cover do-unit-tests-with-cover: $(GOTESTSUM) @echo "running $(GOCMD) unit test ./... + coverage in `pwd`" $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT_WITH_COVERAGE) $(GOCMD) tool cover -html=coverage.txt -o coverage.html .PHONY: buildtest buildtest: ifneq (,$(wildcard ./*.go)) GOARCH=$(GOTESTARCH) CGO_ENABLED=1 $(GOCMD) test -c -o builtunitetest.test endif .PHONY: runbuilttest runbuilttest: $(GOTESTSUM) ifneq (,$(wildcard ./builtunitetest.test)) $(GOTESTSUM) --raw-command -- $(GOCMD) tool test2json -p "./..." -t ./builtunitetest.test -test.v -test.failfast -test.timeout $(GOTEST_TIMEOUT) endif .PHONY: mod-integration-test mod-integration-test: $(GOTESTSUM) @echo "running $(GOCMD) integration test ./... in `pwd`" $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT_WITH_INTEGRATION) @if [ -e integration-coverage.txt ]; then \ $(GOCMD) tool cover -html=integration-coverage.txt -o integration-coverage.html; \ fi .PHONY: do-integration-tests-with-cover do-integration-tests-with-cover: $(GOTESTSUM) @echo "running $(GOCMD) integration test ./... + coverage in `pwd`" $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT_WITH_INTEGRATION_COVERAGE) @if [ -e integration-coverage.txt ]; then \ $(GOCMD) tool cover -html=integration-coverage.txt -o integration-coverage.html; \ fi .PHONY: benchmark benchmark: $(GOTESTSUM) $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="$(ALL_PKGS)" -- -bench=. -run=notests --tags=$(GO_BUILD_TAGS) .PHONY: addlicense addlicense: $(ADDLICENSE) @ADDLICENSEOUT=$$(for f in $$($(ALL_SRC_AND_SHELL)); do \ `$(ADDLICENSE_CMD) "$$f" 2>&1`; \ done); \ if [ "$$ADDLICENSEOUT" ]; then \ echo "$(ADDLICENSE) FAILED => add License errors:\n"; \ echo "$$ADDLICENSEOUT\n"; \ exit 1; \ else \ echo "Add License finished successfully"; \ fi .PHONY: checklicense checklicense: $(ADDLICENSE) @licRes=$$(for f in $$($(ALL_SRC_AND_SHELL)); do \ awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=3 { found=1; next } END { if (!found) print FILENAME }' $$f; \ awk '/SPDX-License-Identifier: Apache-2.0|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \ $(ADDLICENSE_CMD) -check "$$f" 2>&1 || echo "$$f"; \ done); \ if [ -n "$${licRes}" ]; then \ echo "license header checking failed:"; echo "$${licRes}"; \ exit 1; \ else \ echo "Check License finished successfully"; \ fi .PHONY: checklinks checklinks: command -v $(DOCKERCMD) >/dev/null 2>&1 || { echo >&2 "$(DOCKERCMD) not installed. Install before continuing"; exit 1; } $(DOCKERCMD) run -w /home/repo --rm \ --mount 'type=bind,source='$(PWD)',target=/home/repo' \ --mount 'type=bind,source='$(SRC_ROOT)/.github/lychee.toml',target=/lychee.toml' \ lycheeverse/lychee \ --config /lychee.toml \ --root-dir /home/repo \ -v \ --no-progress './**/*.md' .PHONY: fmt fmt: $(GOFUMPT) $(GOIMPORTS) $(GOFUMPT) -l -w . $(GOIMPORTS) -w -local github.com/open-telemetry/opentelemetry-collector-contrib ./ .PHONY: lint lint: $(LINT) checklicense misspell $(LINT) run --allow-parallel-runners --build-tags integration --timeout=30m --path-prefix $(shell basename "$(CURDIR)") .PHONY: govulncheck govulncheck: $(GOVULNCHECK) $(GOVULNCHECK) ./... .PHONY: tidy tidy: rm -fr go.sum $(GOCMD) mod tidy -compat=1.22.0 .PHONY: toolchain toolchain: $(GOCMD) get toolchain@none .PHONY: misspell misspell: $(TOOLS_BIN_DIR)/misspell @echo "running $(MISSPELL)" @$(MISSPELL_CMD) .PHONY: misspell-correction misspell-correction: $(TOOLS_BIN_DIR)/misspell $(MISSPELL_CORRECTION_CMD) .PHONY: moddownload moddownload: $(GOCMD) mod download .PHONY: testifylint testifylint: $(TESTIFYLINT) @echo "running $(TESTIFYLINT)" $(TESTIFYLINT) $(TESTIFYLINT_OPT) ./... .PHONY: testifylint-fix testifylint-fix: @$(MAKE) testifylint TESTIFYLINT_OPT="${TESTIFYLINT_OPT} --fix" .PHONY: gci gci: $(TOOLS_BIN_DIR)/gci @echo "running $(GCI)" @$(GCI) write -s standard -s default -s "prefix(github.com/open-telemetry/opentelemetry-collector-contrib)" $(ALL_SRC_AND_DOC) CHANGED_GOLANG_SOURCES?=$(shell git diff main --name-only | grep -E '.*\.go$$' | grep -v -E '.*_test\.go$$') .PHONY: for-affected-components for-affected-components: @echo "Checking for affected components..." @if [ -z '$${CHANGED_GOLANG_SOURCES}' ]; then \ echo "No go source changes detected in shippable code."; \ else \ cd $(SRC_ROOT); \ DEPENDENT_PKGS=$$(echo $${CHANGED_GOLANG_SOURCES} | xargs sed -n 's|^package .* // import "\(.*\)"$$|\1|p' | uniq); \ if [ -z '$${DEPENDENT_PKGS}' ]; then \ echo "No other package depends on the one being changed."; \ else \ DEPENDENT_PKG_DIRS=$$(echo $${DEPENDENT_PKGS} | tr ' ' '\n' | xargs -I {} grep --include=go.mod -rl {} | xargs -r dirname | uniq); \ set -e; for dir in $$(echo $${DEPENDENT_PKG_DIRS}); do \ (cd "$${dir}" && \ echo "running $${CMD} in $${dir}" && \ $${CMD} ); \ done \ fi \ fi CHANGED_GOLANG_TESTS?=$(shell git diff main --name-only | grep -E '.*_test\.go$$') .PHONY: run-changed-tests run-changed-tests: @echo "Checking for affected tests..." @if [ -z '$${CHANGED_GOLANG_TESTS}' ]; then \ echo "No go test changes detected."; \ else \ cd $(SRC_ROOT); \ AFFECTED_TEST_DIRS=$$(echo $${CHANGED_GOLANG_TESTS} | tr ' ' '\n' | xargs dirname | uniq); \ if [ -z '$${AFFECTED_TEST_DIRS}' ]; then \ echo "Failed to find the affected test directories."; \ else \ set -e; for dir in $$(echo $${AFFECTED_TEST_DIRS}); do \ (cd "$${dir}" && \ $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT) ); \ done \ fi \ fi