fix: avoid importing testing package in release builds

internal/version and pkg/chart/common imported "testing" only to call
testing.Testing(), pulling the testing package and its dependencies
into release binaries.

Replace those checks with exported KubeVersionMajorTesting /
KubeVersionMinorTesting sentinels that default to zero. A new
build-tagged file internal/version/version_helmtest.go seeds them in
init() and only compiles under -tags helmtest.

The Makefile applies -tags helmtest as a baseline so test-unit and
test-coverage work directly or via `make test`. scripts/coverage.sh
passes the tag to its raw `go test` call. CONTRIBUTING.md documents
that contributors running tests outside the Makefile must pass the
tag themselves.

Signed-off-by: Evans Mungai <mbuevans@gmail.com>
pull/32169/head
Evans Mungai 7 days ago
parent 4dec37abd2
commit e8b053d999
No known key found for this signature in database
GPG Key ID: BBEB812143DD14E1

@ -232,6 +232,20 @@ guide](https://helm.sh/docs/community/developers/) to get started.
Coding conventions and standards are explained in the [official developer
docs](https://helm.sh/docs/developers/).
### Running tests
Use the Makefile targets (`make test`, `make test-unit`, `make test-coverage`)
rather than invoking `go test ./...` directly. The Makefile passes the
`helmtest` build tag, which is required: it activates
`internal/version/version_helmtest.go` to seed testing-version sentinels. Test
binaries have no module info, so without this tag the production code path
attempts to read `k8s.io/client-go`'s version from build info and panics during
package init.
If you run tests outside the Makefile (IDE test runners, `go test` directly,
custom CI), pass `-tags helmtest`. The tag is omitted from release builds so
the `testing` package and its dependencies stay out of shipped binaries.
## Pull Requests
Like any good open source project, we use Pull Requests (PRs) to track code changes.

@ -89,6 +89,11 @@ endif
test: test-style
test: test-unit
# The `helmtest` build tag activates internal/version/version_helmtest.go,
# which seeds testing-version sentinels so test binaries don't panic reading
# missing module info. Applied to all test invocations.
TESTFLAGS += -tags helmtest
.PHONY: test-unit
test-unit:
@echo

@ -17,12 +17,10 @@ limitations under the License.
package version
import (
"flag"
"fmt"
"log/slog"
"runtime"
"strings"
"testing"
"github.com/Masterminds/semver/v3"
)
@ -44,8 +42,9 @@ var (
gitTreeState = ""
)
const (
kubeClientGoVersionTesting = "v1.20"
var (
KubeVersionMajorTesting uint64
KubeVersionMinorTesting uint64
)
// BuildInfo describes the compile time information.
@ -82,8 +81,8 @@ func Get() BuildInfo {
// 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() {
return kubeClientGoVersionTesting
if KubeVersionMajorTesting != 0 && KubeVersionMinorTesting != 0 {
return fmt.Sprintf("v%d.%d", KubeVersionMajorTesting, KubeVersionMinorTesting)
}
vstr, err := K8sIOClientGoModVersion()
@ -113,7 +112,7 @@ func Get() BuildInfo {
}
// HACK(bacongobbler): strip out GoVersion during a test run for consistent test output
if flag.Lookup("test.v") != nil {
if KubeVersionMajorTesting != 0 && KubeVersionMinorTesting != 0 {
v.GoVersion = ""
}
return v

@ -0,0 +1,31 @@
//go:build helmtest
/*
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
// This file is only compiled when the `helmtest` build tag is set (applied by
// the Makefile to all test invocations). It seeds the testing-version
// sentinels so that production code paths in this package and in
// pkg/chart/common substitute stable values instead of attempting to read
// build info from a `go test` binary (which has no module info and would
// panic during package init).
func init() {
KubeVersionMajorTesting = 1
KubeVersionMinorTesting = 20
}

@ -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()
@ -146,8 +140,8 @@ 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)
if helmversion.KubeVersionMajorTesting != 0 && helmversion.KubeVersionMinorTesting != 0 {
return newCapabilities(helmversion.KubeVersionMajorTesting, helmversion.KubeVersionMinorTesting)
}
vstr, err := helmversion.K8sIOClientGoModVersion()

@ -37,7 +37,7 @@ generate_cover_data() {
for d in $(go list "$target"); do
(
local output="${coverdir}/${d//\//-}.cover"
go test -coverprofile="${output}" -covermode="$covermode" "$d"
go test -tags helmtest -coverprofile="${output}" -covermode="$covermode" "$d"
)
done

Loading…
Cancel
Save