pull/31296/merge
George Jenkins 1 day ago committed by GitHub
commit 6198302059
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -58,18 +58,6 @@ LDFLAGS += -X helm.sh/helm/v4/internal/version.gitCommit=${GIT_COMMIT}
LDFLAGS += -X helm.sh/helm/v4/internal/version.gitTreeState=${GIT_DIRTY} LDFLAGS += -X helm.sh/helm/v4/internal/version.gitTreeState=${GIT_DIRTY}
LDFLAGS += $(EXT_LDFLAGS) LDFLAGS += $(EXT_LDFLAGS)
# Define constants based on the client-go version
K8S_MODULES_VER=$(subst ., ,$(subst v,,$(shell go list -f '{{.Version}}' -m k8s.io/client-go)))
K8S_MODULES_MAJOR_VER=$(shell echo $$(($(firstword $(K8S_MODULES_VER)) + 1)))
K8S_MODULES_MINOR_VER=$(word 2,$(K8S_MODULES_VER))
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/v2/lint/rules.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/v2/lint/rules.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
LDFLAGS += -X helm.sh/helm/v4/pkg/internal/v3/lint/rules.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
LDFLAGS += -X helm.sh/helm/v4/pkg/internal/v3/lint/rules.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/common/util.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/common/util.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
.PHONY: all .PHONY: all
all: build all: build

@ -28,14 +28,6 @@ import (
kscheme "k8s.io/client-go/kubernetes/scheme" kscheme "k8s.io/client-go/kubernetes/scheme"
) )
var (
// This should be set in the Makefile based on the version of client-go being imported.
// These constants will be overwritten with LDFLAGS. The version components must be
// strings in order for LDFLAGS to set them.
k8sVersionMajor = "1"
k8sVersionMinor = "20"
)
// deprecatedAPIError indicates than an API is deprecated in Kubernetes // deprecatedAPIError indicates than an API is deprecated in Kubernetes
type deprecatedAPIError struct { type deprecatedAPIError struct {
Deprecated string Deprecated string
@ -56,33 +48,29 @@ func validateNoDeprecations(resource *k8sYamlStruct, kubeVersion *common.KubeVer
return nil return nil
} }
majorVersion := k8sVersionMajor if kubeVersion == nil {
minorVersion := k8sVersionMinor kubeVersion = &common.DefaultCapabilities.KubeVersion
if kubeVersion != nil {
majorVersion = kubeVersion.Major
minorVersion = kubeVersion.Minor
} }
runtimeObject, err := resourceToRuntimeObject(resource) kubeVersionMajor, err := strconv.Atoi(kubeVersion.Major)
if err != nil { if err != nil {
// do not error for non-kubernetes resources
if runtime.IsNotRegisteredError(err) {
return nil
}
return err return err
} }
kubeVersionMinor, err := strconv.Atoi(kubeVersion.Minor)
major, err := strconv.Atoi(majorVersion)
if err != nil { if err != nil {
return err return err
} }
minor, err := strconv.Atoi(minorVersion)
runtimeObject, err := resourceToRuntimeObject(resource)
if err != nil { if err != nil {
// do not error for non-kubernetes resources
if runtime.IsNotRegisteredError(err) {
return nil
}
return err return err
} }
if !deprecation.IsDeprecated(runtimeObject, major, minor) { if !deprecation.IsDeprecated(runtimeObject, kubeVersionMajor, kubeVersionMinor) {
return nil return nil
} }
gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind) gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind)

