From fc2b1d8ccd76e83a292b3ebc32e89a6353aa0793 Mon Sep 17 00:00:00 2001 From: chaoliang yan Date: Mon, 20 Apr 2026 00:45:13 +1000 Subject: [PATCH] fix(chart/common): avoid pulling testing into non-test builds Signed-off-by: chaoliang yan --- internal/version/version.go | 16 ++++++---- internal/version/version_test.go | 51 ++++++++++++++++++++++++++++++++ pkg/chart/common/capabilities.go | 23 ++++---------- 3 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 internal/version/version_test.go diff --git a/internal/version/version.go b/internal/version/version.go index 3daf80893..980858635 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -20,9 +20,10 @@ import ( "flag" "fmt" "log/slog" + "os" + "path/filepath" "runtime" "strings" - "testing" "github.com/Masterminds/semver/v3" ) @@ -48,6 +49,11 @@ const ( kubeClientGoVersionTesting = "v1.20" ) +func isGoTestBinary(path string) bool { + base := filepath.Base(path) + return strings.HasSuffix(base, ".test") || strings.HasSuffix(base, ".test.exe") +} + // BuildInfo describes the compile time information. type BuildInfo struct { // Version is the current semver. @@ -79,10 +85,10 @@ func GetUserAgent() string { func Get() BuildInfo { makeKubeClientVersionString := func() string { - // Test builds don't include debug info / module info - // (And even if they did, we probably want a stable version during tests anyway) - // Return a default value for test builds - if testing.Testing() { + // `go test` binaries don't include the module metadata that `K8sIOClientGoModVersion` + // relies on, so keep returning the stable test value without importing `testing` + // into production dependency graphs. + if isGoTestBinary(os.Args[0]) { return kubeClientGoVersionTesting } diff --git a/internal/version/version_test.go b/internal/version/version_test.go new file mode 100644 index 000000000..9d768e5e2 --- /dev/null +++ b/internal/version/version_test.go @@ -0,0 +1,51 @@ +/* +Copyright The Helm 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. +*/ + +package version + +import "testing" + +func TestIsGoTestBinary(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + path string + want bool + }{ + {name: "go test temp binary", path: "/tmp/go-build1234/b001/version.test", want: true}, + {name: "go test windows binary", path: `C:\Temp\go-build1234\b001\version.test.exe`, want: true}, + {name: "regular binary", path: "/usr/local/bin/helm", want: false}, + {name: "user binary with test in name only", path: "/usr/local/bin/helm-test", want: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := isGoTestBinary(tt.path); got != tt.want { + t.Fatalf("isGoTestBinary(%q) = %v, want %v", tt.path, got, tt.want) + } + }) + } +} + +func TestGetUsesStableKubeClientVersionInTestBinary(t *testing.T) { + t.Parallel() + + if got := Get().KubeClientVersion; got != kubeClientGoVersionTesting { + t.Fatalf("Get().KubeClientVersion = %q, want %q", got, kubeClientGoVersionTesting) + } +} diff --git a/pkg/chart/common/capabilities.go b/pkg/chart/common/capabilities.go index 20f4953cf..bb96b41b8 100644 --- a/pkg/chart/common/capabilities.go +++ b/pkg/chart/common/capabilities.go @@ -20,7 +20,6 @@ import ( "slices" "strconv" "strings" - "testing" "github.com/Masterminds/semver/v3" "k8s.io/client-go/kubernetes/scheme" @@ -32,11 +31,6 @@ import ( helmversion "helm.sh/helm/v4/internal/version" ) -const ( - kubeVersionMajorTesting = 1 - kubeVersionMinorTesting = 20 -) - var ( // DefaultVersionSet is the default version set, which includes only Core V1 ("v1"). DefaultVersionSet = allKnownVersions() @@ -143,24 +137,17 @@ func allKnownVersions() VersionSet { } func makeDefaultCapabilities() (*Capabilities, error) { - // Test builds don't include debug info / module info - // (And even if they did, we probably want stable capabilities for tests anyway) - // Return a default value for test builds - if testing.Testing() { - return newCapabilities(kubeVersionMajorTesting, kubeVersionMinorTesting) - } - - vstr, err := helmversion.K8sIOClientGoModVersion() - if err != nil { - return nil, fmt.Errorf("failed to retrieve k8s.io/client-go version: %w", err) + vstr := helmversion.Get().KubeClientVersion + if vstr == "" { + return nil, fmt.Errorf("failed to retrieve Kubernetes client version") } v, err := semver.NewVersion(vstr) if err != nil { - return nil, fmt.Errorf("unable to parse k8s.io/client-go version %q: %w", vstr, err) + return nil, fmt.Errorf("unable to parse Kubernetes client version %q: %w", vstr, err) } - kubeVersionMajor := v.Major() + 1 + kubeVersionMajor := v.Major() kubeVersionMinor := v.Minor() return newCapabilities(kubeVersionMajor, kubeVersionMinor)