From a3146dbfe4223a7aef8863854157f11cf5fa5f53 Mon Sep 17 00:00:00 2001 From: Brian de Alwis Date: Mon, 12 Jul 2021 18:29:28 -0400 Subject: [PATCH] Restore previous behaviour and introduce `default` function --- pkg/skaffold/deploy/helm/helm_test.go | 6 +++--- pkg/skaffold/util/env_template.go | 30 +++++++++++++++++++++++++- pkg/skaffold/util/env_template_test.go | 25 +++++++++++++++++++-- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/pkg/skaffold/deploy/helm/helm_test.go b/pkg/skaffold/deploy/helm/helm_test.go index a08fedef60d..1f383c217dd 100644 --- a/pkg/skaffold/deploy/helm/helm_test.go +++ b/pkg/skaffold/deploy/helm/helm_test.go @@ -117,7 +117,7 @@ var testDeployConfigTemplated = latestV1.HelmDeploy{ SetValueTemplates: map[string]string{ "some.key": "somevalue", "other.key": "{{.FOO}}", - "missing.key": "{{.MISSING}}", + "missing.key": `{{default "" .MISSING}}`, "image.name": "{{.IMAGE_NAME}}", "image.tag": "{{.DIGEST}}", "{{.FOO}}": "somevalue", @@ -881,7 +881,7 @@ func TestHelmDeploy(t *testing.T) { CmdRunWithOutput("helm version --client", version31). AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). - AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set image.name=skaffold-helm --set image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set missing.key= --set other.key=FOOBAR --set some.key=somevalue --set FOOBAR=somevalue -f skaffold-overrides.yaml --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set image.name=skaffold-helm --set image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set missing.key= --set other.key=FOOBAR --set some.key=somevalue --set FOOBAR=somevalue -f skaffold-overrides.yaml --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get all skaffold-helm --template {{.Release.Manifest}} --kubeconfig kubeconfig"), helm: testDeployConfigTemplated, builds: testBuilds, @@ -1328,7 +1328,7 @@ func TestHelmRender(t *testing.T) { shouldErr: false, commands: testutil. CmdRunWithOutput("helm version --client", version31). - AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --set-string image=skaffold-helm:tag1 --set image.name=skaffold-helm --set image.tag=skaffold-helm:tag1 --set missing.key= --set other.key=FOOBAR --set some.key=somevalue --set FOOBAR=somevalue --kubeconfig kubeconfig"), + AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --set-string image=skaffold-helm:tag1 --set image.name=skaffold-helm --set image.tag=skaffold-helm:tag1 --set missing.key= --set other.key=FOOBAR --set some.key=somevalue --set FOOBAR=somevalue --kubeconfig kubeconfig"), helm: testDeployConfigTemplated, builds: []graph.Artifact{ { diff --git a/pkg/skaffold/util/env_template.go b/pkg/skaffold/util/env_template.go index c47f299998c..1f123b845a0 100644 --- a/pkg/skaffold/util/env_template.go +++ b/pkg/skaffold/util/env_template.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "os" + "reflect" "sort" "strings" "text/template" @@ -30,6 +31,9 @@ import ( // For testing var ( OSEnviron = os.Environ + funcsMap = template.FuncMap{ + "default": defaultFunc, + } ) // ExpandEnvTemplate parses and executes template s with an optional environment map @@ -53,7 +57,7 @@ func ExpandEnvTemplateOrFail(s string, envMap map[string]string) (string, error) // ParseEnvTemplate is a simple wrapper to parse an env template func ParseEnvTemplate(t string) (*template.Template, error) { - return template.New("envTemplate").Option("missingkey=zero").Parse(t) + return template.New("envTemplate").Funcs(funcsMap).Parse(t) } // ExecuteEnvTemplate executes an envTemplate based on OS environment variables and a custom map @@ -131,3 +135,27 @@ func MapToFlag(m map[string]*string, flag string) ([]string, error) { return kvFlags, nil } + +// defaultFunc is a template function that behaves as sprig's default function. +// See https://masterminds.github.io/sprig/defaults.html#default +func defaultFunc(dflt, value interface{}) interface{} { + if value == nil { + return dflt + } + v := reflect.ValueOf(value) + switch v.Kind() { + case reflect.Array, reflect.Slice: + if v.Len() == 0 { + return dflt + } + case reflect.Ptr: + if v.IsNil() { + return dflt + } + default: + if v.IsZero() { + return dflt + } + } + return value +} diff --git a/pkg/skaffold/util/env_template_test.go b/pkg/skaffold/util/env_template_test.go index f36667e015f..19163dd1578 100644 --- a/pkg/skaffold/util/env_template_test.go +++ b/pkg/skaffold/util/env_template_test.go @@ -17,6 +17,7 @@ limitations under the License. package util import ( + "fmt" "testing" "github.com/GoogleContainerTools/skaffold/testutil" @@ -64,9 +65,9 @@ func TestEnvTemplate_ExecuteEnvTemplate(t *testing.T) { }, { description: "missing results in empty", - template: "{{.FOO}}:{{.BAR}}", + template: `{{default "a" .FOO}}:{{.BAR}}`, customMap: map[string]string{}, - want: ":", + want: "a:", }, } for _, test := range tests { @@ -178,3 +179,23 @@ func TestMapToFlag(t *testing.T) { }) } } + +func TestDefaultFunc(t *testing.T) { + for _, empty := range []interface{}{nil, false, 0, "", []string{}} { + t.Run(fmt.Sprintf("empties: %v (%T)", empty, empty), func(t *testing.T) { + dflt := "default" + if defaultFunc(dflt, empty) != dflt { + t.Error("did not return default") + } + }) + } + s := "string" + for _, nonEmpty := range []interface{}{&s, true, 1, "hoot", []string{"hoot"}} { + t.Run(fmt.Sprintf("non-empty: %v (%T)", nonEmpty, nonEmpty), func(t *testing.T) { + dflt := "default" + if defaultFunc(dflt, nonEmpty) == dflt { + t.Error("should not return default") + } + }) + } +}