@ -0,0 +1,44 @@
/*
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 "helm.sh/helm/v4/internal/version"
import (
"fmt"
"runtime/debug"
"slices"
_ "k8s.io/client-go/kubernetes" // Force k8s.io/client-go to be included in the build
)
func K8sIOClientGoModVersion() (string, error) {
info, ok := debug.ReadBuildInfo()
if !ok {
return "", fmt.Errorf("failed to read build info")
}
idx := slices.IndexFunc(info.Deps, func(m *debug.Module) bool {
return m.Path == "k8s.io/client-go"
})
if idx == -1 {
return "", fmt.Errorf("k8s.io/client-go not found in build info")
}
m := info.Deps[idx]
return m.Version, nil
}

@ -0,0 +1,30 @@
/*
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"
"github.com/stretchr/testify/require"
)
func TestK8sClientGoModVersion(t *testing.T) {
// Unfortunately, test builds don't include debug info / module info
// So we expect "K8sIOClientGoModVersion" to return error
_, err := K8sIOClientGoModVersion()
require.ErrorContains(t, err, "k8s.io/client-go not found in build info")
}

@ -19,7 +19,9 @@ import (
"fmt" "fmt"
"slices" "slices"
"strconv" "strconv"
"testing"
"github.com/Masterminds/semver/v3"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@ -29,25 +31,23 @@ import (
helmversion "helm.sh/helm/v4/internal/version" helmversion "helm.sh/helm/v4/internal/version"
) )
var ( const (
// The Kubernetes version can be set by LDFLAGS. In order to do that the value kubeVersionMajorTesting = 1
// must be a string. kubeVersionMinorTesting = 20
k8sVersionMajor = "1" )
k8sVersionMinor = "20"
var (
// DefaultVersionSet is the default version set, which includes only Core V1 ("v1"). // DefaultVersionSet is the default version set, which includes only Core V1 ("v1").
DefaultVersionSet = allKnownVersions() DefaultVersionSet = allKnownVersions()
// DefaultCapabilities is the default set of capabilities. DefaultCapabilities = func() *Capabilities {
DefaultCapabilities = &Capabilities{ caps, err := makeDefaultCapabilities()
KubeVersion: KubeVersion{ if err != nil {
Version: fmt.Sprintf("v%s.%s.0", k8sVersionMajor, k8sVersionMinor), panic(fmt.Sprintf("failed to create default capabilities: %v", err))
Major: k8sVersionMajor, }
Minor: k8sVersionMinor, return caps
},
APIVersions: DefaultVersionSet, }()
HelmVersion: helmversion.Get(),
}
) )
// Capabilities describes the capabilities of the Kubernetes cluster. // Capabilities describes the capabilities of the Kubernetes cluster.
@ -122,3 +122,40 @@ func allKnownVersions() VersionSet {
} }
return vs return vs
} }
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 get k8s.io/client-go version: %w", err)
}
v, err := semver.NewVersion(vstr)
if err != nil {
return nil, fmt.Errorf("unable to parse client-go version %q: %v", vstr, err)
}
kubeVersionMajor := v.Major() + 1
kubeVersionMinor := v.Minor()
return newCapabilities(kubeVersionMajor, kubeVersionMinor)
}
func newCapabilities(kubeVersionMajor, kubeVersionMinor uint64) (*Capabilities, error) {
return &Capabilities{
KubeVersion: KubeVersion{
Version: fmt.Sprintf("v%d.%d.0", kubeVersionMajor, kubeVersionMinor),
Major: fmt.Sprintf("%d", kubeVersionMajor),
Minor: fmt.Sprintf("%d", kubeVersionMinor),
},
APIVersions: DefaultVersionSet,
HelmVersion: helmversion.Get(),
}, nil
}

@ -41,7 +41,8 @@ func TestDefaultVersionSet(t *testing.T) {
} }
func TestDefaultCapabilities(t *testing.T) { func TestDefaultCapabilities(t *testing.T) {
kv := DefaultCapabilities.KubeVersion caps := DefaultCapabilities
kv := caps.KubeVersion
if kv.String() != "v1.20.0" { if kv.String() != "v1.20.0" {
t.Errorf("Expected default KubeVersion.String() to be v1.20.0, got %q", kv.String()) t.Errorf("Expected default KubeVersion.String() to be v1.20.0, got %q", kv.String())
} }
@ -57,11 +58,8 @@ func TestDefaultCapabilities(t *testing.T) {
if kv.Minor != "20" { if kv.Minor != "20" {
t.Errorf("Expected default KubeVersion.Minor to be 20, got %q", kv.Minor) t.Errorf("Expected default KubeVersion.Minor to be 20, got %q", kv.Minor)
} }
}
func TestDefaultCapabilitiesHelmVersion(t *testing.T) {
hv := DefaultCapabilities.HelmVersion
hv := caps.HelmVersion
if hv.Version != "v4.0" { if hv.Version != "v4.0" {
t.Errorf("Expected default HelmVersion to be v4.0, got %q", hv.Version) t.Errorf("Expected default HelmVersion to be v4.0, got %q", hv.Version)
} }

@ -28,14 +28,6 @@ import (
kscheme "k8s.io/client-go/kubernetes/scheme" kscheme "k8s.io/client-go/kubernetes/scheme"
) )
var (
// This should be set in the Makefile based on the version of client-go being imported.
// These constants will be overwritten with LDFLAGS. The version components must be
// strings in order for LDFLAGS to set them.
k8sVersionMajor = "1"
k8sVersionMinor = "20"
)
// deprecatedAPIError indicates than an API is deprecated in Kubernetes // deprecatedAPIError indicates than an API is deprecated in Kubernetes
type deprecatedAPIError struct { type deprecatedAPIError struct {
Deprecated string Deprecated string
@ -56,12 +48,8 @@ func validateNoDeprecations(resource *k8sYamlStruct, kubeVersion *common.KubeVer
return nil return nil
} }
majorVersion := k8sVersionMajor if kubeVersion == nil {
minorVersion := k8sVersionMinor kubeVersion = &common.DefaultCapabilities.KubeVersion
if kubeVersion != nil {
majorVersion = kubeVersion.Major
minorVersion = kubeVersion.Minor
} }
runtimeObject, err := resourceToRuntimeObject(resource) runtimeObject, err := resourceToRuntimeObject(resource)
@ -73,16 +61,16 @@ func validateNoDeprecations(resource *k8sYamlStruct, kubeVersion *common.KubeVer
return err return err
} }
major, err := strconv.Atoi(majorVersion) kubeVersionMajor, err := strconv.Atoi(kubeVersion.Major)
if err != nil { if err != nil {
return err return err
} }
minor, err := strconv.Atoi(minorVersion) kubeVersionMinor, err := strconv.Atoi(kubeVersion.Minor)
if err != nil { if err != nil {
return err return err
} }
if !deprecation.IsDeprecated(runtimeObject, major, minor) { if !deprecation.IsDeprecated(runtimeObject, kubeVersionMajor, kubeVersionMinor) {
return nil return nil
} }
gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind) gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind)

Loading…
Cancel
Save