diff --git a/Makefile b/Makefile index e47869d10..5f7d2fa21 100644 --- a/Makefile +++ b/Makefile @@ -15,84 +15,34 @@ # We need bash for some conditional logic below. SHELL := /usr/bin/env bash -e -GO_INSTALL = ./hack/go-install.sh +ROOT_DIR = $(abspath .) +TOOLS_DIR = hack/tools +BUILD_DIR = $(ROOT_DIR)/bin -ROOT_DIR=$(abspath .) -TOOLS_DIR=hack/tools -TOOLS_GOBIN_DIR := $(abspath $(TOOLS_DIR)) -GOBIN_DIR=$(abspath ./bin ) -PATH := $(GOBIN_DIR):$(TOOLS_GOBIN_DIR):$(PATH) -TMPDIR := $(shell mktemp -d) +export UGET_DIRECTORY = $(TOOLS_DIR) +export UGET_CHECKSUMS = hack/tools.checksums +export UGET_VERSIONED_BINARIES = true # Image build configuration # REV is the short git sha of latest commit. -REV ?= $(shell git rev-parse --short HEAD) -IMAGE_REPO ?= kube-bind - -# Detect the path used for the install target -ifeq (,$(shell go env GOBIN)) -INSTALL_GOBIN=$(shell go env GOPATH)/bin -else -INSTALL_GOBIN=$(shell go env GOBIN) -endif - -CONTROLLER_GEN_VER := v0.17.3 -CONTROLLER_GEN_BIN := controller-gen -CONTROLLER_GEN := $(TOOLS_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER) -export CONTROLLER_GEN # so hack scripts can use it - -KUBE_CLIENT_GEN_VER := v0.32.0 -KUBE_CLIENT_GEN_BIN := client-gen -KUBE_LISTER_GEN_VER := v0.32.0 -KUBE_LISTER_GEN_BIN := lister-gen -KUBE_INFORMER_GEN_VER := v0.32.0 -KUBE_INFORMER_GEN_BIN := informer-gen -KUBE_APPLYCONFIGURATION_GEN_VER := v0.32.0 -KUBE_APPLYCONFIGURATION_GEN_BIN := applyconfiguration-gen - -KUBE_CLIENT_GEN := $(GOBIN_DIR)/$(KUBE_CLIENT_GEN_BIN)-$(KUBE_CLIENT_GEN_VER) -export KUBE_CLIENT_GEN -KUBE_LISTER_GEN := $(GOBIN_DIR)/$(KUBE_LISTER_GEN_BIN)-$(KUBE_LISTER_GEN_VER) -export KUBE_LISTER_GEN -KUBE_INFORMER_GEN := $(GOBIN_DIR)/$(KUBE_INFORMER_GEN_BIN)-$(KUBE_INFORMER_GEN_VER) -export KUBE_INFORMER_GEN -KUBE_APPLYCONFIGURATION_GEN := $(GOBIN_DIR)/$(KUBE_APPLYCONFIGURATION_GEN_BIN)-$(KUBE_APPLYCONFIGURATION_GEN_VER) -export KUBE_APPLYCONFIGURATION_GEN - -YAML_PATCH_VER ?= v0.0.11 -YAML_PATCH_BIN := yaml-patch -YAML_PATCH := $(TOOLS_DIR)/$(YAML_PATCH_BIN)-$(YAML_PATCH_VER) -export YAML_PATCH # so hack scripts can use it - -GOLANGCI_LINT_VER := v2.1.6 -GOLANGCI_LINT_BIN := golangci-lint -GOLANGCI_LINT := $(TOOLS_GOBIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER) - -GOTESTSUM_VER := v1.8.1 -GOTESTSUM_BIN := gotestsum -GOTESTSUM := $(abspath $(TOOLS_DIR))/$(GOTESTSUM_BIN)-$(GOTESTSUM_VER) - -LOGCHECK_VER := v0.2.0 -LOGCHECK_BIN := logcheck -LOGCHECK := $(TOOLS_GOBIN_DIR)/$(LOGCHECK_BIN)-$(LOGCHECK_VER) -export LOGCHECK # so hack scripts can use it - -CODE_GENERATOR_VER := v2.4.0 -CODE_GENERATOR_BIN := code-generator -CODE_GENERATOR := $(TOOLS_GOBIN_DIR)/$(CODE_GENERATOR_BIN)-$(CODE_GENERATOR_VER) -export CODE_GENERATOR # so hack scripts can use it - -KCP_VER := v0.28.3 -KCP_BIN := kcp -KCP := $(TOOLS_GOBIN_DIR)/$(KCP_BIN)-$(KCP_VER) -KCP_CMD ?= $(KCP) - -DEX_VER := v2.43.1 -DEX_BIN := dex -DEX := $(TOOLS_GOBIN_DIR)/$(DEX_BIN)-$(DEX_VER) - -ARCH := $(shell go env GOARCH) -OS := $(shell go env GOOS) +export REV ?= $(shell git rev-parse --short HEAD) +export IMAGE_REPO ?= kube-bind + +BOILERPLATE_VERSION := 201dcad9616c117927232ee0bc499ff38a27023e +CODE_GENERATOR_VERSION := v2.4.0 +CONTROLLER_GEN_VERSION := v0.17.3 +DEX_VERSION := v2.43.1 +GOLANGCI_LINT_VERSION := 2.1.6 +GORELEASER_VERSION := 2.13.0 +GOTESTSUM_VERSION := 1.8.1 +HELM_VERSION := 3.18.6 +KCP_VERSION := 0.28.3 +KUBE_APPLYCONFIGURATION_GEN_VERSION := v0.32.0 +KUBE_CLIENT_GEN_VERSION := v0.32.0 +KUBE_INFORMER_GEN_VERSION := v0.32.0 +KUBE_LISTER_GEN_VERSION := v0.32.0 +LOGCHECK_VERSION := v0.2.0 +YAML_PATCH_VERSION ?= v0.0.11 KUBE_MAJOR_VERSION := 1 KUBE_MINOR_VERSION := $(shell go mod edit -json | jq '.Require[] | select(.Path == "k8s.io/client-go") | .Version' --raw-output | sed "s/v[0-9]*\.\([0-9]*\).*/\1/") @@ -118,14 +68,25 @@ LDFLAGS := \ CONTRIBS ?= $(patsubst contrib/%,%,$(wildcard contrib/*)) -all: build .PHONY: all +all: build + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) + @echo "Cleaned $(BUILD_DIR)." + +.PHONY: clean-tools +clean-tools: + rm -rf $(UGET_DIRECTORY) + @echo "Cleaned $(UGET_DIRECTORY)." -check: verify lint test test-e2e test-e2e-contribs .PHONY: check +check: verify lint test test-e2e test-e2e-contribs GOMODS := $(shell find . -name 'go.mod' -exec dirname {} \; | grep -v hack/tools | grep -v ./dex) +.PHONY: ldflags ldflags: @echo $(LDFLAGS) @@ -133,32 +94,102 @@ ldflags: require-%: @if ! command -v $* 1> /dev/null 2>&1; then echo "$* not found in \$$PATH"; exit 1; fi +.PHONY: build build: WHAT ?= ./cmd/... ./cli/cmd/... ./contrib/kcp/cmd/kcp-init/... -build: require-jq require-go require-git verify-go-versions ## Build the project - mkdir -p $(GOBIN_DIR) - set -x; for W in $(WHAT); do \ - pushd . && cd $${W%..}; \ - GOOS=$(OS) GOARCH=$(ARCH) CGO_ENABLED=0 go build $(BUILDFLAGS) -ldflags="$(LDFLAGS)" -o $(GOBIN_DIR) ./...; \ - popd; \ +build: export CGO_ENABLED=0 +build: verify-go-versions ## Build the project + @mkdir -p $(BUILD_DIR) + @for W in $(WHAT); do \ + (set -x; cd $${W%...}; go build $(BUILDFLAGS) -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/ ./...); \ done -.PHONY: build +.PHONY: install install: WHAT ?= ./cmd/... ./cli/cmd/... install: ## install binaries to GOBIN - GOOS=$(OS) GOARCH=$(ARCH) go install -ldflags="$(LDFLAGS)" $(WHAT) -.PHONY: install + go install -ldflags="$(LDFLAGS)" $(WHAT) + +GOLANGCI_LINT = $(ROOT_DIR)/$(UGET_DIRECTORY)/golangci-lint-$(GOLANGCI_LINT_VERSION) + +.PHONY: install-golangci-lint +install-golangci-lint: + @hack/uget.sh https://github.com/golangci/golangci-lint/releases/download/v{VERSION}/golangci-lint-{VERSION}-{GOOS}-{GOARCH}.tar.gz golangci-lint $(GOLANGCI_LINT_VERSION) + +.PHONY: install-logcheck +install-logcheck: + @GO_MODULE=true hack/uget.sh sigs.k8s.io/logtools/logcheck logcheck $(LOGCHECK_VERSION) + +# .PHONY: install-kcp-codegen +# install-kcp-codegen: +# @GO_MODULE=true hack/uget.sh github.com/kcp-dev/code-generator/v2 kcp-code-generator $(CODE_GENERATOR_VERSION) code-generator + +.PHONY: install-controller-gen +install-controller-gen: + @GO_MODULE=true hack/uget.sh sigs.k8s.io/controller-tools/cmd/controller-gen controller-gen $(CONTROLLER_GEN_VERSION) + +.PHONY: install-yaml-patch +install-yaml-patch: + @GO_MODULE=true hack/uget.sh github.com/pivotal-cf/yaml-patch/cmd/yaml-patch yaml-patch $(YAML_PATCH_VERSION) + +.PHONY: install-gotestsum +install-gotestsum: + @hack/uget.sh https://github.com/gotestyourself/gotestsum/releases/download/v{VERSION}/gotestsum_{VERSION}_{GOOS}_{GOARCH}.tar.gz gotestsum $(GOTESTSUM_VERSION) gotestsum + +# .PHONY: install-client-gen +# install-client-gen: +# @GO_MODULE=true hack/uget.sh k8s.io/code-generator/cmd/client-gen client-gen $(CLIENT_GEN_VERSION) + +# .PHONY: install-lister-gen +# install-lister-gen: +# @GO_MODULE=true hack/uget.sh k8s.io/code-generator/cmd/lister-gen lister-gen $(CLIENT_GEN_VERSION) + +# .PHONY: install-informer-gen +# install-informer-gen: +# @GO_MODULE=true hack/uget.sh k8s.io/code-generator/cmd/informer-gen informer-gen $(CLIENT_GEN_VERSION) + +# .PHONY: install-applyconfiguration-gen +# install-applyconfiguration-gen: +# @GO_MODULE=true hack/uget.sh k8s.io/code-generator/cmd/applyconfiguration-gen applyconfiguration-gen $(APPLYCONFIGURATION_GEN_VERSION) + +.PHONY: install-boilerplate +install-boilerplate: + @UGET_VERSIONED_BINARIES=false UNCOMPRESSED=true hack/uget.sh https://raw.githubusercontent.com/kubernetes/repo-infra/master/hack/verify_boilerplate.py verify_boilerplate.py $(BOILERPLATE_VERSION) verify_boilerplate.py + +.PHONY: install-kcp +install-kcp: + @hack/uget.sh https://github.com/kcp-dev/kcp/releases/download/v{VERSION}/kcp_{VERSION}_{GOOS}_{GOARCH}.tar.gz kcp $(KCP_VERSION) + +GORELEASER = $(UGET_DIRECTORY)/goreleaser-$(GORELEASER_VERSION) +.PHONY: install-goreleaser +install-goreleaser: export OS ?= $(shell uname -s) +install-goreleaser: export ARCH ?= $(shell uname -m) +install-goreleaser: + @hack/uget.sh https://github.com/goreleaser/goreleaser/releases/download/v{VERSION}/goreleaser_{ENV:OS}_{ENV:ARCH}.tar.gz goreleaser $(GORELEASER_VERSION) goreleaser -$(GOLANGCI_LINT): - GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) github.com/golangci/golangci-lint/v2/cmd/golangci-lint $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER) +.PHONY: install-helm +install-helm: + @hack/uget.sh https://get.helm.sh/helm-v{VERSION}-{GOOS}-{GOARCH}.tar.gz helm $(HELM_VERSION) -$(LOGCHECK): - GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) sigs.k8s.io/logtools/logcheck $(LOGCHECK_BIN) $(LOGCHECK_VER) +# e2e tests use this env name to locate the dex binary; make sure it's an absolute path +export DEX_BINARY = $(ROOT_DIR)/$(UGET_DIRECTORY)/dex-$(DEX_VERSION) -$(CODE_GENERATOR): - GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) github.com/kcp-dev/code-generator/v2 $(CODE_GENERATOR_BIN) $(CODE_GENERATOR_VER) +.PHONY: install-dex +install-dex: $(DEX_BINARY) -lint: $(GOLANGCI_LINT) $(LOGCHECK) ## Run golangci-lint +$(DEX_BINARY): + mkdir -p $(TOOLS_DIR) + git clone --branch $(DEX_VERSION) --depth 1 https://github.com/dexidp/dex $(TOOLS_DIR)/dex-clone-$(DEX_VERSION) || true + cd $(TOOLS_DIR)/dex-clone-$(DEX_VERSION) && GOWORK=off make build && cp bin/dex $(DEX_BINARY) + +# This target can be used to conveniently update the checksums for all checksummed tools. +# Combine with GOARCH to update for other archs, like "GOARCH=arm64 make update-tools". + +.PHONY: update-tools +update-tools: UGET_UPDATE=true +update-tools: clean-tools install-golangci-lint install-gotestsum install-boilerplate install-kcp install-helm install-goreleaser + +.PHONY: lint +lint: install-golangci-lint install-logcheck ## Run golangci-lint @if [ -n "$(WHAT)" ]; then \ $(GOLANGCI_LINT) run $(GOLANGCI_LINT_FLAGS) -c $(ROOT_DIR)/.golangci.yaml --timeout 20m $(WHAT); \ else \ @@ -166,39 +197,17 @@ lint: $(GOLANGCI_LINT) $(LOGCHECK) ## Run golangci-lint (cd $$MOD; echo "Linting $$MOD"; $(GOLANGCI_LINT) run $(GOLANGCI_LINT_FLAGS) -c $(ROOT_DIR)/.golangci.yaml --timeout 20m); \ done; \ fi -.PHONY: lint -fix-lint: $(GOLANGCI_LINT) ## Run golangci-lint with --fix - GOLANGCI_LINT_FLAGS="--fix" $(MAKE) lint .PHONY: fix-lint +fix-lint: install-golangci-lint ## Run golangci-lint with --fix + GOLANGCI_LINT_FLAGS="--fix" $(MAKE) lint -tools: $(GOLANGCI_LINT) $(CONTROLLER_GEN) $(YAML_PATCH) $(GOTESTSUM) $(CODE_GENERATOR) ## Install tools -.PHONY: tools - -$(CONTROLLER_GEN): - GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) sigs.k8s.io/controller-tools/cmd/controller-gen $(CONTROLLER_GEN_BIN) $(CONTROLLER_GEN_VER) - -$(YAML_PATCH): - GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) github.com/pivotal-cf/yaml-patch/cmd/yaml-patch $(YAML_PATCH_BIN) $(YAML_PATCH_VER) - -$(GOTESTSUM): - GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) gotest.tools/gotestsum $(GOTESTSUM_BIN) $(GOTESTSUM_VER) - -$(KUBE_CLIENT_GEN): - GOBIN=$(GOBIN_DIR) $(GO_INSTALL) k8s.io/code-generator/cmd/$(KUBE_CLIENT_GEN_BIN) $(KUBE_CLIENT_GEN_BIN) $(KUBE_CLIENT_GEN_VER) -$(KUBE_LISTER_GEN): - GOBIN=$(GOBIN_DIR) $(GO_INSTALL) k8s.io/code-generator/cmd/$(KUBE_LISTER_GEN_BIN) $(KUBE_LISTER_GEN_BIN) $(KUBE_LISTER_GEN_VER) -$(KUBE_INFORMER_GEN): - GOBIN=$(GOBIN_DIR) $(GO_INSTALL) k8s.io/code-generator/cmd/$(KUBE_INFORMER_GEN_BIN) $(KUBE_INFORMER_GEN_BIN) $(KUBE_INFORMER_GEN_VER) -$(KUBE_APPLYCONFIGURATION_GEN): - GOBIN=$(GOBIN_DIR) $(GO_INSTALL) k8s.io/code-generator/cmd/$(KUBE_APPLYCONFIGURATION_GEN_BIN) $(KUBE_APPLYCONFIGURATION_GEN_BIN) $(KUBE_APPLYCONFIGURATION_GEN_VER) - - -codegen: $(CONTROLLER_GEN) $(YAML_PATCH) $(CODE_GENERATOR) $(KUBE_CLIENT_GEN) $(KUBE_LISTER_GEN) $(KUBE_INFORMER_GEN) $(KUBE_APPLYCONFIGURATION_GEN) ## Generate code +.PHONY: codegen +codegen: ## Generate code go mod download ./hack/update-codegen.sh + ./hack/update-codegen-clients.sh $(MAKE) imports -.PHONY: codegen # Note, running this locally if you have any modified files, even those that are not generated, # will result in an error. This target is mostly for CI jobs. @@ -218,23 +227,22 @@ verify-codegen: fi .PHONY: imports -imports: $(GOLANGCI_LINT) verify-go-versions ## Fix imports and format code +imports: install-golangci-lint verify-go-versions ## Fix imports and format code @if [ -n "$(WHAT)" ]; then \ - $(GOLANGCI_LINT) fmt --enable gci -c $(ROOT_DIR)/.golangci.yaml $(WHAT); \ + $(GOLANGCI_LINT) fmt --enable gci $(WHAT); \ else \ for MOD in $(GOMODS); do \ ( cd $$MOD; $(GOLANGCI_LINT) fmt --enable gci -c $(ROOT_DIR)/.golangci.yaml; ) \ done; \ fi -$(TOOLS_DIR)/verify_boilerplate.py: - mkdir -p $(TOOLS_DIR) - curl --fail --retry 3 -L -o $(TOOLS_DIR)/verify_boilerplate.py https://raw.githubusercontent.com/kubernetes/repo-infra/master/hack/verify_boilerplate.py - chmod +x $(TOOLS_DIR)/verify_boilerplate.py - .PHONY: verify-boilerplate -verify-boilerplate: $(TOOLS_DIR)/verify_boilerplate.py - $(TOOLS_DIR)/verify_boilerplate.py --boilerplate-dir=hack/boilerplate --skip dex +verify-boilerplate: install-boilerplate + $(TOOLS_DIR)/verify_boilerplate.py --boilerplate-dir=hack/boilerplate \ + --skip dex \ + --skip docs/venv \ + --skip docs/__pycache__ \ + --skip hack/uget.sh ifdef ARTIFACT_DIR GOTESTSUM_ARGS += --junitfile=$(ARTIFACT_DIR)/junit.xml @@ -253,28 +261,18 @@ else E2E_PARALLELISM_FLAG := endif -$(DEX): - mkdir -p $(TOOLS_DIR) - git clone --branch $(DEX_VER) --depth 1 https://github.com/dexidp/dex $(TOOLS_DIR)/dex-clone-$(DEX_VER) || true - cd $(TOOLS_DIR)/dex-clone-$(DEX_VER) && GOWORK=off make build - cp -a $(TOOLS_DIR)/dex-clone-$(DEX_VER)/bin/dex $(DEX) - ln -sf $(DEX) $(TOOLS_GOBIN_DIR)/dex - -run-dex: $(DEX) - $(DEX) serve hack/dex-config-dev.yaml +.PHONY: run-dex +run-dex: $(DEX_BINARY) + $(DEX_BINARY) serve hack/dex-config-dev.yaml -$(KCP): - mkdir -p $(TOOLS_DIR) - curl --fail --retry 3 -L "https://github.com/kcp-dev/kcp/releases/download/$(KCP_VER)/kcp_$(KCP_VER:v%=%)_$(OS)_$(ARCH).tar.gz" | \ - tar xz -C "$(TOOLS_DIR)" --strip-components="1" bin/kcp - mv $(TOOLS_DIR)/kcp $(KCP) - ln -sf $(KCP) $(TOOLS_GOBIN_DIR)/kcp +KCP = $(TOOLS_DIR)/kcp-$(KCP_VERSION) -run-kcp: $(KCP) - $(KCP_CMD) start --bind-address=127.0.0.1 +.PHONY: run-kcp +run-kcp: install-kcp + $(KCP) start --bind-address=127.0.0.1 .PHONY: run-kcp-infra -run-kcp-infra: $(KCP) $(DEX) ## Run KCP infrastructure for e2e tests (blocking) +run-kcp-infra: install-kcp $(DEX_BINARY) ## Run KCP infrastructure for e2e tests (blocking) mkdir -p .kcp $(MAKE) run-dex 2>&1 & DEX_PID=$$!; \ $(MAKE) run-kcp &>.kcp/kcp.log & KCP_PID=$$!; \ @@ -300,7 +298,7 @@ endif test-e2e: TEST_ARGS ?= test-e2e: WORK_DIR ?= . test-e2e: TEST_WHAT ?= ./test/e2e... -test-e2e: $(KCP) $(DEX) build ## Run e2e tests +test-e2e: $(DEX_BINARY) build ## Run e2e tests mkdir .kcp $(MAKE) run-kcp &>.kcp/kcp.log & KCP_PID=$$!; \ trap 'kill -TERM $$KCP_PID; rm -rf .kcp' TERM INT EXIT && \ @@ -312,7 +310,8 @@ CONTRIBS_E2E := $(patsubst %,test-e2e-contrib-%,$(CONTRIBS)) .PHONY: test-e2e-contribs $(CONTRIBS_E2E) test-e2e-contribs: $(CONTRIBS_E2E) ## Run e2e tests for external integrations -test-e2e-contrib-kcp: $(DEX) $(KCP) +.PHONY: test-e2e-contrib-kcp +test-e2e-contrib-kcp: $(DEX_BINARY) $(CONTRIBS_E2E): mkdir .kcp $(MAKE) run-kcp &>.kcp/kcp.log & KCP_PID=$$!; \ @@ -402,45 +401,10 @@ build-web: # Example: make IMAGE_REPO=ghcr.io/ image-local # Set PLATFORMS to override default architectures (e.g., make PLATFORMS=linux/amd64,linux/arm64 image-local) # For local builds, default to current architecture on Linux platform to support --load -PLATFORMS ?= linux/$(ARCH) .PHONY: image-local +image-local: export PLATFORMS ?= linux/$(shell go env GOARCH) image-local: - @echo "Building images locally with tag $(REV) for platforms: $(PLATFORMS)" - @command -v docker >/dev/null 2>&1 || { echo "docker not found. Please install Docker"; exit 1; } - @docker buildx version >/dev/null 2>&1 || { echo "docker buildx not found. Please enable buildx in Docker"; exit 1; } - - @# Create buildx builder if it doesn't exist - @docker buildx create --name kube-bind-builder --use 2>/dev/null || docker buildx use kube-bind-builder 2>/dev/null || true - @docker buildx inspect --bootstrap >/dev/null 2>&1 - - @# Check if building for multiple platforms - @if [[ "$(PLATFORMS)" == *","* ]]; then \ - echo "Multi-platform build detected. Images will be pushed to registry instead of loaded locally."; \ - LOAD_FLAG="--push"; \ - else \ - echo "Single platform build. Images will be loaded to local Docker daemon."; \ - LOAD_FLAG="--load"; \ - fi && \ - \ - echo "Building konnector image..." && \ - docker buildx build \ - --platform $(PLATFORMS) \ - --build-arg LDFLAGS="$(LDFLAGS)" \ - -t $(IMAGE_REPO)/konnector:$(REV) \ - -f Dockerfile.konnector \ - $$LOAD_FLAG . && \ - \ - echo "Building backend image..." && \ - docker buildx build \ - --platform $(PLATFORMS) \ - --build-arg LDFLAGS="$(LDFLAGS)" \ - -t $(IMAGE_REPO)/backend:$(REV) \ - -f Dockerfile \ - $$LOAD_FLAG . && \ - \ - echo "Successfully built images:" && \ - echo " $(IMAGE_REPO)/konnector:$(REV) ($(PLATFORMS))" && \ - echo " $(IMAGE_REPO)/backend:$(REV) ($(PLATFORMS))" + @LDFLAGS="$(LDFLAGS)" hack/build-image.sh # Kind cluster configuration KIND_CLUSTER ?= kube-bind @@ -455,70 +419,22 @@ kind-load: .PHONY: helm-build-local helm-build-local: ## Build and package Helm charts locally for testing - @echo "Building Helm charts locally..." - @command -v helm >/dev/null 2>&1 || { echo "helm not found. Install from: https://helm.sh/docs/intro/install/"; exit 1; } - - @# Set chart version to semver format for local builds (0.0.0-) - CHART_VERSION="0.0.0-$(REV)"; \ - for chart_dir in deploy/charts/*/; do \ - if [ -f "$${chart_dir}Chart.yaml" ]; then \ - chart_name=$$(basename "$$chart_dir"); \ - echo "Processing chart: $$chart_name"; \ - \ - cp "$${chart_dir}Chart.yaml" "$${chart_dir}Chart.yaml.bak"; \ - sed -i.tmp "s/^version:.*/version: $$CHART_VERSION/" "$${chart_dir}Chart.yaml"; \ - sed -i.tmp "s/^appVersion:.*/appVersion: $$CHART_VERSION/" "$${chart_dir}Chart.yaml"; \ - rm -f "$${chart_dir}Chart.yaml.tmp"; \ - \ - helm package "$$chart_dir" --version "$$CHART_VERSION" --destination ./bin/; \ - echo "Packaged: ./bin/$$chart_name-$$CHART_VERSION.tgz"; \ - \ - mv "$${chart_dir}Chart.yaml.bak" "$${chart_dir}Chart.yaml"; \ - fi; \ - done - @echo "Helm charts built successfully in ./bin/" + @hack/helm-build.sh .PHONY: helm-clean helm-clean: ## Clean up built helm charts rm -f ./bin/*.tgz .PHONY: goreleaser-test -goreleaser-test: ## Test GoReleaser flow locally - @command -v goreleaser >/dev/null 2>&1 || { echo "goreleaser not found. Install from: https://goreleaser.com/install/"; exit 1; } - LDFLAGS="$(LDFLAGS)" goreleaser release --snapshot --clean +goreleaser-test: install-goreleaser ## Test GoReleaser flow locally + LDFLAGS="$(LDFLAGS)" $(GORELEASER) release --snapshot --clean .PHONY: helm-push-local helm-push-local: ## Push Helm charts to IMAGE_REPO registry - @echo "Pushing Helm charts to registry: $(IMAGE_REPO)" - @command -v helm >/dev/null 2>&1 || { echo "helm not found. Install from: https://helm.sh/docs/intro/install/"; exit 1; } - - CHART_VERSION="0.0.0-$(REV)"; \ - export HELM_EXPERIMENTAL_OCI=1; \ - for chart_file in ./bin/*-$$CHART_VERSION.tgz; do \ - if [ -f "$$chart_file" ]; then \ - chart_filename=$$(basename "$$chart_file"); \ - chart_name=$${chart_filename%-$$CHART_VERSION.tgz}; \ - if [[ "$$chart_name" =~ [[:space:]] ]]; then \ - echo "Skipping chart with invalid name: '$$chart_name' (contains spaces)"; \ - continue; \ - fi; \ - echo "Pushing $$chart_name to $(IMAGE_REPO)"; \ - helm push "$$chart_file" "oci://$(IMAGE_REPO)/charts"; \ - echo "Chart available at: oci://$(IMAGE_REPO)/charts/$$chart_name:$$CHART_VERSION"; \ - fi; \ - done + @hack/helm-push.sh .PHONY: helm-test helm-test: helm-build-local ## Test Helm chart installation (dry-run) - @echo "Testing Helm chart installation..." - CHART_VERSION="0.0.0-$(REV)"; \ - for chart_dir in deploy/charts/*/; do \ - if [ -f "$${chart_dir}Chart.yaml" ]; then \ - chart_name=$$(basename "$$chart_dir"); \ - echo "Testing chart: $$chart_name"; \ - helm install test-$$chart_name "./bin/$$chart_name-$$CHART_VERSION.tgz" --dry-run --debug; \ - echo "✓ Chart $$chart_name passes dry-run test"; \ - fi; \ - done + @hack/helm-test.sh include Makefile.venv diff --git a/contrib/kcp/Makefile b/contrib/kcp/Makefile index 78c64259c..bfa19dc1a 100644 --- a/contrib/kcp/Makefile +++ b/contrib/kcp/Makefile @@ -12,44 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -# We need bash for some conditional logic below. -SHELL := /usr/bin/env bash -e +ROOT_DIR = $(abspath ../..) -ROOT_DIR=$(abspath ../..) -GO_INSTALL = $(ROOT_DIR)/hack/go-install.sh -TOOLS_GOBIN_DIR = $(ROOT_DIR)/hack/tools -GOBIN_DIR = $(ROOT_DIR)/bin -PATH := $(GOBIN_DIR):$(TOOLS_GOBIN_DIR):$(PATH) -TMPDIR := $(shell mktemp -d) +export UGET_DIRECTORY := $(ROOT_DIR)/hack/tools +export UGET_CHECKSUMS := $(ROOT_DIR)/hack/tools.checksums +export UGET_VERSIONED_BINARIES = true -# Detect the path used for the install target -ifeq (,$(shell go env GOBIN)) -INSTALL_GOBIN=$(shell go env GOPATH)/bin -else -INSTALL_GOBIN=$(shell go env GOBIN) -endif +KCP_APIGEN_VERSION := v0.28.0 - -KCP_APIGEN_VER := v0.28.0 -KCP_APIGEN_BIN := apigen -KCP_APIGEN_GEN := $(TOOLS_GOBIN_DIR)/$(KCP_APIGEN_BIN)-$(KCP_APIGEN_VER) -export KCP_APIGEN_GEN # so hack scripts can use it - -all: build .PHONY: all +all: build -.PHONY: require-% -require-%: - @if ! command -v $* 1> /dev/null 2>&1; then echo "$* not found in \$$PATH"; exit 1; fi - -# KCP tool installation targets -$(KCP_APIGEN_GEN): - GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) github.com/kcp-dev/kcp/sdk/cmd/apigen $(KCP_APIGEN_BIN) $(KCP_APIGEN_VER) - -# KCP runtime targets -run-kcp: $(KCP) ## Start KCP server - $(KCP) start -v=8 +.PHONY: install-apigen +install-apigen: + @GO_MODULE=true $(ROOT_DIR)/hack/uget.sh github.com/kcp-dev/kcp/sdk/cmd/apigen apigen $(KCP_APIGEN_VERSION) -# Generate KCP API resources -codegen: $(KCP_APIGEN_GEN) ## Generate KCP API resources from CRDs +codegen: ## Generate KCP API resources from CRDs ./hack/update-kcp-codegen.sh diff --git a/contrib/kcp/hack/update-kcp-codegen.sh b/contrib/kcp/hack/update-kcp-codegen.sh index 21fe127ca..964e19111 100755 --- a/contrib/kcp/hack/update-kcp-codegen.sh +++ b/contrib/kcp/hack/update-kcp-codegen.sh @@ -17,16 +17,10 @@ set -o errexit set -o nounset set -o pipefail -set -o xtrace -if [[ -z "${MAKELEVEL:-}" ]]; then - echo 'You must invoke this script via make' - exit 1 -fi +cd "$(dirname "$0")/../../.." -REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd) +APIGEN="$(UGET_PRINT_PATH=absolute make -C contrib/kcp --no-print-directory install-apigen)" # Generate kcp API resources from CRDs -( - ${KCP_APIGEN_GEN} --input-dir "${REPO_ROOT}"/deploy/crd --output-dir "${REPO_ROOT}"/contrib/kcp/deploy/resources -) +"$APIGEN" --input-dir deploy/crd --output-dir contrib/kcp/deploy/resources diff --git a/go.mod b/go.mod index de286536a..1c701de2e 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,6 @@ require ( github.com/gorilla/mux v1.8.1 github.com/gorilla/securecookie v1.1.1 github.com/headzoo/surf v1.0.1 - github.com/kcp-dev/code-generator/v3 v3.0.0-20250707080944-4094fb87e20f github.com/kcp-dev/kcp/pkg/apis v0.11.0 github.com/kcp-dev/kcp/sdk v0.28.1 github.com/kcp-dev/multicluster-provider v0.2.1-0.20251002133408-9a8d21dc2872 @@ -53,7 +52,6 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 sigs.k8s.io/controller-runtime v0.21.0 - sigs.k8s.io/controller-tools v0.16.1 sigs.k8s.io/multicluster-runtime v0.21.0-alpha.9.0.20251002124257-36facc7fbe82 sigs.k8s.io/yaml v1.6.0 ) @@ -67,14 +65,12 @@ require ( github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/bombsimon/logrusr/v3 v3.1.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect - github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect @@ -87,7 +83,6 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/flect v1.0.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect @@ -106,8 +101,6 @@ require ( github.com/kylelemons/godebug v1.1.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.9.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect @@ -121,7 +114,6 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect @@ -163,7 +155,6 @@ require ( google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect diff --git a/go.sum b/go.sum index bca6f432d..a91df585f 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bombsimon/logrusr/v3 v3.1.0 h1:zORbLM943D+hDMGgyjMhSAz/iDz86ZV72qaak/CA0zQ= -github.com/bombsimon/logrusr/v3 v3.1.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -43,8 +41,6 @@ github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= @@ -72,8 +68,6 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= -github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -130,8 +124,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kcp-dev/apimachinery/v2 v2.0.1-0.20250728122101-adbf20db3e51 h1:l38RDS+VUMx9etvyaCgJIZa4nM7FaNevNubWN0kDZY4= github.com/kcp-dev/apimachinery/v2 v2.0.1-0.20250728122101-adbf20db3e51/go.mod h1:rF1jfvUfPjFXs+HV/LN1BtPzAz1bfjJOwVa+hAVfroQ= -github.com/kcp-dev/code-generator/v3 v3.0.0-20250707080944-4094fb87e20f h1:Qfpk7+Y5gwWV8FNY6zu+l5hbKWlFZ6oJqgL67RoCEJg= -github.com/kcp-dev/code-generator/v3 v3.0.0-20250707080944-4094fb87e20f/go.mod h1:1EZhJqiFvXq1N0xKJnJOf8kQ++wuwLkqFGIRVSoVACk= github.com/kcp-dev/kcp/pkg/apis v0.11.0 h1:K6p+tNHNcvfACCPLcHgY0EMLeaIwR1jS491FyLfXMII= github.com/kcp-dev/kcp/pkg/apis v0.11.0/go.mod h1:8cUAmfMJcksauz53UtsLYG8Phhx62rvuCnd/5t/Zihk= github.com/kcp-dev/kcp/sdk v0.28.1 h1:bTtuHVjFRjbwFEqXTPxc1J1JP2Hc3mTYqQ2xfJsi16M= @@ -159,11 +151,6 @@ github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4 github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/martinlindhe/base36 v1.1.1 h1:1F1MZ5MGghBXDZ2KJ3QfxmiydlWOGB8HCEtkap5NkVg= github.com/martinlindhe/base36 v1.1.1/go.mod h1:vMS8PaZ5e/jV9LwFKlm0YLnXl/hpOihiBxKkIoc3g08= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -176,10 +163,6 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= @@ -352,11 +335,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -430,10 +410,6 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -467,8 +443,6 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUo sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= -sigs.k8s.io/controller-tools v0.16.1 h1:gvIsZm+2aimFDIBiDKumR7EBkc+oLxljoUVfRbDI6RI= -sigs.k8s.io/controller-tools v0.16.1/go.mod h1:0I0xqjR65YTfoO12iR+mZR6s6UAVcUARgXRlsu0ljB0= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/kustomize/api v0.20.1 h1:iWP1Ydh3/lmldBnH/S5RXgT98vWYMaTUL1ADcr+Sv7I= diff --git a/hack/build-image.sh b/hack/build-image.sh new file mode 100755 index 000000000..67fce1dee --- /dev/null +++ b/hack/build-image.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Copyright 2025 The Kube Bind Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eu + +echo "Building images locally with tag $REV for platforms: $PLATFORMS" + +command -v docker >/dev/null 2>&1 || { echo "docker not found. Please install Docker"; exit 1; } +docker buildx version >/dev/null 2>&1 || { echo "docker buildx not found. Please enable buildx in Docker"; exit 1; } + +# Create buildx builder if it doesn't exist +docker buildx create --name kube-bind-builder --use 2>/dev/null || docker buildx use kube-bind-builder 2>/dev/null || true +docker buildx inspect --bootstrap >/dev/null 2>&1 + +# Check if building for multiple platforms +if [[ "$PLATFORMS" == *","* ]]; then + echo "Multi-platform build detected. Images will be pushed to registry instead of loaded locally." + LOAD_FLAG="--push" +else + echo "Single platform build. Images will be loaded to local Docker daemon." + LOAD_FLAG="--load" +fi + +echo "Building konnector image..." +docker buildx build \ + --platform $PLATFORMS \ + --build-arg LDFLAGS="$LDFLAGS" \ + -t "$IMAGE_REPO/konnector:$REV" \ + -f Dockerfile.konnector \ + $LOAD_FLAG . + +echo "Building backend image..." +docker buildx build \ + --platform $PLATFORMS \ + --build-arg LDFLAGS="$LDFLAGS" \ + -t "$IMAGE_REPO)/backend:$REV" \ + -f Dockerfile \ + $LOAD_FLAG . + +echo "Successfully built images:" +echo " $IMAGE_REPO/konnector:$REV ($PLATFORMS)" +echo " $IMAGE_REPO/backend:$REV ($PLATFORMS)" diff --git a/hack/go-install.sh b/hack/go-install.sh deleted file mode 100755 index baa7dbc02..000000000 --- a/hack/go-install.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2021 The Kube Bind Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Originally copied from -# https://github.com/kubernetes-sigs/cluster-api-provider-gcp/blob/c26a68b23e9317323d5d37660fe9d29b3d2ff40c/scripts/go_install.sh - -set -o errexit -set -o nounset -set -o pipefail - -if [[ -z "${1:-}" ]]; then - echo "must provide module as first parameter" - exit 1 -fi - -if [[ -z "${2:-}" ]]; then - echo "must provide binary name as second parameter" - exit 1 -fi - -if [[ -z "${3:-}" ]]; then - echo "must provide version as third parameter" - exit 1 -fi - -if [[ -z "${GOBIN:-}" ]]; then - echo "GOBIN is not set. Must set GOBIN to install the bin in a specified directory." - exit 1 -fi - -mkdir -p "${GOBIN}" - -tmp_dir=$(mktemp -d -t goinstall_XXXXXXXXXX) -function clean { - rm -rf "${tmp_dir}" -} -trap clean EXIT - -rm "${GOBIN}/${2}"* > /dev/null 2>&1 || true - -cd "${tmp_dir}" - -# create a new module in the tmp directory -go mod init fake/mod - -# install the golang module specified as the first argument -go install -tags tools "${1}@${3}" -mv "${GOBIN}/${2}" "${GOBIN}/${2}-${3}" -ln -sf "${GOBIN}/${2}-${3}" "${GOBIN}/${2}" \ No newline at end of file diff --git a/hack/helm-build.sh b/hack/helm-build.sh new file mode 100755 index 000000000..fa1a8fd55 --- /dev/null +++ b/hack/helm-build.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# Copyright 2025 The Kube Bind Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eu + +echo "Building Helm charts locally..." + +HELM="$(UGET_PRINT_PATH=absolute make --no-print-directory install-helm)" + +# Set chart version to semver format for local builds (0.0.0-) +CHART_VERSION="0.0.0-$REV"; + +for chart_dir in deploy/charts/*/; do + if [ -f "${chart_dir}Chart.yaml" ]; then + chart_name=$(basename "$chart_dir") + echo "Processing chart: $chart_name" + + cp "${chart_dir}Chart.yaml" "${chart_dir}Chart.yaml.bak" + sed -i.tmp "s/^version:.*/version: $CHART_VERSION/" "${chart_dir}Chart.yaml" + sed -i.tmp "s/^appVersion:.*/appVersion: $CHART_VERSION/" "${chart_dir}Chart.yaml" + rm -f "${chart_dir}Chart.yaml.tmp" + + "$HELM" package "$chart_dir" --version "$CHART_VERSION" --destination ./bin/ + echo "Packaged: ./bin/$chart_name-$CHART_VERSION.tgz" + + mv "${chart_dir}Chart.yaml.bak" "${chart_dir}Chart.yaml" + fi +done + +echo "Helm charts built successfully in ./bin/" diff --git a/hack/helm-push.sh b/hack/helm-push.sh new file mode 100755 index 000000000..e84a70075 --- /dev/null +++ b/hack/helm-push.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Copyright 2025 The Kube Bind Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eu + +echo "Pushing Helm charts to registry: $IMAGE_REPO" + +HELM="$(UGET_PRINT_PATH=absolute make --no-print-directory install-helm)" +CHART_VERSION="0.0.0-$REV" + +export HELM_EXPERIMENTAL_OCI=1 + +for chart_file in ./bin/*-$CHART_VERSION.tgz; do + if [ -f "$chart_file" ]; then + chart_filename=$(basename "$chart_file") + chart_name=${chart_filename%-$CHART_VERSION.tgz} + + if [[ "$chart_name" =~ [[:space:]] ]]; then + echo "Skipping chart with invalid name: '$chart_name' (contains spaces)" + continue + fi + + echo "Pushing $chart_name to $(IMAGE_REPO)" + "$HELM" push "$chart_file" "oci://$(IMAGE_REPO)/charts" + echo "Chart available at: oci://$(IMAGE_REPO)/charts/$chart_name:$CHART_VERSION" + fi +done diff --git a/hack/helm-test.sh b/hack/helm-test.sh new file mode 100755 index 000000000..0b6af9fd5 --- /dev/null +++ b/hack/helm-test.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Copyright 2025 The Kube Bind Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eu + +echo "Testing Helm chart installation..." + +HELM="$(UGET_PRINT_PATH=absolute make --no-print-directory install-helm)" +CHART_VERSION="0.0.0-$REV" + +for chart_dir in deploy/charts/*/; do + if [ -f "${chart_dir}Chart.yaml" ]; then + chart_name=$(basename "$chart_dir") + echo "Testing chart: $chart_name" + "$HELM" install test-$chart_name "./bin/$chart_name-$CHART_VERSION.tgz" --dry-run --debug + echo "✓ Chart $chart_name passes dry-run test" + fi +done diff --git a/hack/tools.checksums b/hack/tools.checksums new file mode 100644 index 000000000..d13423a16 --- /dev/null +++ b/hack/tools.checksums @@ -0,0 +1,9 @@ +golangci-lint|GOARCH=amd64;GOOS=linux|7009324a8aad93c1f84dce1c3cf61181bdd6b68e5f1b8b5d6971662258255050 +golangci-lint|GOARCH=arm64;GOOS=linux|c51ff5b21be688b043baea44de7dd855cf07b855c14f0de405bfaf922b1d7634 +goreleaser|ARCH=x86_64;OS=Linux|8de4a7d97d9b2b62e8186bcd28f7a203ba55ecfaaa4329e14264d3235095faed +gotestsum|GOARCH=amd64;GOOS=linux|ee25248e6f5073cad0b7a712c97ed473adb7420f7eefad534177de0113a8a505 +gotestsum|GOARCH=arm64;GOOS=linux|7a5e7f8cb5e2126be563b7c7182cc4522fbc65408a99df82d156d30e997b8705 +helm|GOARCH=amd64;GOOS=linux|c153fd9c1173f39aefe8e9aa9f00fd3daf6b40c8ea01e94a0d2f2c1787fc60e0 +kcp|GOARCH=amd64;GOOS=linux|41149ef78d2092243b14164a363dfdacc3e0f2bece8c00b715457c21c423a80b +kcp|GOARCH=arm64;GOOS=linux|bd2412179c1e3294dc81641630e0a2184892d4b45c6ef5bed7dc15fbd2c333fe +verify_boilerplate.py||6928a807e2ffc2e6902de705ce7a7cddbbbf5ef61a43901432c4f4551b4e9a7b diff --git a/hack/tools.go b/hack/tools.go index e35a8ffa8..e996264ca 100644 --- a/hack/tools.go +++ b/hack/tools.go @@ -19,11 +19,5 @@ limitations under the License. package tools import ( - _ "github.com/kcp-dev/code-generator/v3/cmd/cluster-client-gen" - _ "github.com/kcp-dev/kcp/sdk/cmd/apigen" _ "k8s.io/code-generator" - _ "k8s.io/code-generator/cmd/conversion-gen" - _ "k8s.io/code-generator/cmd/deepcopy-gen" - _ "k8s.io/code-generator/cmd/defaulter-gen" - _ "sigs.k8s.io/controller-tools/cmd/controller-gen" ) diff --git a/hack/uget.sh b/hack/uget.sh new file mode 100755 index 000000000..4f13fefcc --- /dev/null +++ b/hack/uget.sh @@ -0,0 +1,702 @@ +#!/bin/sh + +# SPDX-FileCopyrightText: 2025 Christoph Mewes, https://codeberg.org/xrstf/uget +# SPDX-License-Identifier: MIT +# +# µget 0.5.0 – your friendly downloader +# ------------------------------------- +# +# µget can download software as binaries, archives or Go modules. +# +# Usage: ./uget.sh URL_PATTERN BINARY_NAME VERSION [EXTRACT_PATTERN=**/$BINARY_NAME] + +set -eu + +############################################################################### +# Configuration + +# µget supports a large range of environment variables to customize its +# behaviour. Global configuration settings are prefixed with UGET_, settings +# usually meant for a single tool only have no prefix (like GO_MODULE). + +# GO_MODULE can be set to true to create a dummy Go module, add the given +# URL and version as a dependency and then go build the desired binary. Note +# that Go modules do not use checksums by default, see $UGET_GO_CHECKSUMS. +GO_MODULE=${GO_MODULE:-false} + +# GO_EXTRA_DEPS is an optional, space-separated list of additional dependencies +# that should be added to the temporary Go module before the actual dependency +# is added and built. This can be used to override/upgrade individual dependencies +# when needed. +GO_EXTRA_DEPS="${GO_EXTRA_DEPS:-}" + +# UNCOMPRESSED can be set to true if the downloaded file is not an archive, +# but the binary itself and doesn't need decompressing. +UNCOMPRESSED=${UNCOMPRESSED:-false} + +# UGET_UPDATE can be set to true when the VERSION parameter of a program has +# been updated and you want µget to update all known variants (based on the +# checksums file) before installing the correct variant for the current system. +# When UGET_CHECKSUMS is not in use, this variable has no effect. +# Use UGET_UPDATE_ONLY if you want to just update the checksums without also +# installing the binary. +UGET_UPDATE=${UGET_UPDATE:-false} + +# UGET_UPDATE_ONLY is like UGET_UPDATE, but does not install the binary on +# the current system (i.e. it only touches the checksum file). +UGET_UPDATE_ONLY=${UGET_UPDATE_ONLY:-false} + +# UGET_DIRECTORY is where downloaded binaries will be placed. +UGET_DIRECTORY="${UGET_DIRECTORY:-_tools}" + +# UGET_CHECKSUMS is an optional path to a checksum file that µget should use to +# ensure subsequent downloads match previously known checksums to prevent +# tampering on the server side. +UGET_CHECKSUMS="${UGET_CHECKSUMS:-}" + +# UGET_VERSIONED_BINARIES can be set to true to append the binary's version to +# its filename, leading to final paths like "_tools/mytool-v1.2.3". This can +# help when µget is being used in Makefiles to improve staleness detection. +# Note that µget never deletes any installed binaries, so enabling this can +# lead to leftover binaries that you can cleanup at your own convenience. +UGET_VERSIONED_BINARIES=${UGET_VERSIONED_BINARIES:-false} + +# UGET_TEMPDIR is the root directory to use when creating new temporary dirs. +UGET_TEMPDIR="${UGET_TEMPDIR:-/tmp}" + +# UGET_CACHE is an optional path to a directory where binaries are stored/read +# from instead of being downloaded from the internet. This can be useful if you +# have many projects using µget and do not want to re-download the same binary +# for all of them. This does not apply for Go modules since those are already +# effectively cached by Go itself. +UGET_CACHE="${UGET_CACHE:-}" + +# UGET_CACHE_SYMLINK can be set to true to create a symlink between the cached +# file and the local copy in $UGET_DIRECTORY. If left on false, µget will instead +# copy the file from the cache. +UGET_CACHE_SYMLINK=${UGET_CACHE_SYMLINK:-false} + +# UGET_PRINT_PATH can be set to "relative" to make µget only omit log output +# and only print the relative path to the binary, and set to "absolute" to +# output the absolute path. +UGET_PRINT_PATH="${UGET_PRINT_PATH:-no}" + +# UGET_HASHFUNC is the hashing function used to calculate file checksums. The +# output of this program is processed with awk to only print the first column. +UGET_HASHFUNC="${UGET_HASHFUNC:-sha256sum}" + +# UGET_GO_BUILD_CMD overwrites the default call to "go build" when installing +# a Go module. Use this to inject custom Go flags or toolchains. +# The given command is called with "-o BINARY_NAME MODULE_URL" with the pwd +# being inside a fake module that depends on the given module. +UGET_GO_BUILD_CMD="${UGET_GO_BUILD_CMD:-go build}" + +# UGET_GO_CHECKSUMS can be set to true to force checksums even for Go modules. +# This is disabled by default because the exact binaries being built depend on +# a lot of factors and usually it's a hassle to ensure everyone in a project +# has the *exact* same build environment. Go modules already make use of Google's +# GOSUMDB and should be "safe enough" by default with µget checksums. +UGET_GO_CHECKSUMS=${UGET_GO_CHECKSUMS:-false} + +############################################################################### +# Function library + +uget_mktemp() { + set -e + # --tmpdir does not work on MacOS + mktemp -d -p "$ABS_UGET_TEMPDIR" +} + +uget_log() { + if [ "$UGET_PRINT_PATH" = "no" ]; then + echo "$@" >&2 + fi +} + +uget_error() { + echo "$@" >&2 +} + +uget_lowercase() { + set -e + cat | tr '[:upper:]' '[:lower:]' +} + +uget_checksum_enabled() { + set -e + [ -n "$UGET_CHECKSUMS" ] +} + +uget_cache_enabled() { + set -e + [ -n "$UGET_CACHE" ] +} + +uget_checksum_check() { + set -e + + local kvString="$1" + local downloadedBinary="$2" + + if ! uget_checksum_enabled; then return; fi + + local newChecksum + newChecksum="$(uget_checksum_calculate "$downloadedBinary")" + + local oldChecksum + oldChecksum="$(uget_checksum_read "$kvString")" + + if [ -n "$oldChecksum" ] && [ "$oldChecksum" != "$newChecksum" ]; then + uget_error + uget_error " *************************************************************************" + uget_error " SECURITY ERROR" + uget_error + uget_error " The downloaded file $downloadedBinary does not have the expected checksum." + uget_error + uget_error " Expected: $oldChecksum" + uget_error " Actual : $newChecksum" + uget_error + uget_error " If you are updating $IDENTIFIER, this error is expected." + uget_error " Re-run this command with the environment variable UGET_UPDATE=true to make" + uget_error " µget update the checksums for all known variants of $IDENTIFIER." + uget_error " Use UGET_UPDATE_ONLY=true if you want to just update the checksums and not" + uget_error " install the given binary on this machine." + uget_error " *************************************************************************" + uget_error + + return 1 + fi + + if [ -z "$oldChecksum" ]; then + uget_checksum_write "$kvString" "$newChecksum" + fi +} + +uget_checksum_read() { + set -e + + local kvString="$1" + + if [ -f "$UGET_CHECKSUMS" ]; then + awk -F'|' -v "binary=$IDENTIFIER" -v "kv=$kvString" '{ if ($1 == binary && $2 == kv) print $3 }' "$UGET_CHECKSUMS" + fi +} + +uget_checksum_calculate() { + set -e + "$UGET_HASHFUNC" "$1" | awk '{ print $1 }' +} + +# hash_string includes a trailing newline in the hashed data +# (because of echo), but since *all* hashes contain it, it +# doesn't matter. +uget_hash_string() { + set -e + echo "$1" | "$UGET_HASHFUNC" | awk '{ print $1 }' +} + +uget_checksum_write() { + set -e + + local kvString="$1" + local checksum="$2" + + if [ -f "$UGET_CHECKSUMS" ]; then + local tempDir + tempDir="$(uget_mktemp)" + + # use awk to drop any existing hash for this binary/keyvalue combo + # (for better readability, do not invert the condition here); + # checking for NF (number of fields) to drop empty lines + awk \ + -F'|' -v "binary=$IDENTIFIER" -v "kv=$kvString" \ + '{ if (NF == 0 || ($1 == binary && $2 == kv)) {} else print }' \ + "$UGET_CHECKSUMS" > "$tempDir/checksums.txt" + + # add our new checksum + echo "$IDENTIFIER|$kvString|$checksum" >> "$tempDir/checksums.txt" + + # sort the file because it looks nicer and prevents ugly git diffs + sort "$tempDir/checksums.txt" > "$UGET_CHECKSUMS" + + rm -rf -- "$tempDir" + else + # start a new file + echo "$IDENTIFIER|$kvString|$checksum" > "$UGET_CHECKSUMS" + fi +} + +uget_begins_with() { + case $2 in + "$1"*) true ;; + *) false ;; + esac +} + +uget_trim_env_prefix() { + set -e + + echo "${1#ENV:}" +} + +uget_url_placeholder() { + set -e + + # trim potential "ENV:" prefix + local envName + envName="$(uget_trim_env_prefix "$1")" + + if [ "$envName" != "$1" ]; then + if ! printenv "$envName"; then + uget_error "Unexpected placeholder, environment variable $envName is not set." + return 1 + fi + else + # built-in, default placeholders + case "$1" in + GOARCH) go env GOARCH ;; + GOOS) go env GOOS ;; + UARCH) uname -m | uget_lowercase ;; + UOS) uname -s | uget_lowercase ;; + *) uget_error "Unexpected placeholder $1."; return 1 ;; + esac + fi +} + +# valueFromPair returns "foo" for "myvalue=foo;myothervalue=bar" when called with +# "myvalue" as the key. +uget_url_valueFromPair() { + set -e + + local kvString="$1" + local key="$2" + + # adding semicolons makes matching full keys easier + echo ";$kvString;" | sed -E "s/.*;$key=([^;]+).*/\\1/" +} + +uget_url_setKeyInPairs() { + set -e + + local kvString="$1" + local key="$2" + local value="$3" + + # first take the existing pairs and turn it into a multiline string; then + # awk out the existing pair for $key, + # then add a new pair and sort it all together, strip empty lines in case + # kvstring as empty, then join the multiple lines back into a single line + # and drop the trailing ';' + ( + echo "$kvString" | tr ';' "\n" | awk -F'=' -v "key=$key" '{ if ($1 != key) print }' + echo "$key=$value" + ) | sort | sed '/^[[:space:]]*$/d' | tr "\n" ';' | sed 's/;$//' +} + +uget_url_findPlaceholders() { + set -e + + # match all {...}, + # then sort and return only unique values (no need to replace the + # same placeholder multiple times) (this is important to allow for consistent + # matches when awk'ing through the checksum file), + # then remove braces and + # finally turn into a singleline string + echo "$1" | + grep -oE '\{(ENV:)?[A-Z0-9_]+\}' | + sort -u | + tr -d '{}' | + awk '{printf("%s ", $0)}' +} + +# replaceLive() use live system-data to replace placeholders in the given pattern. +# It returns a string of form "KVSTRING|URL". +uget_url_replaceLive() { + set -e + + local urlPattern="$1" + local usedPlaceholders="" + + for placeholder in $(uget_url_findPlaceholders "$urlPattern"); do + # version is treated specially + [ "$placeholder" = "VERSION" ] && continue + + local replacement + replacement="$(uget_url_placeholder "$placeholder")" + urlPattern="$(echo "$urlPattern" | sed "s|{$placeholder}|$replacement|g")" + + # remember this placeholder and its value + placeholder="$(uget_trim_env_prefix "$placeholder")" + usedPlaceholders="$usedPlaceholders;$placeholder=$replacement" + done + + # trim leading ";" + usedPlaceholders="$(echo "$usedPlaceholders" | sed 's/^;//')" + + echo "$usedPlaceholders|$urlPattern" +} + +# replaceWithArgs() does not ask the current system for the values when replacing +# a placeholder, but uses a given key-value pair string as the source. It also +# only returns the resulting string, since the used placeholders are known to +# the caller already. +uget_url_replaceWithArgs() { + set -e + + local urlPattern="$1" + local kvString="$2" + + for placeholder in $(uget_url_findPlaceholders "$urlPattern"); do + # version is treated specially + [ "$placeholder" = "VERSION" ] && continue + + placeholder="$(uget_trim_env_prefix "$placeholder")" + + local replacement + replacement="$(uget_url_valueFromPair "$kvString" "$placeholder")" + if [ -z "$replacement" ]; then + uget_error "Found no replacement string for placeholder $placeholder." + exit 1 + fi + + urlPattern="$(echo "$urlPattern" | sed "s|{$placeholder}|$replacement|g")" + done + + echo "$urlPattern" +} + +# returns "KVSTRING URL" +uget_url_build() { + set -e + + local kvString="${1:-}" + local pattern + + if [ -z "$kvString" ]; then + local result + result="$(uget_url_replaceLive "$URL_PATTERN")" + kvString="$(echo "$result" | cut -d'|' -f1)" + pattern="$(echo "$result" | cut -d'|' -f2)" + else + pattern="$(uget_url_replaceWithArgs "$URL_PATTERN" "$kvString")" + fi + + pattern="$(echo "$pattern" | sed "s|{VERSION}|$VERSION|g")" + + echo "$kvString|$pattern" +} + +# uget_http_download() uses either curl or wget to download the given URL into +# the current directory. +uget_http_download() { + set -e + + local url="$1" + + if command -v curl >/dev/null 2>&1; then + curl --fail -LO "$url" + elif command -v wget >/dev/null 2>&1; then + wget "$url" + else + uget_error "Neither curl nor wget are available." + return 1 + fi +} + +# uget_go_install creates a temporary Go module, adds the given URL as a +# dependency and then builds $BINARY. +uget_go_install() { + set -e + + local destinationDir="$1" + local kvString="$2" + local url="$3" + + # make sure GOARCH and GOOS will be set correctly + local os + local arch + os="$(uget_url_valueFromPair "$kvString" "GOOS")" + arch="$(uget_url_valueFromPair "$kvString" "GOARCH")" + + # since we crosscompile, we cannot do "GOBIN=(somewhere) go install url@version", + # because Go considers this to be dangerous behaviour: + # https://github.com/golang/go/issues/57485 + # Instead we create a dummy module and use the desired program as a dependency, + # *then* we're allowed to crosscompile it anywhere using "go build". Go figure. + + go mod init temp 2>/dev/null + + if [ -n "$GO_EXTRA_DEPS" ]; then + for dependency in $GO_EXTRA_DEPS; do + go get "$dependency" + done + fi + + go get "$url@$VERSION" + + local tmpFilename="__tmp.bin" + + # go build command is meant to be expanded + # shellcheck disable=SC2086 + GOFLAGS=-trimpath GOARCH="$arch" GOOS="$os" $UGET_GO_BUILD_CMD -o "$tmpFilename" "$url" + + mv "$tmpFilename" "$destinationDir/$BINARY" +} + +# uget_extract_archive extracts a downloaded archive and moves the one interesting +# file out of it. +uget_extract_archive() { + set -e + + local destinationDir="$1" + local archive="$2" + + if ! $UNCOMPRESSED; then + case "$archive" in + *.tar.gz | *.tgz) + tar xzf "$archive" + ;; + *.tar.bz2 | *.tbz2) + tar xjf "$archive" + ;; + *.tar.xz | *.txz) + tar xJf "$archive" + ;; + *.zip) + unzip "$archive" + ;; + *) + uget_error "Unknown file type: $archive" + return 1 + esac + fi + + # pattern is explicitly meant to be interpreted by the shell + # shellcheck disable=SC2086 + mv $BINARY_PATTERN "$destinationDir/$BINARY" + chmod +x "$destinationDir/$BINARY" +} + +# uget_download performs the actual download or reads a binary +# from the configured cache (if any), and finally places it +# in a given directory. +uget_download() { + set -e + + local destinationDir="$1" + local kvString="$2" + local url="$3" + + local startDir + startDir="$(pwd)" + + local tempDir + tempDir="$(uget_mktemp)" + + cd "$tempDir" + + if $GO_MODULE; then + uget_go_install "$destinationDir" "$kvString" "$url" + else + local urlHash + urlHash="$(uget_hash_string "$url")" + + cacheFile="$UGET_CACHE/$IDENTIFIER-$VERSION-$urlHash" + + if uget_cache_enabled && [ -f "$cacheFile" ]; then + if $UGET_CACHE_SYMLINK; then + ln -s "$cacheFile" "$destinationDir/$BINARY" + uget_log "Symlinked $BINARY from µget cache." + else + cp "$cacheFile" "$destinationDir/$BINARY" + uget_log "Copied $BINARY from µget cache." + fi + else + uget_http_download "$url" + + local archive + archive="$(ls)" + + uget_extract_archive "$destinationDir" "$archive" + + if uget_cache_enabled; then + cp "$destinationDir/$BINARY" "$cacheFile" + fi + fi + fi + + cd "$startDir" + rm -rf -- "$tempDir" +} + +# ready() checks if the desired binary already exists in the desired version. +uget_ready() { + local fullFinalPath="$ABS_UGET_DIRECTORY/$BINARY" + if ! [ -f "$fullFinalPath" ]; then + return 1 + fi + + # skip further checks if we're using versioned binaries + if $UGET_VERSIONED_BINARIES; then + return 0 + fi + + local versionFile="$fullFinalPath.version" + [ -f "$versionFile" ] && [ "$VERSION" = "$(cat "$versionFile")" ] +} + +# install() downloads the binary, checks the checksum and places it in UGET_DIRECTORY. +uget_install() { + set -e + + local kvString="$1" + local url="$2" + local fullFinalPath="$ABS_UGET_DIRECTORY/$BINARY" + local versionFile="$fullFinalPath.version" + + local startDir + startDir="$(pwd)" + + local tempDir + tempDir="$(uget_mktemp)" + + uget_log "Downloading $IDENTIFIER version $VERSION ..." + uget_download "$tempDir" "$kvString" "$url" + + local fullTempBinary="$tempDir/$BINARY" + uget_checksum_check "$kvString" "$fullTempBinary" + + # if everything is fine, place the binary in its final location + mv "$fullTempBinary" "$fullFinalPath" + + if ! $UGET_VERSIONED_BINARIES; then + echo "$VERSION" > "$versionFile" + fi + + uget_log "Installed at $UGET_DIRECTORY/$BINARY." + + cd "$startDir" + rm -rf -- "$tempDir" +} + +# update() downloads the binary, updates the checksums and discards the binary. +uget_update() { + set -e + + local kvString="$1" + local url="$2" + + local startDir + startDir="$(pwd)" + + local tempDir + tempDir="$(uget_mktemp)" + + uget_log " ~> $kvString" + uget_download "$tempDir" "$kvString" "$url" + + local fullBinaryPath="$tempDir/$BINARY" + + local checksum + checksum="$(uget_checksum_calculate "$fullBinaryPath")" + + uget_checksum_write "$kvString" "$checksum" + + cd "$startDir" + rm -rf -- "$tempDir" +} + +############################################################################### +# General Setup Logic + +# get CLI flags +export URL_PATTERN="$1" +export IDENTIFIER="$2" +export VERSION="$3" +BINARY_PATTERN="${4:-**/$IDENTIFIER}" + +export BINARY="$IDENTIFIER" +if $UGET_VERSIONED_BINARIES; then + BINARY="$IDENTIFIER-$VERSION" +fi + +# ensure target directory exists +mkdir -p "$UGET_DIRECTORY" "$UGET_TEMPDIR" + +ABS_UGET_DIRECTORY="$(realpath "$UGET_DIRECTORY")" +ABS_UGET_TEMPDIR="$(realpath "$UGET_TEMPDIR")" + +if uget_cache_enabled; then + mkdir -p "$UGET_CACHE" + UGET_CACHE="$(realpath "$UGET_CACHE")" +fi + +if $GO_MODULE && ! $UGET_GO_CHECKSUMS; then + UGET_CHECKSUMS="" +fi + +if uget_checksum_enabled; then + touch "$UGET_CHECKSUMS" + UGET_CHECKSUMS="$(realpath "$UGET_CHECKSUMS")" +else + if $GO_MODULE; then + if $UGET_UPDATE || $UGET_UPDATE_ONLY; then + uget_error "Checksums are disabled for Go modules, cannot update $IDENTIFIER checksums." + # This is not an error because in complex Makefiles, there might be 3 binaries required + # for one make target, and if one of them is a Go module and you have no direct way + # to just update a single binary, then running "UGET_UPDATE make complex-task" would + # fail at the Go module. It's simply more convenient to just warn and move on to the next + # binary. + fi + fi + + UGET_UPDATE=false + UGET_UPDATE_ONLY=false +fi + +############################################################################### +# Main application logic + +# When in update-only mode, we do not download the binary for the current system +# only, but instead for all known variants based on the checksums file, +# recalculate the checksums and then discard the temporary binaries. Otherwise +# after updating the checksums we continue with the regular install logic. + +if $UGET_UPDATE || $UGET_UPDATE_ONLY; then + uget_log "Updating checksums for $IDENTIFIER ..." + + # Find and process all known variants... + awk -F'|' -v "binary=$IDENTIFIER" '{ if ($1 == binary) print $2 }' "$UGET_CHECKSUMS" | while IFS= read -r kvString; do + result="$(uget_url_build "$kvString")" + url="$(echo "$result" | cut -d'|' -f2)" + + # download binary into tempdir, update checksums, but then delete it again + uget_update "$kvString" "$url" + done + + uget_log "All checksums were updated." +fi + +if ! $UGET_UPDATE_ONLY; then + if ! uget_ready; then + # Replace placeholders in the URL with system-specific data, like arch or OS + result="$(uget_url_build)" + kvString="$(echo "$result" | cut -d'|' -f1)" + url="$(echo "$result" | cut -d'|' -f2)" + + # Go modules usually do not have arch/os infos in their module names, but + # the resulting binary still depends on the local system. To support checksums + # for different machines, we always assume GOARCH and GOOS are "used placeholders". + if $GO_MODULE; then + kvString="$(uget_url_setKeyInPairs "$kvString" "GOARCH" "$(uget_url_placeholder GOARCH)")" + kvString="$(uget_url_setKeyInPairs "$kvString" "GOOS" "$(uget_url_placeholder GOOS)")" + fi + + uget_install "$kvString" "$url" + fi + + case "$UGET_PRINT_PATH" in + absolute) echo "$ABS_UGET_DIRECTORY/$BINARY" ;; + relative) echo "$UGET_DIRECTORY/$BINARY" ;; + esac +fi diff --git a/hack/update-codegen-clients.sh b/hack/update-codegen-clients.sh index 0f3420e4c..e4fc49da4 100755 --- a/hack/update-codegen-clients.sh +++ b/hack/update-codegen-clients.sh @@ -17,13 +17,10 @@ set -o errexit set -o nounset set -o pipefail -set -o xtrace -export GOPATH=$(go env GOPATH) - -SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; go list -f '{{.Dir}}' -m k8s.io/code-generator)} +cd "$(dirname "$0")/.." +CODEGEN_PKG="${CODEGEN_PKG:-$(go list -f '{{.Dir}}' -m k8s.io/code-generator)}" source "${CODEGEN_PKG}/kube_codegen.sh" pushd sdk diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index e39b870d7..0d697902d 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -17,48 +17,47 @@ set -o errexit set -o nounset set -o pipefail -set -o xtrace -if [[ -z "${MAKELEVEL:-}" ]]; then - echo 'You must invoke this script via make' - exit 1 -fi +cd "$(dirname "$0")/.." -"$(dirname "${BASH_SOURCE[0]}")/update-codegen-clients.sh" -REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +CONTROLLER_GEN="$(UGET_PRINT_PATH=absolute make --no-print-directory install-controller-gen)" +YAML_PATCH="$(UGET_PRINT_PATH=absolute make --no-print-directory install-yaml-patch)" # Update generated CRD YAML -cd sdk/apis -../../${CONTROLLER_GEN} \ - crd \ - rbac:roleName=manager-role \ - webhook \ - paths="./..." \ - output:crd:artifacts:config=../../deploy/crd - -../../${CONTROLLER_GEN} \ - crd \ - rbac:roleName=manager-role \ - webhook \ - paths="./..." \ - output:crd:artifacts:config=../../deploy/charts/backend/crds - -# Generate RBAC manifests for Helm chart from backend controllers -../../${CONTROLLER_GEN} \ - rbac:roleName=kube-bind-role \ - paths="../../backend/controllers/..." \ - output:rbac:artifacts:config=../../deploy/charts/backend/templates - -cd - - -cd deploy/crd -for CRD in *.yaml; do - if [ -f "../patches/${CRD}-patch" ]; then - echo "Applying ${CRD}-patch" - ../../${YAML_PATCH} -o "../patches/${CRD}-patch" < "${CRD}" > "${CRD}.patched" - mv "${CRD}.patched" "${CRD}" - fi -done - -cd ../../contrib/kcp -make codegen +( + cd sdk/apis + "$CONTROLLER_GEN" \ + crd \ + rbac:roleName=manager-role \ + webhook \ + paths="./..." \ + output:crd:artifacts:config=../../deploy/crd + + "$CONTROLLER_GEN" \ + crd \ + rbac:roleName=manager-role \ + webhook \ + paths="./..." \ + output:crd:artifacts:config=../../deploy/charts/backend/crds + + # Generate RBAC manifests for Helm chart from backend controllers + "$CONTROLLER_GEN" \ + rbac:roleName=kube-bind-role \ + paths="../../backend/controllers/..." \ + output:rbac:artifacts:config=../../deploy/charts/backend/templates +) + +( + cd deploy/crd + for CRD in *.yaml; do + if [ -f "../patches/${CRD}-patch" ]; then + echo "Applying ${CRD}-patch" + "$YAML_PATCH" -o "../patches/${CRD}-patch" < "${CRD}" > "${CRD}.patched" + mv "${CRD}.patched" "${CRD}" + fi + done +) + +( + make -C contrib/kcp codegen +)