Skip to content

Commit a8b23ca

Browse files
✨ feat: Automate ENVTEST version from go.mod (kubernetes-sigs#4401)
feat: Automate ENVTEST version from go.mod Remove the need to manually bump release branches in the Makefile by deriving the ENVTEST version directly from Kubernetes versions specified in go.mod.
1 parent 503eb5a commit a8b23ca

File tree

39 files changed

+894
-293
lines changed

39 files changed

+894
-293
lines changed

docs/book/src/cronjob-tutorial/testdata/project/Makefile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Image URL to use all building/pushing image targets
22
IMG ?= controller:latest
3-
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
4-
ENVTEST_K8S_VERSION = 1.31.0
53

64
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
75
ifeq (,$(shell go env GOBIN))
@@ -64,7 +62,7 @@ vet: ## Run go vet against code.
6462
go vet ./...
6563

6664
.PHONY: test
67-
test: manifests generate fmt vet envtest ## Run tests.
65+
test: manifests generate fmt vet setup-envtest ## Run tests.
6866
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
6967

7068
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
@@ -176,7 +174,10 @@ GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
176174
## Tool Versions
177175
KUSTOMIZE_VERSION ?= v5.5.0
178176
CONTROLLER_TOOLS_VERSION ?= v0.16.5
179-
ENVTEST_VERSION ?= release-0.19
177+
#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20)
178+
ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
179+
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
180+
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
180181
GOLANGCI_LINT_VERSION ?= v1.61.0
181182

182183
.PHONY: kustomize
@@ -189,6 +190,14 @@ controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessar
189190
$(CONTROLLER_GEN): $(LOCALBIN)
190191
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
191192

193+
.PHONY: setup-envtest
194+
setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory.
195+
@echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..."
196+
@$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path || { \
197+
echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \
198+
exit 1; \
199+
}
200+
192201
.PHONY: envtest
193202
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
194203
$(ENVTEST): $(LOCALBIN)

docs/book/src/cronjob-tutorial/testdata/project/internal/controller/suite_test.go

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ package controller
2727

2828
import (
2929
"context"
30-
"fmt"
30+
"os"
3131
"path/filepath"
32-
"runtime"
3332
"testing"
3433

3534
ctrl "sigs.k8s.io/controller-runtime"
@@ -83,19 +82,16 @@ var _ = BeforeSuite(func() {
8382
testEnv = &envtest.Environment{
8483
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
8584
ErrorIfCRDPathMissing: true,
86-
87-
// The BinaryAssetsDirectory is only required if you want to run the tests directly
88-
// without call the makefile target test. If not informed it will look for the
89-
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
90-
// Note that you must have the required binaries setup under the bin directory to perform
91-
// the tests directly. When we run make test it will be setup and used automatically.
92-
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
93-
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
9485
}
9586

87+
// Retrieve the first found binary directory to allow running tests from IDEs
88+
if getFirstFoundEnvTestBinaryDir() != "" {
89+
testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir()
90+
}
9691
/*
9792
Then, we start the envtest cluster.
9893
*/
94+
9995
var err error
10096
// cfg is defined in this file globally.
10197
cfg, err = testEnv.Start()
@@ -178,3 +174,26 @@ var _ = AfterSuite(func() {
178174
/*
179175
Now that you have your controller running on a test cluster and a client ready to perform operations on your CronJob, we can start writing integration tests!
180176
*/
177+
178+
// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path.
179+
// ENVTEST-based tests depend on specific binaries, usually located in paths set by
180+
// controller-runtime. When running tests directly (e.g., via an IDE) without using
181+
// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured.
182+
//
183+
// This function streamlines the process by finding the required binaries, similar to
184+
// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are
185+
// properly set up, run 'make setup-envtest' beforehand.
186+
func getFirstFoundEnvTestBinaryDir() string {
187+
basePath := filepath.Join("..", "..", "bin", "k8s")
188+
entries, err := os.ReadDir(basePath)
189+
if err != nil {
190+
logf.Log.Error(err, "Failed to read directory", "path", basePath)
191+
return ""
192+
}
193+
for _, entry := range entries {
194+
if entry.IsDir() {
195+
return filepath.Join(basePath, entry.Name())
196+
}
197+
}
198+
return ""
199+
}

docs/book/src/cronjob-tutorial/testdata/project/internal/webhook/v1/webhook_suite_test.go

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import (
2121
"crypto/tls"
2222
"fmt"
2323
"net"
24+
"os"
2425
"path/filepath"
25-
"runtime"
2626
"testing"
2727
"time"
2828

@@ -72,19 +72,16 @@ var _ = BeforeSuite(func() {
7272
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")},
7373
ErrorIfCRDPathMissing: false,
7474

75-
// The BinaryAssetsDirectory is only required if you want to run the tests directly
76-
// without call the makefile target test. If not informed it will look for the
77-
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
78-
// Note that you must have the required binaries setup under the bin directory to perform
79-
// the tests directly. When we run make test it will be setup and used automatically.
80-
BinaryAssetsDirectory: filepath.Join("..", "..", "..", "bin", "k8s",
81-
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
82-
8375
WebhookInstallOptions: envtest.WebhookInstallOptions{
8476
Paths: []string{filepath.Join("..", "..", "..", "config", "webhook")},
8577
},
8678
}
8779

80+
// Retrieve the first found binary directory to allow running tests from IDEs
81+
if getFirstFoundEnvTestBinaryDir() != "" {
82+
testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir()
83+
}
84+
8885
var err error
8986
// cfg is defined in this file globally.
9087
cfg, err = testEnv.Start()
@@ -148,3 +145,26 @@ var _ = AfterSuite(func() {
148145
err := testEnv.Stop()
149146
Expect(err).NotTo(HaveOccurred())
150147
})
148+
149+
// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path.
150+
// ENVTEST-based tests depend on specific binaries, usually located in paths set by
151+
// controller-runtime. When running tests directly (e.g., via an IDE) without using
152+
// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured.
153+
//
154+
// This function streamlines the process by finding the required binaries, similar to
155+
// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are
156+
// properly set up, run 'make setup-envtest' beforehand.
157+
func getFirstFoundEnvTestBinaryDir() string {
158+
basePath := filepath.Join("..", "..", "..", "bin", "k8s")
159+
entries, err := os.ReadDir(basePath)
160+
if err != nil {
161+
logf.Log.Error(err, "Failed to read directory", "path", basePath)
162+
return ""
163+
}
164+
for _, entry := range entries {
165+
if entry.IsDir() {
166+
return filepath.Join(basePath, entry.Name())
167+
}
168+
}
169+
return ""
170+
}

docs/book/src/getting-started/testdata/project/Makefile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Image URL to use all building/pushing image targets
22
IMG ?= controller:latest
3-
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
4-
ENVTEST_K8S_VERSION = 1.31.0
53

64
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
75
ifeq (,$(shell go env GOBIN))
@@ -60,7 +58,7 @@ vet: ## Run go vet against code.
6058
go vet ./...
6159

6260
.PHONY: test
63-
test: manifests generate fmt vet envtest ## Run tests.
61+
test: manifests generate fmt vet setup-envtest ## Run tests.
6462
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
6563

6664
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
@@ -172,7 +170,10 @@ GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
172170
## Tool Versions
173171
KUSTOMIZE_VERSION ?= v5.5.0
174172
CONTROLLER_TOOLS_VERSION ?= v0.16.5
175-
ENVTEST_VERSION ?= release-0.19
173+
#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20)
174+
ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
175+
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
176+
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
176177
GOLANGCI_LINT_VERSION ?= v1.61.0
177178

178179
.PHONY: kustomize
@@ -185,6 +186,14 @@ controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessar
185186
$(CONTROLLER_GEN): $(LOCALBIN)
186187
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
187188

189+
.PHONY: setup-envtest
190+
setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory.
191+
@echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..."
192+
@$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path || { \
193+
echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \
194+
exit 1; \
195+
}
196+
188197
.PHONY: envtest
189198
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
190199
$(ENVTEST): $(LOCALBIN)

docs/book/src/getting-started/testdata/project/internal/controller/suite_test.go

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@ package controller
1818

1919
import (
2020
"context"
21-
"fmt"
21+
"os"
2222
"path/filepath"
23-
"runtime"
2423
"testing"
2524

2625
. "github.com/onsi/ginkgo/v2"
@@ -61,14 +60,11 @@ var _ = BeforeSuite(func() {
6160
testEnv = &envtest.Environment{
6261
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
6362
ErrorIfCRDPathMissing: true,
63+
}
6464

65-
// The BinaryAssetsDirectory is only required if you want to run the tests directly
66-
// without call the makefile target test. If not informed it will look for the
67-
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
68-
// Note that you must have the required binaries setup under the bin directory to perform
69-
// the tests directly. When we run make test it will be setup and used automatically.
70-
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
71-
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
65+
// Retrieve the first found binary directory to allow running tests from IDEs
66+
if getFirstFoundEnvTestBinaryDir() != "" {
67+
testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir()
7268
}
7369

7470
var err error
@@ -94,3 +90,26 @@ var _ = AfterSuite(func() {
9490
err := testEnv.Stop()
9591
Expect(err).NotTo(HaveOccurred())
9692
})
93+
94+
// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path.
95+
// ENVTEST-based tests depend on specific binaries, usually located in paths set by
96+
// controller-runtime. When running tests directly (e.g., via an IDE) without using
97+
// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured.
98+
//
99+
// This function streamlines the process by finding the required binaries, similar to
100+
// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are
101+
// properly set up, run 'make setup-envtest' beforehand.
102+
func getFirstFoundEnvTestBinaryDir() string {
103+
basePath := filepath.Join("..", "..", "bin", "k8s")
104+
entries, err := os.ReadDir(basePath)
105+
if err != nil {
106+
logf.Log.Error(err, "Failed to read directory", "path", basePath)
107+
return ""
108+
}
109+
for _, entry := range entries {
110+
if entry.IsDir() {
111+
return filepath.Join(basePath, entry.Name())
112+
}
113+
}
114+
return ""
115+
}

docs/book/src/multiversion-tutorial/testdata/project/Makefile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Image URL to use all building/pushing image targets
22
IMG ?= controller:latest
3-
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
4-
ENVTEST_K8S_VERSION = 1.31.0
53

64
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
75
ifeq (,$(shell go env GOBIN))
@@ -64,7 +62,7 @@ vet: ## Run go vet against code.
6462
go vet ./...
6563

6664
.PHONY: test
67-
test: manifests generate fmt vet envtest ## Run tests.
65+
test: manifests generate fmt vet setup-envtest ## Run tests.
6866
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
6967

7068
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
@@ -176,7 +174,10 @@ GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
176174
## Tool Versions
177175
KUSTOMIZE_VERSION ?= v5.5.0
178176
CONTROLLER_TOOLS_VERSION ?= v0.16.5
179-
ENVTEST_VERSION ?= release-0.19
177+
#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20)
178+
ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
179+
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
180+
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
180181
GOLANGCI_LINT_VERSION ?= v1.61.0
181182

182183
.PHONY: kustomize
@@ -189,6 +190,14 @@ controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessar
189190
$(CONTROLLER_GEN): $(LOCALBIN)
190191
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
191192

193+
.PHONY: setup-envtest
194+
setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory.
195+
@echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..."
196+
@$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path || { \
197+
echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \
198+
exit 1; \
199+
}
200+
192201
.PHONY: envtest
193202
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
194203
$(ENVTEST): $(LOCALBIN)

docs/book/src/multiversion-tutorial/testdata/project/internal/controller/suite_test.go

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ package controller
2626

2727
import (
2828
"context"
29-
"fmt"
29+
"os"
3030
"path/filepath"
31-
"runtime"
3231
"testing"
3332

3433
ctrl "sigs.k8s.io/controller-runtime"
@@ -82,19 +81,16 @@ var _ = BeforeSuite(func() {
8281
testEnv = &envtest.Environment{
8382
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
8483
ErrorIfCRDPathMissing: true,
85-
86-
// The BinaryAssetsDirectory is only required if you want to run the tests directly
87-
// without call the makefile target test. If not informed it will look for the
88-
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
89-
// Note that you must have the required binaries setup under the bin directory to perform
90-
// the tests directly. When we run make test it will be setup and used automatically.
91-
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
92-
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
9384
}
9485

86+
// Retrieve the first found binary directory to allow running tests from IDEs
87+
if getFirstFoundEnvTestBinaryDir() != "" {
88+
testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir()
89+
}
9590
/*
9691
Then, we start the envtest cluster.
9792
*/
93+
9894
var err error
9995
// cfg is defined in this file globally.
10096
cfg, err = testEnv.Start()
@@ -177,3 +173,26 @@ var _ = AfterSuite(func() {
177173
/*
178174
Now that you have your controller running on a test cluster and a client ready to perform operations on your CronJob, we can start writing integration tests!
179175
*/
176+
177+
// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path.
178+
// ENVTEST-based tests depend on specific binaries, usually located in paths set by
179+
// controller-runtime. When running tests directly (e.g., via an IDE) without using
180+
// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured.
181+
//
182+
// This function streamlines the process by finding the required binaries, similar to
183+
// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are
184+
// properly set up, run 'make setup-envtest' beforehand.
185+
func getFirstFoundEnvTestBinaryDir() string {
186+
basePath := filepath.Join("..", "..", "bin", "k8s")
187+
entries, err := os.ReadDir(basePath)
188+
if err != nil {
189+
logf.Log.Error(err, "Failed to read directory", "path", basePath)
190+
return ""
191+
}
192+
for _, entry := range entries {
193+
if entry.IsDir() {
194+
return filepath.Join(basePath, entry.Name())
195+
}
196+
}
197+
return ""
198+
}

0 commit comments

Comments
 (0)