From 462c6a70e6a93827304c9fcc5b5a47185ac74370 Mon Sep 17 00:00:00 2001 From: Yugo Kobayashi Date: Fri, 24 Jul 2026 21:45:59 +0900 Subject: [PATCH 1/2] refactor(version): avoid linking Kubernetes clientset for build info Signed-off-by: Yugo Kobayashi --- internal/version/clientgo.go | 2 +- internal/version/clientgo_test.go | 37 +++++++++++++++++++ .../version/testdata/clientgo-version/main.go | 34 +++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 internal/version/testdata/clientgo-version/main.go diff --git a/internal/version/clientgo.go b/internal/version/clientgo.go index 50a4fd5cb..7ae5184c5 100644 --- a/internal/version/clientgo.go +++ b/internal/version/clientgo.go @@ -21,7 +21,7 @@ import ( "runtime/debug" "slices" - _ "k8s.io/client-go/kubernetes" // Force k8s.io/client-go to be included in the build + _ "k8s.io/client-go/pkg/version" // Force the k8s.io/client-go module version into build info ) func K8sIOClientGoModVersion() (string, error) { diff --git a/internal/version/clientgo_test.go b/internal/version/clientgo_test.go index 624c669af..33a21f222 100644 --- a/internal/version/clientgo_test.go +++ b/internal/version/clientgo_test.go @@ -17,6 +17,10 @@ limitations under the License. package version import ( + "os/exec" + "path/filepath" + "runtime" + "strings" "testing" "github.com/stretchr/testify/require" @@ -28,3 +32,36 @@ func TestK8sClientGoModVersion(t *testing.T) { _, err := K8sIOClientGoModVersion() require.ErrorContains(t, err, "k8s.io/client-go not found in build info") } + +func TestK8sClientGoModVersionFromBuiltBinary(t *testing.T) { + cmd := exec.CommandContext(t.Context(), "go", "list", "-m", "-f={{.Version}}", "k8s.io/client-go") + expectedVersion, err := cmd.CombinedOutput() + require.NoError(t, err, string(expectedVersion)) + + binary := filepath.Join(t.TempDir(), "clientgo-version") + if runtime.GOOS == "windows" { + binary += ".exe" + } + + cmd = exec.CommandContext(t.Context(), "go", "build", "-o", binary, "./testdata/clientgo-version") + output, err := cmd.CombinedOutput() + require.NoError(t, err, string(output)) + + cmd = exec.CommandContext(t.Context(), binary) + output, err = cmd.CombinedOutput() + require.NoError(t, err, string(output)) + require.Equal(t, strings.TrimSpace(string(expectedVersion)), strings.TrimSpace(string(output))) +} + +func TestK8sClientGoDependencyIsLightweight(t *testing.T) { + cmd := exec.CommandContext(t.Context(), "go", "list", "-deps", ".") + output, err := cmd.CombinedOutput() + require.NoError(t, err, string(output)) + + dependencies := strings.Fields(string(output)) + require.Contains(t, dependencies, "k8s.io/client-go/pkg/version") + for _, dependency := range dependencies { + require.NotEqual(t, "k8s.io/client-go/kubernetes", dependency) + require.NotContains(t, dependency, "k8s.io/client-go/kubernetes/") + } +} diff --git a/internal/version/testdata/clientgo-version/main.go b/internal/version/testdata/clientgo-version/main.go new file mode 100644 index 000000000..81650bb64 --- /dev/null +++ b/internal/version/testdata/clientgo-version/main.go @@ -0,0 +1,34 @@ +/* +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 main + +import ( + "fmt" + "os" + + "helm.sh/helm/v4/internal/version" +) + +func main() { + clientGoVersion, err := version.K8sIOClientGoModVersion() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + fmt.Print(clientGoVersion) +} From c6791474e197cf592a5a6bfda1dd88daa35d3bba Mon Sep 17 00:00:00 2001 From: Yugo Kobayashi Date: Fri, 24 Jul 2026 22:51:07 +0900 Subject: [PATCH 2/2] test(version): clarify test binary build info Signed-off-by: Yugo Kobayashi --- internal/version/clientgo_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/version/clientgo_test.go b/internal/version/clientgo_test.go index 33a21f222..c80b21a29 100644 --- a/internal/version/clientgo_test.go +++ b/internal/version/clientgo_test.go @@ -27,8 +27,9 @@ import ( ) func TestK8sClientGoModVersion(t *testing.T) { - // Unfortunately, test builds don't include debug info / module info - // So we expect "K8sIOClientGoModVersion" to return error + // Generated test binaries omit dependency modules from embedded build info, + // even when the package under test imports them. The built-binary test below + // covers the normal executable path where dependency modules are present. _, err := K8sIOClientGoModVersion() require.ErrorContains(t, err, "k8s.io/client-go not found in build info") }