From afa83a935a179ecb6c3d6ddefc33b888957fd16d Mon Sep 17 00:00:00 2001 From: Karuppiah Natarajan Date: Fri, 6 Mar 2020 09:12:35 +0530 Subject: [PATCH] add go version, compiler and platform to .Capabilities.KubeVersion Signed-off-by: Karuppiah Natarajan --- cmd/helm/template_test.go | 41 ++++ ...-template-with-kubernetes-version-info.txt | 12 + .../testcharts/issue-7004/.helmignore | 23 ++ .../testdata/testcharts/issue-7004/Chart.yaml | 21 ++ .../issue-7004/templates/_helpers.tpl | 45 ++++ .../issue-7004/templates/configmap.yaml | 10 + .../testcharts/issue-7004/values.yaml | 1 + go.mod | 3 + go.sum | 15 ++ internal/test/action/mock_action.go | 99 ++++++++ internal/test/discovery/mock_discovery.go | 216 ++++++++++++++++++ pkg/action/action.go | 9 +- pkg/action/action_test.go | 67 ++++++ pkg/chartutil/capabilities.go | 21 +- pkg/chartutil/capabilities_test.go | 30 ++- scripts/mock-generation.sh | 22 ++ 16 files changed, 619 insertions(+), 16 deletions(-) create mode 100644 cmd/helm/testdata/output/templatized-template-with-kubernetes-version-info.txt create mode 100644 cmd/helm/testdata/testcharts/issue-7004/.helmignore create mode 100644 cmd/helm/testdata/testcharts/issue-7004/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/issue-7004/templates/_helpers.tpl create mode 100644 cmd/helm/testdata/testcharts/issue-7004/templates/configmap.yaml create mode 100644 cmd/helm/testdata/testcharts/issue-7004/values.yaml create mode 100644 internal/test/action/mock_action.go create mode 100644 internal/test/discovery/mock_discovery.go create mode 100755 scripts/mock-generation.sh diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index f8cd31347..2eb4c6203 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -18,13 +18,24 @@ package main import ( "fmt" + "io/ioutil" "path/filepath" + "runtime" + "strings" "testing" + "text/template" + + "helm.sh/helm/v3/internal/test/ensure" ) var chartPath = "testdata/testcharts/subchart" func TestTemplateCmd(t *testing.T) { + expectedTemplateOutput, err := prepareExpectedTemplateOutputForKubernetesVersionInfoCheck(t) + if err != nil { + t.Fatal("failed to generated expected template output: ", err) + } + tests := []cmdTestCase{ { name: "check name", @@ -121,6 +132,11 @@ func TestTemplateCmd(t *testing.T) { wantError: true, golden: "output/template-with-invalid-yaml-debug.txt", }, + { + name: "chart with template with kubernetes go version, platform and compile", + cmd: fmt.Sprintf("template '%s' --debug", "testdata/testcharts/issue-7004"), + golden: expectedTemplateOutput, + }, } runTestCmd(t, tests) } @@ -154,3 +170,28 @@ func TestTemplateVersionCompletion(t *testing.T) { }} runTestCmd(t, tests) } + +func prepareExpectedTemplateOutputForKubernetesVersionInfoCheck(t *testing.T) (string, error) { + tmpDir := ensure.TempDir(t) + templatePath := filepath.Join("testdata", "output", "templatized-template-with-kubernetes-version-info.txt") + tmpl, err := template.ParseFiles(templatePath) + if err != nil { + return "", err + } + templateOutput := &strings.Builder{} + data := map[string]string{ + "Compiler": runtime.Compiler, + "Platform": fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + "GoVersion": runtime.Version(), + } + err = tmpl.Execute(templateOutput, data) + if err != nil { + return "", err + } + outputFilePath := filepath.Join(tmpDir, "template-with-kubernetes-version-info.txt") + err = ioutil.WriteFile(outputFilePath, []byte(templateOutput.String()), 0644) + if err != nil { + return "", err + } + return outputFilePath, nil +} diff --git a/cmd/helm/testdata/output/templatized-template-with-kubernetes-version-info.txt b/cmd/helm/testdata/output/templatized-template-with-kubernetes-version-info.txt new file mode 100644 index 000000000..6887e8372 --- /dev/null +++ b/cmd/helm/testdata/output/templatized-template-with-kubernetes-version-info.txt @@ -0,0 +1,12 @@ +--- +# Source: issue-7004/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: RELEASE-NAME-issue-7004 + labels: + kube-version/compiler: "{{ .Compiler }}" + kube-version/platform: "{{ .Platform }}" + kube-version/go-version: "{{ .GoVersion }}" +data: + someKey: dummyValue diff --git a/cmd/helm/testdata/testcharts/issue-7004/.helmignore b/cmd/helm/testdata/testcharts/issue-7004/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7004/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/cmd/helm/testdata/testcharts/issue-7004/Chart.yaml b/cmd/helm/testdata/testcharts/issue-7004/Chart.yaml new file mode 100644 index 000000000..8f27a804b --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7004/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +name: issue-7004 +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.16.0 diff --git a/cmd/helm/testdata/testcharts/issue-7004/templates/_helpers.tpl b/cmd/helm/testdata/testcharts/issue-7004/templates/_helpers.tpl new file mode 100644 index 000000000..c8f2083b0 --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7004/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "issue-7004.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "issue-7004.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "issue-7004.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "issue-7004.labels" -}} +app.kubernetes.io/name: {{ include "issue-7004.name" . }} +helm.sh/chart: {{ include "issue-7004.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} diff --git a/cmd/helm/testdata/testcharts/issue-7004/templates/configmap.yaml b/cmd/helm/testdata/testcharts/issue-7004/templates/configmap.yaml new file mode 100644 index 000000000..d5777f26e --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7004/templates/configmap.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "issue-7004.fullname" . }} + labels: + kube-version/compiler: "{{ .Capabilities.KubeVersion.Compiler }}" + kube-version/platform: "{{ .Capabilities.KubeVersion.Platform }}" + kube-version/go-version: "{{ .Capabilities.KubeVersion.GoVersion }}" +data: + someKey: {{ .Values.someValue }} \ No newline at end of file diff --git a/cmd/helm/testdata/testcharts/issue-7004/values.yaml b/cmd/helm/testdata/testcharts/issue-7004/values.yaml new file mode 100644 index 000000000..ae95ed9dc --- /dev/null +++ b/cmd/helm/testdata/testcharts/issue-7004/values.yaml @@ -0,0 +1 @@ +someValue: "dummyValue" \ No newline at end of file diff --git a/go.mod b/go.mod index 08eae92fa..ec4f024ee 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,8 @@ require ( github.com/evanphx/json-patch v4.5.0+incompatible github.com/gobwas/glob v0.2.3 github.com/gofrs/flock v0.7.1 + github.com/golang/mock v1.4.3 + github.com/googleapis/gnostic v0.4.0 github.com/gosuri/uitable v0.0.4 github.com/jmoiron/sqlx v1.2.0 github.com/lib/pq v1.7.0 @@ -34,6 +36,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect k8s.io/api v0.18.4 k8s.io/apiextensions-apiserver v0.18.4 k8s.io/apimachinery v0.18.4 diff --git a/go.sum b/go.sum index 0d0ef8c83..d2ad332cb 100644 --- a/go.sum +++ b/go.sum @@ -181,6 +181,7 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arX github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -305,7 +306,10 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -338,6 +342,8 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1 github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.0 h1:BXDUo8p/DaxC+4FJY/SSx3gvnx9C1VdHNgaUkiEL5mk= +github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -772,6 +778,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -812,6 +820,7 @@ golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f h1:68K/z8GLUxV76xGSqwTWw2gyk/jwn79LUL43rES2g8o= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -833,6 +842,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -841,6 +851,7 @@ golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -941,6 +952,10 @@ k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/metrics v0.18.4/go.mod h1:luze4fyI9JG4eLDZy0kFdYEebqNfi0QrG4xNEbPkHOs= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= diff --git a/internal/test/action/mock_action.go b/internal/test/action/mock_action.go new file mode 100644 index 000000000..2ba312c01 --- /dev/null +++ b/internal/test/action/mock_action.go @@ -0,0 +1,99 @@ +/* +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. +*/ + +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/action/action.go +// Command used to generate: mockgen -package action -source pkg/action/action.go -destination internal/test/action/mock_action.go /action/action.go + +// Package action is a generated GoMock package. +package action + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + meta "k8s.io/apimachinery/pkg/api/meta" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" +) + +// MockRESTClientGetter is a mock of RESTClientGetter interface +type MockRESTClientGetter struct { + ctrl *gomock.Controller + recorder *MockRESTClientGetterMockRecorder +} + +// MockRESTClientGetterMockRecorder is the mock recorder for MockRESTClientGetter +type MockRESTClientGetterMockRecorder struct { + mock *MockRESTClientGetter +} + +// NewMockRESTClientGetter creates a new mock instance +func NewMockRESTClientGetter(ctrl *gomock.Controller) *MockRESTClientGetter { + mock := &MockRESTClientGetter{ctrl: ctrl} + mock.recorder = &MockRESTClientGetterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRESTClientGetter) EXPECT() *MockRESTClientGetterMockRecorder { + return m.recorder +} + +// ToRESTConfig mocks base method +func (m *MockRESTClientGetter) ToRESTConfig() (*rest.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ToRESTConfig") + ret0, _ := ret[0].(*rest.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ToRESTConfig indicates an expected call of ToRESTConfig +func (mr *MockRESTClientGetterMockRecorder) ToRESTConfig() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToRESTConfig", reflect.TypeOf((*MockRESTClientGetter)(nil).ToRESTConfig)) +} + +// ToDiscoveryClient mocks base method +func (m *MockRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ToDiscoveryClient") + ret0, _ := ret[0].(discovery.CachedDiscoveryInterface) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ToDiscoveryClient indicates an expected call of ToDiscoveryClient +func (mr *MockRESTClientGetterMockRecorder) ToDiscoveryClient() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToDiscoveryClient", reflect.TypeOf((*MockRESTClientGetter)(nil).ToDiscoveryClient)) +} + +// ToRESTMapper mocks base method +func (m *MockRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ToRESTMapper") + ret0, _ := ret[0].(meta.RESTMapper) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ToRESTMapper indicates an expected call of ToRESTMapper +func (mr *MockRESTClientGetterMockRecorder) ToRESTMapper() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToRESTMapper", reflect.TypeOf((*MockRESTClientGetter)(nil).ToRESTMapper)) +} diff --git a/internal/test/discovery/mock_discovery.go b/internal/test/discovery/mock_discovery.go new file mode 100644 index 000000000..a074902e8 --- /dev/null +++ b/internal/test/discovery/mock_discovery.go @@ -0,0 +1,216 @@ +/* +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. +*/ + +// Code generated by MockGen. DO NOT EDIT. +// Source: k8s.io/client-go/discovery (interfaces: CachedDiscoveryInterface) +// Command used to generate: mockgen -package discovery -destination internal/test/discovery/mock_discovery.go k8s.io/client-go/discovery CachedDiscoveryInterface + +// Package discovery is a generated GoMock package. +package discovery + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + version "k8s.io/apimachinery/pkg/version" + rest "k8s.io/client-go/rest" +) + +// MockCachedDiscoveryInterface is a mock of CachedDiscoveryInterface interface +type MockCachedDiscoveryInterface struct { + ctrl *gomock.Controller + recorder *MockCachedDiscoveryInterfaceMockRecorder +} + +// MockCachedDiscoveryInterfaceMockRecorder is the mock recorder for MockCachedDiscoveryInterface +type MockCachedDiscoveryInterfaceMockRecorder struct { + mock *MockCachedDiscoveryInterface +} + +// NewMockCachedDiscoveryInterface creates a new mock instance +func NewMockCachedDiscoveryInterface(ctrl *gomock.Controller) *MockCachedDiscoveryInterface { + mock := &MockCachedDiscoveryInterface{ctrl: ctrl} + mock.recorder = &MockCachedDiscoveryInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockCachedDiscoveryInterface) EXPECT() *MockCachedDiscoveryInterfaceMockRecorder { + return m.recorder +} + +// Fresh mocks base method +func (m *MockCachedDiscoveryInterface) Fresh() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Fresh") + ret0, _ := ret[0].(bool) + return ret0 +} + +// Fresh indicates an expected call of Fresh +func (mr *MockCachedDiscoveryInterfaceMockRecorder) Fresh() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fresh", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).Fresh)) +} + +// Invalidate mocks base method +func (m *MockCachedDiscoveryInterface) Invalidate() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Invalidate") +} + +// Invalidate indicates an expected call of Invalidate +func (mr *MockCachedDiscoveryInterfaceMockRecorder) Invalidate() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invalidate", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).Invalidate)) +} + +// OpenAPISchema mocks base method +func (m *MockCachedDiscoveryInterface) OpenAPISchema() (*openapi_v2.Document, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OpenAPISchema") + ret0, _ := ret[0].(*openapi_v2.Document) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenAPISchema indicates an expected call of OpenAPISchema +func (mr *MockCachedDiscoveryInterfaceMockRecorder) OpenAPISchema() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenAPISchema", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).OpenAPISchema)) +} + +// RESTClient mocks base method +func (m *MockCachedDiscoveryInterface) RESTClient() rest.Interface { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RESTClient") + ret0, _ := ret[0].(rest.Interface) + return ret0 +} + +// RESTClient indicates an expected call of RESTClient +func (mr *MockCachedDiscoveryInterfaceMockRecorder) RESTClient() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RESTClient", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).RESTClient)) +} + +// ServerGroups mocks base method +func (m *MockCachedDiscoveryInterface) ServerGroups() (*v1.APIGroupList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerGroups") + ret0, _ := ret[0].(*v1.APIGroupList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ServerGroups indicates an expected call of ServerGroups +func (mr *MockCachedDiscoveryInterfaceMockRecorder) ServerGroups() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerGroups", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).ServerGroups)) +} + +// ServerGroupsAndResources mocks base method +func (m *MockCachedDiscoveryInterface) ServerGroupsAndResources() ([]*v1.APIGroup, []*v1.APIResourceList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerGroupsAndResources") + ret0, _ := ret[0].([]*v1.APIGroup) + ret1, _ := ret[1].([]*v1.APIResourceList) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// ServerGroupsAndResources indicates an expected call of ServerGroupsAndResources +func (mr *MockCachedDiscoveryInterfaceMockRecorder) ServerGroupsAndResources() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerGroupsAndResources", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).ServerGroupsAndResources)) +} + +// ServerPreferredNamespacedResources mocks base method +func (m *MockCachedDiscoveryInterface) ServerPreferredNamespacedResources() ([]*v1.APIResourceList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerPreferredNamespacedResources") + ret0, _ := ret[0].([]*v1.APIResourceList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ServerPreferredNamespacedResources indicates an expected call of ServerPreferredNamespacedResources +func (mr *MockCachedDiscoveryInterfaceMockRecorder) ServerPreferredNamespacedResources() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerPreferredNamespacedResources", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).ServerPreferredNamespacedResources)) +} + +// ServerPreferredResources mocks base method +func (m *MockCachedDiscoveryInterface) ServerPreferredResources() ([]*v1.APIResourceList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerPreferredResources") + ret0, _ := ret[0].([]*v1.APIResourceList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ServerPreferredResources indicates an expected call of ServerPreferredResources +func (mr *MockCachedDiscoveryInterfaceMockRecorder) ServerPreferredResources() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerPreferredResources", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).ServerPreferredResources)) +} + +// ServerResources mocks base method +func (m *MockCachedDiscoveryInterface) ServerResources() ([]*v1.APIResourceList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerResources") + ret0, _ := ret[0].([]*v1.APIResourceList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ServerResources indicates an expected call of ServerResources +func (mr *MockCachedDiscoveryInterfaceMockRecorder) ServerResources() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerResources", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).ServerResources)) +} + +// ServerResourcesForGroupVersion mocks base method +func (m *MockCachedDiscoveryInterface) ServerResourcesForGroupVersion(arg0 string) (*v1.APIResourceList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerResourcesForGroupVersion", arg0) + ret0, _ := ret[0].(*v1.APIResourceList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ServerResourcesForGroupVersion indicates an expected call of ServerResourcesForGroupVersion +func (mr *MockCachedDiscoveryInterfaceMockRecorder) ServerResourcesForGroupVersion(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerResourcesForGroupVersion", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).ServerResourcesForGroupVersion), arg0) +} + +// ServerVersion mocks base method +func (m *MockCachedDiscoveryInterface) ServerVersion() (*version.Info, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerVersion") + ret0, _ := ret[0].(*version.Info) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ServerVersion indicates an expected call of ServerVersion +func (mr *MockCachedDiscoveryInterfaceMockRecorder) ServerVersion() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerVersion", reflect.TypeOf((*MockCachedDiscoveryInterface)(nil).ServerVersion)) +} diff --git a/pkg/action/action.go b/pkg/action/action.go index bb9ef5f71..066646caf 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -263,9 +263,12 @@ func (c *Configuration) getCapabilities() (*chartutil.Capabilities, error) { c.Capabilities = &chartutil.Capabilities{ APIVersions: apiVersions, KubeVersion: chartutil.KubeVersion{ - Version: kubeVersion.GitVersion, - Major: kubeVersion.Major, - Minor: kubeVersion.Minor, + Version: kubeVersion.GitVersion, + Major: kubeVersion.Major, + Minor: kubeVersion.Minor, + GoVersion: kubeVersion.GoVersion, + Compiler: kubeVersion.Compiler, + Platform: kubeVersion.Platform, }, } return c.Capabilities, nil diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 0cbdb162b..eb3261ab1 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -18,15 +18,22 @@ package action import ( "context" "flag" + "fmt" "io/ioutil" "net/http" "path/filepath" + "runtime" "testing" + "github.com/golang/mock/gomock" + "k8s.io/apimachinery/pkg/version" + dockerauth "github.com/deislabs/oras/pkg/auth/docker" fakeclientset "k8s.io/client-go/kubernetes/fake" "helm.sh/helm/v3/internal/experimental/registry" + "helm.sh/helm/v3/internal/test/action" + "helm.sh/helm/v3/internal/test/discovery" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" kubefake "helm.sh/helm/v3/pkg/kube/fake" @@ -353,3 +360,63 @@ func TestValidName(t *testing.T) { } } } + +func TestGetCapabilities(t *testing.T) { + t.Run("Capabilities.KubeVersion gives the correct version information", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockDiscoveryClient := discovery.NewMockCachedDiscoveryInterface(ctrl) + serverVersion := &version.Info{ + GitVersion: "v1.18.0", + Major: "1", + Minor: "18", + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } + mockDiscoveryClient.EXPECT().Invalidate() + mockDiscoveryClient.EXPECT().ServerVersion().Return(serverVersion, nil) + mockDiscoveryClient.EXPECT().ServerGroupsAndResources().Return(nil, nil, nil) + + mockRESTClientGetter := action.NewMockRESTClientGetter(ctrl) + + mockRESTClientGetter.EXPECT().ToDiscoveryClient().Return(mockDiscoveryClient, nil) + + configuration := &Configuration{RESTClientGetter: mockRESTClientGetter} + + capabilities, err := configuration.getCapabilities() + + if err != nil { + t.Error(err) + } + + expectedKubeMajorVersion := "1" + expectedKubeMinorVersion := "18" + expectedKubeVersion := fmt.Sprintf("v%s.%s.0", expectedKubeMajorVersion, expectedKubeMinorVersion) + kv := capabilities.KubeVersion + + if kv.String() != expectedKubeVersion { + t.Errorf("Expected default KubeVersion.String() to be %s, got %q", expectedKubeVersion, kv.String()) + } + if kv.Version != expectedKubeVersion { + t.Errorf("Expected default KubeVersion.Version to be %s, got %q", expectedKubeVersion, kv.Version) + } + if kv.Major != expectedKubeMajorVersion { + t.Errorf("Expected default KubeVersion.Major to be %s, got %q", expectedKubeMajorVersion, kv.Major) + } + if kv.Minor != expectedKubeMinorVersion { + t.Errorf("Expected default KubeVersion.Minor to be %s, got %q", expectedKubeMinorVersion, kv.Minor) + } + if kv.GoVersion != runtime.Version() { + t.Errorf("Expected default KubeVersion.GoVersion to be %q, got %q", runtime.Version(), kv.GoVersion) + } + if kv.Compiler != runtime.Compiler { + t.Errorf("Expected default KubeVersion.Compiler to be %q, got %q", runtime.Compiler, kv.Compiler) + } + expectedPlatform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) + if kv.Platform != expectedPlatform { + t.Errorf("Expected default KubeVersion.Platform to be %q, got %q", expectedPlatform, kv.Platform) + } + }) +} diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index adfe2363d..e792b7247 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -16,6 +16,9 @@ limitations under the License. package chartutil import ( + "fmt" + "runtime" + "k8s.io/client-go/kubernetes/scheme" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -31,9 +34,12 @@ var ( // DefaultCapabilities is the default set of capabilities. DefaultCapabilities = &Capabilities{ KubeVersion: KubeVersion{ - Version: "v1.18.0", - Major: "1", - Minor: "18", + Version: "v1.18.0", + Major: "1", + Minor: "18", + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), }, APIVersions: DefaultVersionSet, HelmVersion: helmversion.Get(), @@ -52,9 +58,12 @@ type Capabilities struct { // KubeVersion is the Kubernetes version. type KubeVersion struct { - Version string // Kubernetes version - Major string // Kubernetes major version - Minor string // Kubernetes minor version + Version string // Kubernetes version + Major string // Kubernetes major version + Minor string // Kubernetes minor version + GoVersion string // Kubernetes Golang version + Compiler string // Kubernetes Compiler toolchain + Platform string // Kubernetes OS and Architecture } // String implements fmt.Stringer diff --git a/pkg/chartutil/capabilities_test.go b/pkg/chartutil/capabilities_test.go index 489a472be..ec708b3a5 100644 --- a/pkg/chartutil/capabilities_test.go +++ b/pkg/chartutil/capabilities_test.go @@ -16,6 +16,8 @@ limitations under the License. package chartutil import ( + "fmt" + "runtime" "testing" ) @@ -41,21 +43,35 @@ func TestDefaultVersionSet(t *testing.T) { } func TestDefaultCapabilities(t *testing.T) { + expectedKubeMajorVersion := "1" + expectedKubeMinorVersion := "18" + expectedKubeVersion := fmt.Sprintf("v%s.%s.0", expectedKubeMajorVersion, expectedKubeMinorVersion) kv := DefaultCapabilities.KubeVersion - if kv.String() != "v1.18.0" { + if kv.String() != expectedKubeVersion { t.Errorf("Expected default KubeVersion.String() to be v1.18.0, got %q", kv.String()) } - if kv.Version != "v1.18.0" { + if kv.Version != expectedKubeVersion { t.Errorf("Expected default KubeVersion.Version to be v1.18.0, got %q", kv.Version) } - if kv.GitVersion() != "v1.18.0" { + if kv.GitVersion() != expectedKubeVersion { t.Errorf("Expected default KubeVersion.GitVersion() to be v1.18.0, got %q", kv.Version) } - if kv.Major != "1" { - t.Errorf("Expected default KubeVersion.Major to be 1, got %q", kv.Major) + if kv.Major != expectedKubeMajorVersion { + t.Errorf("Expected default KubeVersion.Major to be %s, got %q", expectedKubeMajorVersion, kv.Major) + + } + if kv.Minor != expectedKubeMinorVersion { + t.Errorf("Expected default KubeVersion.Minor to be %s, got %q", expectedKubeMinorVersion, kv.Minor) + } + if kv.GoVersion != runtime.Version() { + t.Errorf("Expected default KubeVersion.GoVersion to be %q, got %q", runtime.Version(), kv.GoVersion) + } + if kv.Compiler != runtime.Compiler { + t.Errorf("Expected default KubeVersion.Compiler to be %q, got %q", runtime.Compiler, kv.Compiler) } - if kv.Minor != "18" { - t.Errorf("Expected default KubeVersion.Minor to be 16, got %q", kv.Minor) + expectedPlatform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) + if kv.Platform != expectedPlatform { + t.Errorf("Expected default KubeVersion.Platform to be %q, got %q", expectedPlatform, kv.Platform) } } diff --git a/scripts/mock-generation.sh b/scripts/mock-generation.sh new file mode 100755 index 000000000..a36026e6b --- /dev/null +++ b/scripts/mock-generation.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# 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. + +set -euo pipefail + +mockgen -package discovery -destination internal/test/discovery/mock_discovery.go k8s.io/client-go/discovery CachedDiscoveryInterface +mockgen -package action -source pkg/action/action.go -destination internal/test/action/mock_action.go /action/action.go + +# Add license information at the top of the generated files