diff --git a/go/fn/const.go b/go/fn/const.go index fcf624955..c5d5b8dc9 100644 --- a/go/fn/const.go +++ b/go/fn/const.go @@ -4,7 +4,7 @@ // 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 +// 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, diff --git a/go/fn/doc.go b/go/fn/doc.go index 066f79f20..fe3ca9bb1 100644 --- a/go/fn/doc.go +++ b/go/fn/doc.go @@ -15,17 +15,17 @@ /* Package fn provides the SDK to write KRM functions. -Before you start +# Before you start This fn SDK requires some basic KRM function Specification knowledge. To make the best usage of your time, we recommend you to be familiar with "ResourceList" before moving forward. - The KRM Function Specification, or "ResourceList", defines the standards of the inter-process communication between - the orchestrator (i.e. kpt CLI) and functions. + The KRM Function Specification, or "ResourceList", defines the standards of the inter-process communication between + the orchestrator (i.e. kpt CLI) and functions. See KRM Function Specification reference in https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md -KRM Function +# KRM Function A KRM function can mutate and/or validate Kubernetes resources in a ResourceList. @@ -37,13 +37,13 @@ Read more about how to use KRM functions in https://kpt.dev/book/04-using-functi Read more about how to develop a KRM function in https://kpt.dev/book/05-developing-functions/ A general workflow is: - 1. Reads the "ResourceList" object from STDIN. - 2. Gets the function configs from the "ResourceList.FunctionConfig". - 3. Mutate or validate the Kubernetes YAML resources from the "ResourceList.Items" field with the function configs. - 4. Writes the modified "ResourceList" to STDOUT. - 5. Write function message to "ResourceList.Results" with severity "Info", "Warning" or "Error" + 1. Reads the "ResourceList" object from STDIN. + 2. Gets the function configs from the "ResourceList.FunctionConfig". + 3. Mutate or validate the Kubernetes YAML resources from the "ResourceList.Items" field with the function configs. + 4. Writes the modified "ResourceList" to STDOUT. + 5. Write function message to "ResourceList.Results" with severity "Info", "Warning" or "Error" -KubeObject +# KubeObject The KubeObject is the basic unit to perform operations on KRM resources. @@ -65,7 +65,7 @@ SubObject.NestedInt64("replicas") Besides unstructured style, another way to use KubeObject is to purely work on the KubeObject/SubObject by calling "GetMap", "GetSlice", "UpsertMap" which expects the return to be SubObject(s) pointer. -AsMain +# AsMain "AsMain" is the main entrypoint. In most cases, you only need to provide the mutator or validation logic and have AsMain handles the ResourceList parsing, KRM resource field type detection, read from STDIN and write to STDOUT. @@ -73,6 +73,5 @@ handles the ResourceList parsing, KRM resource field type detection, read from S "AsMain" accepts a struct that either implement the ResourceListProcessor interface or Runner interface. See github.com/GoogleContainerTools/kpt-functions-sdk/go/fn/examples for detailed usage. - */ package fn diff --git a/go/fn/errors.go b/go/fn/errors.go index 7b687134c..36827fb6d 100644 --- a/go/fn/errors.go +++ b/go/fn/errors.go @@ -19,6 +19,8 @@ import ( "strings" ) +const pathDelimitor = "." + // ErrMissingFnConfig raises error if a required functionConfig is missing. type ErrMissingFnConfig struct{} @@ -26,38 +28,6 @@ func (ErrMissingFnConfig) Error() string { return "unable to find the functionConfig in the resourceList" } -// errKubeObjectFields raises if the KubeObject operation panics. -type errKubeObjectFields struct { - obj *KubeObject - fields []string -} - -func (e *errKubeObjectFields) Error() string { - return fmt.Sprintf("Resource(apiVersion=%v, kind=%v, Name=%v) has unmatched field type: `%v", - e.obj.GetAPIVersion(), e.obj.GetKind(), e.obj.GetName(), strings.Join(e.fields, "/")) -} - -// errSubObjectFields raises if the SubObject operation panics. -type errSubObjectFields struct { - fields []string -} - -func (e *errSubObjectFields) Error() string { - return fmt.Sprintf("SubObject has unmatched field type: `%v", strings.Join(e.fields, "/")) -} - -type errResultEnd struct { - obj *KubeObject - message string -} - -func (e *errResultEnd) Error() string { - if e.obj != nil { - return fmt.Sprintf("function is terminated by %v: %v", e.obj.ShortString(), e.message) - } - return fmt.Sprintf("function is terminated: %v", e.message) -} - type ErrAttemptToTouchUpstreamIdentifier struct{} func (ErrAttemptToTouchUpstreamIdentifier) Error() string { @@ -71,3 +41,25 @@ type ErrInternalAnnotation struct { func (e *ErrInternalAnnotation) Error() string { return e.Message } + +// NewErrUnmatchedField returns a ErrUnmatchedField error with the specific field path of a KubeObject that has the mismatched data type. +func NewErrUnmatchedField(obj SubObject, fields []string, expectedFieldType any) *ErrUnmatchedField { + relativefields := strings.Join(fields, pathDelimitor) + obj.fieldpath += pathDelimitor + relativefields + return &ErrUnmatchedField{ + SubObject: &obj, DataType: fmt.Sprintf("%T", expectedFieldType), + } +} + +// ErrUnmatchedField defines the error when a KubeObject's field paths has a different data type as expected +// e.g. ConfigMap `.data` is string map. If the a ConfigMap KubeObject calls `NestedInt("data")`, this error should raise. +type ErrUnmatchedField struct { + SubObject *SubObject + DataType string +} + +// Error returns the message to guide users +func (e *ErrUnmatchedField) Error() string { + return fmt.Sprintf("Resource(apiVersion=%v, kind=%v) has unmatched field type %q in fieldpath %v", + e.SubObject.parentGVK.GroupVersion(), e.SubObject.parentGVK.Kind, e.DataType, e.SubObject.fieldpath) +} diff --git a/go/fn/examples/example_asmain_runner_test.go b/go/fn/examples/example_asmain_runner_test.go index 94702c75b..8a1a67b2a 100644 --- a/go/fn/examples/example_asmain_runner_test.go +++ b/go/fn/examples/example_asmain_runner_test.go @@ -4,7 +4,7 @@ // 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 +// 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, @@ -30,14 +30,21 @@ type SetLabels struct { // `ctx` provides easy methods to add info, error or warning result to `ResourceList.Results`. // `items` is parsed from the STDIN "ResourceList.Items". // `functionConfig` is from the STDIN "ResourceList.FunctionConfig". The value has been assigned to the r.Labels -// the functionConfig is validated to have kind "SetLabels" and apiVersion "fn.kpt.dev/v1alpha1" +// +// the functionConfig is validated to have kind "SetLabels" and apiVersion "fn.kpt.dev/v1alpha1" func (r *SetLabels) Run(ctx *fn.Context, functionConfig *fn.KubeObject, items fn.KubeObjects, results *fn.Results) bool { for _, o := range items { for k, newLabel := range r.Labels { - o.SetLabel(k, newLabel) + err := o.SetLabel(k, newLabel) + if err != nil { + results.ErrorE(err) + // continue even if error occurs, we want the final results to show all errors. + } } } - results.Infof("updated labels") + if results.ExitCode() != 1 { + results.Infof("updated labels") + } return true } @@ -50,13 +57,15 @@ func (r *SetLabels) Run(ctx *fn.Context, functionConfig *fn.KubeObject, items fn // - apiVersion: v1 // kind: Service // metadata: -// name: example +// name: example +// // functionConfig: -// apiVersion: fn.kpt.dev/v1alpha1 -// kind: SetLabels -// metadata: -// name: setlabel-fn-config -func main() { +// +// apiVersion: fn.kpt.dev/v1alpha1 +// kind: SetLabels +// metadata: +// name: setlabel-fn-config +func Example_asMain() { file, _ := os.Open("./data/setlabels-resourcelist.yaml") defer file.Close() os.Stdin = file diff --git a/go/fn/examples/example_filter_GVK_test.go b/go/fn/examples/example_filter_GVK_test.go index 820babb1f..6a91eb59c 100644 --- a/go/fn/examples/example_filter_GVK_test.go +++ b/go/fn/examples/example_filter_GVK_test.go @@ -34,9 +34,14 @@ func updateReplicas(rl *fn.ResourceList) (bool, error) { return false, fn.ErrMissingFnConfig{} } var replicas int - rl.FunctionConfig.GetOrDie(&replicas, "replicas") + found, err := rl.FunctionConfig.NestedResource(&replicas, "replicas") + if err != nil || !found { + return found, err + } for i := range rl.Items.Where(fn.IsGVK("apps", "v1", "Deployment")) { - rl.Items[i].SetOrDie(replicas, "spec", "replicas") + if err := rl.Items[i].SetNestedField(replicas, "spec", "replicas"); err != nil { + return false, err + } } return true, nil } diff --git a/go/fn/examples/example_generator_test.go b/go/fn/examples/example_generator_test.go index 28a2a1501..f517d4a09 100644 --- a/go/fn/examples/example_generator_test.go +++ b/go/fn/examples/example_generator_test.go @@ -41,8 +41,8 @@ func generate(rl *fn.ResourceList) (bool, error) { return false, fn.ErrMissingFnConfig{} } - revision := rl.FunctionConfig.NestedStringOrDie("data", "revision") - id := rl.FunctionConfig.NestedStringOrDie("data", "id") + revision, _, _ := rl.FunctionConfig.NestedString("data", "revision") + id, _, _ := rl.FunctionConfig.NestedString("data", "id") js, err := fetchDashboard(revision, id) if err != nil { return false, fmt.Errorf("fetch dashboard: %v", err) diff --git a/go/fn/examples/example_kubeobject_test.go b/go/fn/examples/example_kubeobject_test.go index 88be007de..18137e26e 100644 --- a/go/fn/examples/example_kubeobject_test.go +++ b/go/fn/examples/example_kubeobject_test.go @@ -29,18 +29,24 @@ func Example_kubeObjectMutatePrimitiveField() { replicas := spec.GetInt("replicas") // mutate the replicas variable - spec.SetNestedIntOrDie(int(replicas)) + err := spec.SetNestedInt(int(replicas)) + if err != nil { + panic(err) + } } func Example_kubeObjectMutatePrimitiveSlice() { - finalizers := deployment.NestedStringSliceOrDie("metadata", "finalizers") + finalizers, _, _ := deployment.NestedStringSlice("metadata", "finalizers") // mutate the finalizers slice - deployment.SetNestedStringSliceOrDie(finalizers, "metadata", "finalizers") + err := deployment.SetNestedStringSlice(finalizers, "metadata", "finalizers") + if err != nil { + panic(err) + } } func Example_kubeObjectMutatePrimitiveMap() { - data := configMap.NestedStringMapOrDie("data") + data, _, _ := configMap.NestedStringMap("data") // mutate the data map err := deployment.SetNestedStringMap(data, "data") @@ -52,17 +58,21 @@ func Example_kubeObjectMutateStrongTypedField() { var newPodTemplate corev1.PodTemplate curPodTemplate := configMap.GetMap("spec").GetMap("template") // Assign the current PodTemplate value to newPodTemplate - // Use AsOrDie to AsMain handles the errors. - curPodTemplate.AsOrDie(&newPodTemplate) + // Use As to AsMain handles the errors. + err := curPodTemplate.As(&newPodTemplate) + if err != nil { + panic(err) + } // mutate the newPodTemplate object - err := deployment.SetNestedField(newPodTemplate, "spec", "template") + err = deployment.SetNestedField(newPodTemplate, "spec", "template") if err != nil { /* do something */ + panic(err) } } func Example_kubeObjectMutateStrongTypedSlice() { var containers []corev1.Container - found, err := deployment.Get(&containers, "spec", "template", "spec", "containers") + found, err := deployment.NestedResource(&containers, "spec", "template", "spec", "containers") if err != nil { /* do something */ } if !found { /* do something */ diff --git a/go/fn/examples/example_logger_injector_test.go b/go/fn/examples/example_logger_injector_test.go index dbc84f3f8..6d4bc8c52 100644 --- a/go/fn/examples/example_logger_injector_test.go +++ b/go/fn/examples/example_logger_injector_test.go @@ -41,7 +41,10 @@ func injectLogger(rl *fn.ResourceList) (bool, error) { } for i, obj := range rl.Items.Where(hasDesiredGVK) { var containers []corev1.Container - obj.GetOrDie(&containers, "spec", "template", "spec", "containers") + found, err := obj.NestedResource(&containers, "spec", "template", "spec", "containers") + if err != nil || !found { + return found, err + } foundTargetContainer := false for j, container := range containers { if container.Name == li.ContainerName { @@ -57,7 +60,9 @@ func injectLogger(rl *fn.ResourceList) (bool, error) { } containers = append(containers, c) } - rl.Items[i].SetOrDie(containers, "spec", "template", "spec", "containers") + if err = rl.Items[i].SetNestedField(containers, "spec", "template", "spec", "containers"); err != nil { + return false, nil + } } return true, nil } diff --git a/go/fn/examples/example_read_field_test.go b/go/fn/examples/example_read_field_test.go index a5910019c..0844449f1 100644 --- a/go/fn/examples/example_read_field_test.go +++ b/go/fn/examples/example_read_field_test.go @@ -31,13 +31,15 @@ func Example_aReadField() { func readField(rl *fn.ResourceList) (bool, error) { for _, obj := range rl.Items.Where(fn.IsGVK("apps", "v1", "Deployment")) { // Style 1: like using unstrucuted.Unstructured, get/set the value from field paths* - replicas := obj.NestedInt64OrDie("spec", "replicas") + replicas, _, _ := obj.NestedInt64("spec", "replicas") fn.Logf("replicas is %v\n", replicas) - paused := obj.NestedBoolOrDie("spec", "paused") + paused, _, _ := obj.NestedBool("spec", "paused") fn.Logf("paused is %v\n", paused) // Update strategy from Recreate to RollingUpdate. - if strategy := obj.NestedStringOrDie("spec", "strategy", "type"); strategy == "Recreate" { - obj.SetNestedStringOrDie("RollingUpdate", "spec", "strategy", "type") + if strategy, _, _ := obj.NestedString("spec", "strategy", "type"); strategy == "Recreate" { + if err := obj.SetNestedString("RollingUpdate", "spec", "strategy", "type"); err != nil { + return false, err + } } // Style 2: operate each resource layer via `GetMap` @@ -46,7 +48,9 @@ func readField(rl *fn.ResourceList) (bool, error) { fn.Logf("replicas is %v\n", replicas) nodeSelector := spec.GetMap("template").GetMap("spec").GetMap("nodeSelector") if nodeSelector.GetString("disktype") != "ssd" { - nodeSelector.SetNestedStringOrDie("ssd", "disktype") + if err := nodeSelector.SetNestedString("ssd", "disktype"); err != nil { + return false, err + } } } return true, nil diff --git a/go/fn/examples/example_read_functionConfig_test.go b/go/fn/examples/example_read_functionConfig_test.go index ebb070bdb..4fcf90474 100644 --- a/go/fn/examples/example_read_functionConfig_test.go +++ b/go/fn/examples/example_read_functionConfig_test.go @@ -32,7 +32,9 @@ func Example_bReadFunctionConfig() { func readFunctionConfig(rl *fn.ResourceList) (bool, error) { var sr SetReplicas - rl.FunctionConfig.AsOrDie(&sr) + if err := rl.FunctionConfig.As(&sr); err != nil { + return false, err + } fn.Logf("desired replicas is %v\n", sr.DesiredReplicas) return true, nil } diff --git a/go/fn/examples/example_set_field_test.go b/go/fn/examples/example_set_field_test.go index 815be3b09..38054f8c3 100644 --- a/go/fn/examples/example_set_field_test.go +++ b/go/fn/examples/example_set_field_test.go @@ -32,7 +32,9 @@ func setField(rl *fn.ResourceList) (bool, error) { for _, obj := range rl.Items { if obj.GetAPIVersion() == "apps/v1" && obj.GetKind() == "Deployment" { replicas := 10 - obj.SetOrDie(&replicas, "spec", "replicas") + if err := obj.SetNestedField(&replicas, "spec", "replicas"); err != nil { + return false, err + } } } return true, nil diff --git a/go/fn/examples/example_validator_test.go b/go/fn/examples/example_validator_test.go index 2201d2e5e..68aa154e7 100644 --- a/go/fn/examples/example_validator_test.go +++ b/go/fn/examples/example_validator_test.go @@ -32,7 +32,9 @@ func validator(rl *fn.ResourceList) (bool, error) { var results fn.Results for _, obj := range rl.Items.Where(hasDesiredGVK) { var runAsNonRoot bool - obj.GetOrDie(&runAsNonRoot, "spec", "template", "spec", "securityContext", "runAsNonRoot") + if _, err := obj.NestedResource(&runAsNonRoot, "spec", "template", "spec", "securityContext", "runAsNonRoot"); err != nil { + return false, err + } if !runAsNonRoot { results = append(results, fn.ConfigObjectResult("`spec.template.spec.securityContext.runAsNonRoot` must be set to true", obj, fn.Error)) } diff --git a/go/fn/examples/go.mod b/go/fn/examples/go.mod index 306f0602b..ed76c6059 100644 --- a/go/fn/examples/go.mod +++ b/go/fn/examples/go.mod @@ -27,21 +27,20 @@ require ( github.com/google/gofuzz v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/pretty v0.2.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.7.1 // indirect + github.com/stretchr/testify v1.8.0 // indirect github.com/xlab/treeprint v1.1.0 // indirect - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 // indirect k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect diff --git a/go/fn/examples/go.sum b/go/fn/examples/go.sum index a64ccc637..0109518c8 100644 --- a/go/fn/examples/go.sum +++ b/go/fn/examples/go.sum @@ -152,8 +152,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -217,8 +216,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -274,6 +272,7 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -291,16 +290,18 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= @@ -407,8 +408,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -554,8 +555,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -667,7 +666,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -684,8 +682,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -720,4 +719,3 @@ sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLz sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/go/fn/go.mod b/go/fn/go.mod index 6700c7f61..5798d2c3b 100644 --- a/go/fn/go.mod +++ b/go/fn/go.mod @@ -5,8 +5,8 @@ go 1.18 require ( github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20220720212527-133180134b93 github.com/go-errors/errors v1.0.1 - github.com/google/go-cmp v0.5.7 - github.com/stretchr/testify v1.7.1 + github.com/google/go-cmp v0.5.9 + github.com/stretchr/testify v1.8.0 k8s.io/apimachinery v0.24.0 // We must not include any core k8s APIs (e.g. k8s.io/api) in // the dependencies, depending on them will likely to cause version skew for @@ -28,18 +28,19 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/kr/pretty v0.3.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/xlab/treeprint v1.1.0 // indirect - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go/fn/go.sum b/go/fn/go.sum index 72b215251..0ed897469 100644 --- a/go/fn/go.sum +++ b/go/fn/go.sum @@ -151,8 +151,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -215,8 +215,9 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -270,6 +271,9 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -286,16 +290,18 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= @@ -402,8 +408,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -549,8 +555,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -678,8 +682,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go/fn/internal/maphelpers.go b/go/fn/internal/maphelpers.go index 6af95996d..640f6a28b 100644 --- a/go/fn/internal/maphelpers.go +++ b/go/fn/internal/maphelpers.go @@ -16,8 +16,20 @@ package internal import ( "fmt" + + "sigs.k8s.io/kustomize/kyaml/yaml" ) +func (o *MapVariant) GetRNode(fields ...string) (*yaml.RNode, bool, error) { + rn := &yaml.RNode{} + val, found, err := o.GetNestedValue(fields...) + if err != nil || !found { + return nil, found, err + } + rn.SetYNode(val.Node()) + return rn, found, err +} + func (o *MapVariant) GetNestedValue(fields ...string) (variant, bool, error) { current := o n := len(fields) diff --git a/go/fn/internal/test/go.mod b/go/fn/internal/test/go.mod index 375f760ce..9ab28dc4f 100644 --- a/go/fn/internal/test/go.mod +++ b/go/fn/internal/test/go.mod @@ -6,7 +6,7 @@ replace github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0 => ../.. require ( github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.8.0 k8s.io/api v0.24.0 k8s.io/apimachinery v0.24.0 sigs.k8s.io/kustomize/kyaml v0.13.7-0.20220418212550-9d5491c2e20c @@ -28,7 +28,6 @@ require ( github.com/google/gofuzz v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/pretty v0.2.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -36,12 +35,12 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/xlab/treeprint v1.1.0 // indirect - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 // indirect k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect diff --git a/go/fn/internal/test/go.sum b/go/fn/internal/test/go.sum index a64ccc637..0109518c8 100644 --- a/go/fn/internal/test/go.sum +++ b/go/fn/internal/test/go.sum @@ -152,8 +152,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -217,8 +216,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -274,6 +272,7 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -291,16 +290,18 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= @@ -407,8 +408,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -554,8 +555,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -667,7 +666,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -684,8 +682,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -720,4 +719,3 @@ sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLz sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/go/fn/object.go b/go/fn/object.go index 9e165f953..173206f5e 100644 --- a/go/fn/object.go +++ b/go/fn/object.go @@ -50,93 +50,70 @@ func ParseKubeObject(in []byte) (*KubeObject, error) { return asKubeObject(rlMap), nil } -// GetOrDie gets the value for a nested field located by fields. A pointer must -// be passed in, and the value will be stored in ptr. If the field doesn't -// exist, the ptr will be set to nil. It will panic if it encounters any error. -func (o *SubObject) GetOrDie(ptr interface{}, fields ...string) { - _, err := o.Get(ptr, fields...) - if err != nil { - panic(errSubObjectFields{fields: fields}) - } -} - // NestedBool returns the bool value, if the field exist and a potential error. func (o *SubObject) NestedBool(fields ...string) (bool, bool, error) { - var val bool - found, err := o.Get(&val, fields...) - return val, found, err -} - -// NestedBoolOrDie returns the bool value at `fields`. An empty string will be -// returned if the field is not found. It will panic if encountering any errors. -func (o *SubObject) NestedBoolOrDie(fields ...string) bool { - val, _, err := o.NestedBool(fields...) + b, found, err := o.obj.GetNestedBool(fields...) if err != nil { - panic(errSubObjectFields{fields: fields}) + var val bool + return val, found, NewErrUnmatchedField(*o, fields, val) } - return val + return b, found, nil } // NestedString returns the string value, if the field exist and a potential error. func (o *SubObject) NestedString(fields ...string) (string, bool, error) { - var val string - found, err := o.Get(&val, fields...) - return val, found, err -} - -// NestedStringOrDie returns the string value at fields. An empty string will be -// returned if the field is not found. It will panic if encountering any errors. -func (o *SubObject) NestedStringOrDie(fields ...string) string { - val, _, err := o.NestedString(fields...) + s, found, err := o.obj.GetNestedString(fields...) if err != nil { - panic(errSubObjectFields{fields: fields}) + var val string + return val, found, NewErrUnmatchedField(*o, fields, val) } - return val + return s, found, nil } // NestedFloat64 returns the float64 value, if the field exist and a potential error. func (o *SubObject) NestedFloat64(fields ...string) (float64, bool, error) { - var val float64 - found, err := o.Get(&val, fields...) - return val, found, err -} - -// NestedFloat64OrDie returns the string value at fields. 0 will be -// returned if the field is not found. It will panic if encountering any errors. -func (o *SubObject) NestedFloat64OrDie(fields ...string) float64 { - val, _, err := o.NestedFloat64(fields...) + f, found, err := o.obj.GetNestedFloat(fields...) if err != nil { - panic(errSubObjectFields{fields: fields}) + var val float64 + return val, found, NewErrUnmatchedField(*o, fields, val) } - return val + return f, found, nil } // NestedInt64 returns the int64 value, if the field exist and a potential error. func (o *SubObject) NestedInt64(fields ...string) (int64, bool, error) { - var val int64 - found, err := o.Get(&val, fields...) - return val, found, err + i, found, err := o.obj.GetNestedInt(fields...) + if err != nil { + var val int64 + return val, found, NewErrUnmatchedField(*o, fields, val) + } + return int64(i), found, nil } -// NestedInt64OrDie returns the string value at fields. An empty string will be -// returned if the field is not found. It will panic if encountering any errors. -func (o *SubObject) NestedInt64OrDie(fields ...string) int64 { - val, _, err := o.NestedInt64(fields...) +// NestedInt returns the int64 value, if the field exist and a potential error. +func (o *SubObject) NestedInt(fields ...string) (int, bool, error) { + i, found, err := o.obj.GetNestedInt(fields...) if err != nil { - panic(errSubObjectFields{fields: fields}) + var val int + return val, found, NewErrUnmatchedField(*o, fields, val) } - return val + return i, found, nil } // NestedSlice accepts a slice of `fields` which represents the path to the slice component and // return a slice of SubObjects as the first return value; whether the component exists or // not as the second return value, and errors as the third return value. func (o *SubObject) NestedSlice(fields ...string) (SliceSubObjects, bool, error) { + // Expect a struct like SubObject. + var obj struct{} var mapVariant *internal.MapVariant if len(fields) > 1 { m, found, err := o.obj.GetNestedMap(fields[:len(fields)-1]...) - if err != nil || !found { - return nil, found, err + if err != nil { + return nil, found, NewErrUnmatchedField(*o, fields, obj) + } + if !found { + return nil, found, nil } mapVariant = m } else { @@ -144,7 +121,7 @@ func (o *SubObject) NestedSlice(fields ...string) (SliceSubObjects, bool, error) } sliceVal, found, err := mapVariant.GetNestedSlice(fields[len(fields)-1]) if err != nil { - panic(errSubObjectFields{fields: fields}) + return nil, found, NewErrUnmatchedField(*o, fields, obj) } if !found { return nil, found, nil @@ -160,64 +137,67 @@ func (o *SubObject) NestedSlice(fields ...string) (SliceSubObjects, bool, error) return val, true, nil } -// NestedSliceOrDie accepts a slice of `fields` which represents the path to the slice component and -// return a slice of SubObjects. -// - It returns nil if the fields does not exist. -// - It panics with errSubObjectFields error if the field is not a slice type. -func (o *SubObject) NestedSliceOrDie(fields ...string) SliceSubObjects { - val, _, err := o.NestedSlice(fields...) +// NestedMap returns a map[string]string value of a nested field, false if not found and an error if not a map[string]string type. +func (o *SubObject) NestedSubObject(fields ...string) (SubObject, bool, error) { + var variant SubObject + m, found, err := o.obj.GetNestedMap(fields...) if err != nil { - panic(errSubObjectFields{fields: fields}) + return variant, found, NewErrUnmatchedField(*o, fields, variant) } - return val + if !found { + return variant, found, nil + } + err = m.Node().Decode(variant) + return variant, true, err } // NestedMap returns a map[string]string value of a nested field, false if not found and an error if not a map[string]string type. -func (o *SubObject) NestedStringMap(fields ...string) (map[string]string, bool, error) { - var variant map[string]string - found, err := o.Get(&variant, fields...) - if err != nil || !found { - return nil, found, err +func (o *SubObject) NestedResource(ptr interface{}, fields ...string) (bool, error) { + if ptr == nil || reflect.ValueOf(ptr).Kind() != reflect.Ptr { + return false, fmt.Errorf("ptr must be a pointer to an object") } - return variant, found, err -} - -// NestedStringMapOrDie returns a map[string]string value of a nested field, if the fields does not exist, it returns -// empty map[string]string. It will panic if the fields are not map[string]string type. -func (o *SubObject) NestedStringMapOrDie(fields ...string) map[string]string { - val, _, err := o.NestedStringMap(fields...) + k := reflect.TypeOf(ptr).Elem().Kind() + if k != reflect.Struct && k != reflect.Map { + return false, fmt.Errorf("expect struct or map, got %T", ptr) + } + m, found, err := o.obj.GetNestedMap(fields...) if err != nil { - panic(errSubObjectFields{fields: fields}) + o.fieldpath = o.fieldpath + "." + strings.Join(fields, ".") + return found, NewErrUnmatchedField(*o, fields, ptr) } - return val + if !found { + return found, nil + } + err = m.Node().Decode(ptr) + return true, err } // NestedMap returns a map[string]string value of a nested field, false if not found and an error if not a map[string]string type. -func (o *SubObject) NestedStringSlice(fields ...string) ([]string, bool, error) { - var variant []string - found, err := o.Get(&variant, fields...) - if err != nil || !found { - return nil, found, err +func (o *SubObject) NestedStringMap(fields ...string) (map[string]string, bool, error) { + var variant map[string]string + m, found, err := o.obj.GetNestedMap(fields...) + if err != nil { + return variant, found, NewErrUnmatchedField(*o, fields, variant) + } + if !found { + return variant, false, nil } + err = m.Node().Decode(&variant) return variant, found, err } -// NestedMapOrDie returns a map[string]string value of a nested field. -// It will panic if the fields are not map[string]string type. -func (o *SubObject) NestedStringSliceOrDie(fields ...string) []string { - val, _, err := o.NestedStringSlice(fields...) +// NestedStringSlice returns a map[string]string value of a nested field, false if not found and an error if not a map[string]string type. +func (o *SubObject) NestedStringSlice(fields ...string) ([]string, bool, error) { + var variant []string + s, found, err := o.obj.GetNestedSlice(fields...) if err != nil { - panic(errSubObjectFields{fields: fields}) + return variant, found, NewErrUnmatchedField(*o, fields, variant) } - return val -} - -// RemoveNestedFieldOrDie removes the field located by fields if found. It will panic if it -// encounters any error. -func (o *SubObject) RemoveNestedFieldOrDie(fields ...string) { - if _, err := o.RemoveNestedField(fields...); err != nil { - panic(errSubObjectFields{fields: fields}) + if !found { + return variant, false, nil } + err = s.Node().Decode(&variant) + return variant, true, err } // RemoveNestedField removes the field located by fields if found. It returns if the field @@ -235,96 +215,6 @@ func (o *SubObject) RemoveNestedField(fields ...string) (bool, error) { return found, nil } -// Get gets the value for a nested field located by fields. A pointer must be -// passed in, and the value will be stored in ptr. ptr can be a concrete type -// (e.g. string, []corev1.Container, []string, corev1.Pod, map[string]string) or -// a yaml.RNode. yaml.RNode should be used if you are dealing with comments that -// is more than what LineComment, HeadComment, SetLineComment and -// SetHeadComment can handle. It returns if the field is found and a -// potential error. -func (o *SubObject) Get(ptr interface{}, fields ...string) (bool, error) { - found, err := func() (bool, error) { - if o == nil { - return false, fmt.Errorf("the object doesn't exist") - } - if ptr == nil || reflect.ValueOf(ptr).Kind() != reflect.Ptr { - return false, fmt.Errorf("ptr must be a pointer to an object") - } - - if rn, ok := ptr.(*yaml.RNode); ok { - val, found, err := o.obj.GetNestedValue(fields...) - if err != nil || !found { - return found, err - } - rn.SetYNode(val.Node()) - return found, err - } - - switch k := reflect.TypeOf(ptr).Elem().Kind(); k { - case reflect.Struct, reflect.Map: - m, found, err := o.obj.GetNestedMap(fields...) - if err != nil || !found { - return found, err - } - err = m.Node().Decode(ptr) - return found, err - case reflect.Slice: - s, found, err := o.obj.GetNestedSlice(fields...) - if err != nil || !found { - return found, err - } - err = s.Node().Decode(ptr) - return found, err - case reflect.String: - s, found, err := o.obj.GetNestedString(fields...) - if err != nil || !found { - return found, err - } - *(ptr.(*string)) = s - return found, nil - case reflect.Int, reflect.Int64: - i, found, err := o.obj.GetNestedInt(fields...) - if err != nil || !found { - return found, err - } - if k == reflect.Int { - *(ptr.(*int)) = i - } else if k == reflect.Int64 { - *(ptr.(*int64)) = int64(i) - } - return found, nil - case reflect.Float64: - f, found, err := o.obj.GetNestedFloat(fields...) - if err != nil || !found { - return found, err - } - *(ptr.(*float64)) = f - return found, nil - case reflect.Bool: - b, found, err := o.obj.GetNestedBool(fields...) - if err != nil || !found { - return found, err - } - *(ptr.(*bool)) = b - return found, nil - default: - return false, fmt.Errorf("unhandled kind %s", k) - } - }() - if err != nil { - return found, fmt.Errorf("unable to get fields %v as %T with error: %w", fields, ptr, err) - } - return found, nil -} - -// SetOrDie sets a nested field located by fields to the value provided as val. -// It will panic if it encounters any error. -func (o *SubObject) SetOrDie(val interface{}, fields ...string) { - if err := o.SetNestedField(val, fields...); err != nil { - panic(errSubObjectFields{fields: fields}) - } -} - // onLockedFields locks the SubObject fields which are expected for kpt internal use only. func (o *SubObject) onLockedFields(val interface{}, fields ...string) error { if o.hasUpstreamIdentifier(val, fields...) { @@ -418,66 +308,26 @@ func (o *SubObject) SetNestedField(val interface{}, fields ...string) error { return nil } -// SetNestedIntOrDie sets the `fields` value to int `value`. It panics if the fields type is not int. -func (o *SubObject) SetNestedIntOrDie(value int, fields ...string) { - err := o.SetNestedInt(value, fields...) - if err != nil { - panic(errSubObjectFields{fields: fields}) - } -} - // SetNestedInt sets the `fields` value to int `value`. It returns error if the fields type is not int. func (o *SubObject) SetNestedInt(value int, fields ...string) error { return o.SetNestedField(value, fields...) } -// SetNestedBoolOrDie sets the `fields` value to bool `value`. It panics if the fields type is not bool. -func (o *SubObject) SetNestedBoolOrDie(value bool, fields ...string) { - err := o.SetNestedBool(value, fields...) - if err != nil { - panic(errSubObjectFields{fields: fields}) - } -} - // SetNestedBool sets the `fields` value to bool `value`. It returns error if the fields type is not bool. func (o *SubObject) SetNestedBool(value bool, fields ...string) error { return o.SetNestedField(value, fields...) } -// SetNestedStringOrDie sets the `fields` value to string `value`. It panics if the fields type is not string. -func (o *SubObject) SetNestedStringOrDie(value string, fields ...string) { - err := o.SetNestedString(value, fields...) - if err != nil { - panic(errSubObjectFields{fields: fields}) - } -} - -// SetNestedStringOrDie sets the `fields` value to string `value`. It returns error if the fields type is not string. +// SetNestedString sets the `fields` value to string `value`. It returns error if the fields type is not string. func (o *SubObject) SetNestedString(value string, fields ...string) error { return o.SetNestedField(value, fields...) } -// SetNestedStringMapOrDie sets the `fields` value to map[string]string `value`. It panics if the fields type is not map[string]string. -func (o *SubObject) SetNestedStringMapOrDie(value map[string]string, fields ...string) { - err := o.SetNestedStringMap(value, fields...) - if err != nil { - panic(errSubObjectFields{fields: fields}) - } -} - // SetNestedStringMap sets the `fields` value to map[string]string `value`. It returns error if the fields type is not map[string]string. func (o *SubObject) SetNestedStringMap(value map[string]string, fields ...string) error { return o.SetNestedField(value, fields...) } -// SetNestedStringSliceOrDie sets the `fields` value to []string `value`. It panics if the fields type is not []string. -func (o *SubObject) SetNestedStringSliceOrDie(value []string, fields ...string) { - err := o.SetNestedStringSlice(value, fields...) - if err != nil { - panic(errSubObjectFields{fields: fields}) - } -} - // SetNestedStringSlice sets the `fields` value to []string `value`. It returns error if the fields type is not []string. func (o *SubObject) SetNestedStringSlice(value []string, fields ...string) error { return o.SetNestedField(value, fields...) @@ -486,8 +336,7 @@ func (o *SubObject) SetNestedStringSlice(value []string, fields ...string) error // LineComment returns the line comment, if the target field exist and a // potential error. func (o *KubeObject) LineComment(fields ...string) (string, bool, error) { - rn := &yaml.RNode{} - found, err := o.Get(rn, fields...) + rn, found, err := o.obj.GetRNode(fields...) if !found || err != nil { return "", found, err } @@ -497,8 +346,7 @@ func (o *KubeObject) LineComment(fields ...string) (string, bool, error) { // HeadComment returns the head comment, if the target field exist and a // potential error. func (o *KubeObject) HeadComment(fields ...string) (string, bool, error) { - rn := &yaml.RNode{} - found, err := o.Get(rn, fields...) + rn, found, err := o.obj.GetRNode(fields...) if !found || err != nil { return "", found, err } @@ -506,8 +354,7 @@ func (o *KubeObject) HeadComment(fields ...string) (string, bool, error) { } func (o *KubeObject) SetLineComment(comment string, fields ...string) error { - rn := &yaml.RNode{} - found, err := o.Get(rn, fields...) + rn, found, err := o.obj.GetRNode(fields...) if err != nil { return err } @@ -519,8 +366,7 @@ func (o *KubeObject) SetLineComment(comment string, fields ...string) error { } func (o *KubeObject) SetHeadComment(comment string, fields ...string) error { - rn := &yaml.RNode{} - found, err := o.Get(rn, fields...) + rn, found, err := o.obj.GetRNode(fields...) if err != nil { return err } @@ -531,14 +377,6 @@ func (o *KubeObject) SetHeadComment(comment string, fields ...string) error { return nil } -// AsOrDie converts a KubeObject to the desired typed object. ptr must -// be a pointer to a typed object. It will panic if it encounters an error. -func (o *SubObject) AsOrDie(ptr interface{}) { - if err := o.As(ptr); err != nil { - panic(errSubObjectFields{fields: nil}) - } -} - // As converts a KubeObject to the desired typed object. ptr must be // a pointer to a typed object. func (o *SubObject) As(ptr interface{}) error { @@ -569,7 +407,8 @@ func NewFromTypedObject(v interface{}) (*KubeObject, error) { case reflect.Struct, reflect.Map: m, err = internal.TypedObjectToMapVariant(v) case reflect.Slice: - return nil, fmt.Errorf("The typed object should be of a reflect.Struct or reflect.Map, got reflect.Slice") + return nil, fmt.Errorf( + "the typed object should be of a reflect.Struct or reflect.Map, got reflect.Slice") } if err != nil { return nil, err @@ -671,10 +510,8 @@ func (o *KubeObject) GetAPIVersion() string { return apiVersion } -func (o *KubeObject) SetAPIVersion(apiVersion string) { - if err := o.obj.SetNestedString(apiVersion, "apiVersion"); err != nil { - panic(fmt.Errorf("cannot set apiVersion '%v': %v", apiVersion, err)) - } +func (o *KubeObject) SetAPIVersion(apiVersion string) error { + return o.obj.SetNestedString(apiVersion, "apiVersion") } func (o *KubeObject) GetKind() string { @@ -682,10 +519,8 @@ func (o *KubeObject) GetKind() string { return kind } -func (o *KubeObject) SetKind(kind string) { - if err := o.SetNestedField(kind, "kind"); err != nil { - panic(fmt.Errorf("cannot set kind '%v': %v", kind, err)) - } +func (o *KubeObject) SetKind(kind string) error { + return o.SetNestedField(kind, "kind") } func (o *KubeObject) GetName() string { @@ -693,10 +528,8 @@ func (o *KubeObject) GetName() string { return s } -func (o *KubeObject) SetName(name string) { - if err := o.SetNestedField(name, "metadata", "name"); err != nil { - panic(fmt.Errorf("cannot set metadata name '%v': %v", name, err)) - } +func (o *KubeObject) SetName(name string) error { + return o.SetNestedField(name, "metadata", "name") } func (o *KubeObject) GetNamespace() string { @@ -725,20 +558,19 @@ func (o *KubeObject) HasNamespace() bool { return found } -func (o *KubeObject) SetNamespace(name string) { - if err := o.SetNestedField(name, "metadata", "namespace"); err != nil { - panic(fmt.Errorf("cannot set namespace '%v': %v", name, err)) - } +func (o *KubeObject) SetNamespace(name string) error { + return o.SetNestedField(name, "metadata", "namespace") } -func (o *KubeObject) SetAnnotation(k, v string) { +func (o *KubeObject) SetAnnotation(k, v string) error { // Keep upstream-identifier untouched from users if k == UpstreamIdentifier { - panic(ErrAttemptToTouchUpstreamIdentifier{}) + return ErrAttemptToTouchUpstreamIdentifier{} } if err := o.SetNestedField(v, "metadata", "annotations", k); err != nil { - panic(fmt.Errorf("cannot set metadata annotations '%v': %v", k, err)) + return fmt.Errorf("cannot set metadata annotations '%v': %v", k, err) } + return nil } // GetAnnotations returns all annotations. @@ -778,10 +610,8 @@ func (o *KubeObject) RemoveAnnotationsIfEmpty() error { return nil } -func (o *KubeObject) SetLabel(k, v string) { - if err := o.SetNestedField(v, "metadata", "labels", k); err != nil { - panic(fmt.Errorf("cannot set metadata labels '%v': %v", k, err)) - } +func (o *KubeObject) SetLabel(k, v string) error { + return o.SetNestedField(v, "metadata", "labels", k) } // Label returns one label with key k. @@ -958,11 +788,16 @@ func (o *KubeObject) IsEmpty() bool { } func NewEmptyKubeObject() *KubeObject { - return &KubeObject{SubObject{internal.NewMap(nil)}} + subObject := SubObject{parentGVK: schema.GroupVersionKind{}, obj: internal.NewMap(nil), fieldpath: ""} + return &KubeObject{subObject} } -func asKubeObject(obj *internal.MapVariant) *KubeObject { - return &KubeObject{SubObject{obj}} +func asKubeObject(mapVariant *internal.MapVariant) *KubeObject { + group, _, _ := mapVariant.GetNestedString("group") + version, _, _ := mapVariant.GetNestedString("version") + kind, _, _ := mapVariant.GetNestedString("kind") + gvk := schema.GroupVersionKind{Group: group, Version: version, Kind: kind} + return &KubeObject{SubObject{parentGVK: gvk, obj: mapVariant, fieldpath: ""}} } func (o *KubeObject) node() *internal.MapVariant { @@ -971,57 +806,64 @@ func (o *KubeObject) node() *internal.MapVariant { func rnodeToKubeObject(rn *yaml.RNode) *KubeObject { mapVariant := internal.NewMap(rn.YNode()) - return &KubeObject{SubObject{mapVariant}} + return asKubeObject(mapVariant) } // SubObject represents a map within a KubeObject type SubObject struct { - obj *internal.MapVariant + parentGVK schema.GroupVersionKind + fieldpath string + obj *internal.MapVariant } func (o *SubObject) UpsertMap(k string) *SubObject { m := o.obj.UpsertMap(k) - return &SubObject{obj: m} + return &SubObject{obj: m, parentGVK: o.parentGVK, fieldpath: o.fieldpath + "." + k} } // GetMap accepts a single key `k` whose value is expected to be a map. It returns // the map in the form of a SubObject pointer. // It panic with ErrSubObjectFields error if the field cannot be represented as a SubObject. func (o *SubObject) GetMap(k string) *SubObject { - var variant yaml.RNode - found, err := o.Get(&variant, k) + var rn yaml.RNode + val, found, err := o.obj.GetNestedValue(k) if err != nil || !found { return nil } - return &SubObject{obj: internal.NewMap(variant.YNode())} + rn.SetYNode(val.Node()) + return &SubObject{obj: internal.NewMap(rn.YNode()), parentGVK: o.parentGVK, fieldpath: o.fieldpath + "." + k} } // GetBool accepts a single key `k` whose value is expected to be a boolean. It returns // the int value of the `k`. It panic with errSubObjectFields error if the // field is not an integer type. func (o *SubObject) GetBool(k string) bool { - return o.NestedBoolOrDie(k) + val, _, _ := o.NestedBool(k) + return val } // GetInt accepts a single key `k` whose value is expected to be an integer. It returns // the int value of the `k`. It panic with errSubObjectFields error if the // field is not an integer type. func (o *SubObject) GetInt(k string) int64 { - return o.NestedInt64OrDie(k) + val, _, _ := o.NestedInt64(k) + return val } // GetString accepts a single key `k` whose value is expected to be a string. It returns // the value of the `k`. It panic with errSubObjectFields error if the // field is not a string type. func (o *SubObject) GetString(k string) string { - return o.NestedStringOrDie(k) + val, _, _ := o.NestedString(k) + return val } // GetSlice accepts a single key `k` whose value is expected to be a slice. It returns // the value as a slice of SubObject. It panic with errSubObjectFields error if the // field is not a slice type. func (o *SubObject) GetSlice(k string) SliceSubObjects { - return o.NestedSliceOrDie(k) + val, _, _ := o.NestedSlice(k) + return val } // SetSlice sets the SliceSubObjects to the given field. It creates the field if not exists. If returns error if the field exists but not a slice type. @@ -1044,3 +886,9 @@ func (s *SliceSubObjects) MarshalJSON() ([]byte, error) { } return yaml.NewRNode(node).MarshalJSON() } + +// DEPRECATED: Please use type-aware functions instead. +// To parse struct object, please use `NestedResource`. +func (o *SubObject) Get(_ interface{}, _ ...string) (bool, error) { + return false, fmt.Errorf("unsupported") +} diff --git a/go/fn/object_test.go b/go/fn/object_test.go index a729cc452..22bd549c0 100644 --- a/go/fn/object_test.go +++ b/go/fn/object_test.go @@ -356,29 +356,36 @@ func TestNilFnConfigResourceList(t *testing.T) { t.Errorf("Nil KubeObject shall not have the field path `not-exist` exist, and not expect errors") } } + var err error // Check that nil FunctionConfig should be editable. { - rl.FunctionConfig.SetKind("CustomFn") + err = rl.FunctionConfig.SetKind("CustomFn") + assert.NoError(t, err) if rl.FunctionConfig.GetKind() != "CustomFn" { t.Errorf("Nil KubeObject cannot call SetKind()") } - rl.FunctionConfig.SetAPIVersion("kpt.fn/v1") + err = rl.FunctionConfig.SetAPIVersion("kpt.fn/v1") + assert.NoError(t, err) if rl.FunctionConfig.GetAPIVersion() != "kpt.fn/v1" { t.Errorf("Nil KubeObject cannot call SetAPIVersion()") } - rl.FunctionConfig.SetName("test") + err = rl.FunctionConfig.SetName("test") + assert.NoError(t, err) if rl.FunctionConfig.GetName() != "test" { t.Errorf("Nil KubeObject cannot call SetName()") } - rl.FunctionConfig.SetNamespace("test-ns") + err = rl.FunctionConfig.SetNamespace("test-ns") + assert.NoError(t, err) if rl.FunctionConfig.GetNamespace() != "test-ns" { t.Errorf("Nil KubeObject cannot call SetNamespace()") } - rl.FunctionConfig.SetAnnotation("k", "v") + err = rl.FunctionConfig.SetAnnotation("k", "v") + assert.NoError(t, err) if rl.FunctionConfig.GetAnnotation("k") != "v" { t.Errorf("Nil KubeObject cannot call SetAnnotation()") } - rl.FunctionConfig.SetLabel("k", "v") + err = rl.FunctionConfig.SetLabel("k", "v") + assert.NoError(t, err) if rl.FunctionConfig.GetLabel("k") != "v" { t.Errorf("Nil KubeObject cannot call SetLabel()") } @@ -432,22 +439,22 @@ func TestGetNestedFields(t *testing.T) { rl, _ := ParseResourceList(deploymentResourceList) deployment := rl.Items[0] // Style 1, using concatenated fields in NestedType function. - if intVal := deployment.NestedInt64OrDie("spec", "replicas"); intVal != 3 { + if intVal, _, _ := deployment.NestedInt64("spec", "replicas"); intVal != 3 { t.Errorf("deployment .spec.replicas expected to be 3, got %v", intVal) } - if boolVal := deployment.NestedBoolOrDie("spec", "paused"); boolVal != true { + if boolVal, _, _ := deployment.NestedBool("spec", "paused"); boolVal != true { t.Errorf("deployment .spec.paused expected to be true, got %v", boolVal) } - if stringVal := deployment.NestedStringOrDie("spec", "strategy", "type"); stringVal != "Recreate" { + if stringVal, _, _ := deployment.NestedString("spec", "strategy", "type"); stringVal != "Recreate" { t.Errorf("deployment .spec.strategy.type expected to be `Recreate`, got %v", stringVal) } - if stringMapVal := deployment.NestedStringMapOrDie("spec", "template", "spec", "nodeSelector"); !reflect.DeepEqual(stringMapVal, map[string]string{"disktype": "ssd"}) { + if stringMapVal, _, _ := deployment.NestedStringMap("spec", "template", "spec", "nodeSelector"); !reflect.DeepEqual(stringMapVal, map[string]string{"disktype": "ssd"}) { t.Errorf("deployment .spec.template.spec.nodeSelector expected to get {`disktype`: `ssd`}, got %v", stringMapVal) } - if sliceVal := deployment.NestedSliceOrDie("spec", "template", "spec", "containers"); sliceVal[0].NestedStringOrDie("name") != "nginx" { - t.Errorf("deployment .spec.template.spec.containers[0].name expected to get `nginx`, got %v", sliceVal[0].NestedStringOrDie("name")) + if sliceVal, _, _ := deployment.NestedSlice("spec", "template", "spec", "containers"); sliceVal[0].GetString("name") != "nginx" { + t.Errorf("deployment .spec.template.spec.containers[0].name expected to get `nginx`, got %v", sliceVal[0].GetString("name")) } - if stringSliceVal := deployment.NestedStringSliceOrDie("spec", "fakeStringSlice"); !reflect.DeepEqual(stringSliceVal, []string{"test1", "test2"}) { + if stringSliceVal, _, _ := deployment.NestedStringSlice("spec", "fakeStringSlice"); !reflect.DeepEqual(stringSliceVal, []string{"test1", "test2"}) { t.Errorf("deployment .spec.fakeStringSlice expected to get [`test1`, `test2`], got %v", stringSliceVal) } // Style 2, get each struct layer by type. @@ -466,50 +473,54 @@ func TestGetNestedFields(t *testing.T) { t.Errorf("deployment .spec.template.spec.nodeSelector expected to get {`disktype`: `ssd`}, got %v", stringMapVal.GetString("disktype")) } if sliceVal := tmplSpec.GetSlice("containers"); sliceVal[0].GetString("name") != "nginx" { - t.Errorf("deployment .spec.template.spec.containers[0].name expected to get `nginx`, got %v", sliceVal[0].NestedStringOrDie("name")) + t.Errorf("deployment .spec.template.spec.containers[0].name expected to get `nginx`, got %v", sliceVal[0].GetString("name")) } } func TestSetNestedFields(t *testing.T) { + var err error o := NewEmptyKubeObject() - o.SetNestedStringOrDie("some starlark script...", "source") - if stringVal := o.NestedStringOrDie("source"); stringVal != "some starlark script..." { + err = o.SetNestedString("some starlark script...", "source") + assert.NoError(t, err) + if stringVal, _, _ := o.NestedString("source"); stringVal != "some starlark script..." { t.Errorf("KubeObject .source expected to get \"some starlark script...\", got %v", stringVal) } - o.SetNestedStringMapOrDie(map[string]string{"tag1": "abc", "tag2": "test1"}, "tags") - if stringMapVal := o.NestedStringOrDie("tags", "tag2"); stringMapVal != "test1" { + err = o.SetNestedStringMap(map[string]string{"tag1": "abc", "tag2": "test1"}, "tags") + assert.NoError(t, err) + if stringMapVal, _, _ := o.NestedString("tags", "tag2"); stringMapVal != "test1" { t.Errorf("KubeObject .tags.tag2 expected to get `test1`, got %v", stringMapVal) } - o.SetNestedStringSliceOrDie([]string{"lable1", "lable2"}, "labels") - if stringSliceVal := o.NestedStringSliceOrDie("labels"); !reflect.DeepEqual(stringSliceVal, []string{"lable1", "lable2"}) { + err = o.SetNestedStringSlice([]string{"lable1", "lable2"}, "labels") + assert.NoError(t, err) + if stringSliceVal, _, _ := o.NestedStringSlice("labels"); !reflect.DeepEqual(stringSliceVal, []string{"lable1", "lable2"}) { t.Errorf("KubeObject .labels expected to get [`lable1`, `lable2`], got %v", stringSliceVal) } } func TestInternalAnnotationsUntouchable(t *testing.T) { + var err error o := NewEmptyKubeObject() // Verify the "upstream-identifier" annotation cannot be changed via SetNestedStringMap - o.SetNestedStringMapOrDie(map[string]string{"owner": "kpt"}, "metadata", "annotations") - if stringMapVal := o.NestedStringMapOrDie("metadata", "annotations"); !reflect.DeepEqual(stringMapVal, map[string]string{"owner": "kpt"}) { + err = o.SetNestedStringMap(map[string]string{"owner": "kpt"}, "metadata", "annotations") + assert.NoError(t, err) + if stringMapVal, _, _ := o.NestedStringMap("metadata", "annotations"); !reflect.DeepEqual(stringMapVal, map[string]string{"owner": "kpt"}) { t.Errorf("annotations cannot be set via SetNestedStringMap, got %v", stringMapVal) } - err := o.SetNestedStringMap(map[string]string{UpstreamIdentifier: "apps|Deployment|default|dp"}, "metadata", "annotations") + err = o.SetNestedStringMap(map[string]string{UpstreamIdentifier: "apps|Deployment|default|dp"}, "metadata", "annotations") if !errors.Is(ErrAttemptToTouchUpstreamIdentifier{}, err) { t.Errorf("set internal annotation via SetNestedStringMap() failed, expect %e, got %e", ErrAttemptToTouchUpstreamIdentifier{}, err) } // Verify the "upstream-identifier" annotation cannot be changed via SetAnnotation - o.SetAnnotation("owner", "kpt") + err = o.SetAnnotation("owner", "kpt") + assert.NoError(t, err) if o.GetAnnotation("owner") != "kpt" { t.Errorf("annotations cannot be set via SetAnnotation(), got %v", o.GetAnnotation("owner")) } - defer func() { - if r := recover(); r == nil { - t.Errorf("set internal annotation via SetAnnotation() expect panic (%v), got pass", - ErrAttemptToTouchUpstreamIdentifier{}) - } - }() - o.SetAnnotation(UpstreamIdentifier, "apps|Deployment|default|dp") + if err = o.SetAnnotation(UpstreamIdentifier, "apps|Deployment|default|dp"); err == nil { + t.Errorf("set internal annotation via SetAnnotation() expect panic (%v), got pass", + ErrAttemptToTouchUpstreamIdentifier{}) + } // Verify the "upstream-identifier" annotation cannot be changed via SetNestedField err = o.SetNestedField(map[string]string{UpstreamIdentifier: "apps|Deployment|default|dp"}, "metadata", "annotations") @@ -703,7 +714,8 @@ metadata: // add the label "g=h" to all resources with annotation "bar=foo" for _, obj := range input.Where(HasAnnotations(map[string]string{"bar": "foo"})) { - obj.SetLabel("g", "h") + err = obj.SetLabel("g", "h") + assert.NoError(t, err) } assert.Equal(t, input.String(), `apiVersion: apps/v1 kind: Deployment diff --git a/go/fn/origin.go b/go/fn/origin.go index a84d33d40..5a95479c1 100644 --- a/go/fn/origin.go +++ b/go/fn/origin.go @@ -4,7 +4,7 @@ // 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 +// 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, @@ -90,13 +90,13 @@ func (o *KubeObject) GetId() *ResourceIdentifier { } } -func parseUpstreamIdentifier(upstreamId string) *ResourceIdentifier { +func parseUpstreamIdentifier(upstreamId string) (*ResourceIdentifier, error) { upstreamId = strings.TrimSpace(upstreamId) r := regexp.MustCompile(upstreamIdentifierRegexPattern) match := r.FindStringSubmatch(upstreamId) if match == nil { - panic(ErrInternalAnnotation{Message: fmt.Sprintf("annotation %v: %v is in bad format. expect %q", - UpstreamIdentifier, upstreamId, upstreamIdentifierFormat)}) + return nil, &ErrInternalAnnotation{Message: fmt.Sprintf("annotation %v: %v is in bad format. expect %q", + UpstreamIdentifier, upstreamId, upstreamIdentifierFormat)} } matchGroups := make(map[string]string) for i, name := range r.SubexpNames() { @@ -109,18 +109,18 @@ func parseUpstreamIdentifier(upstreamId string) *ResourceIdentifier { Kind: matchGroups[regexPatternKind], Namespace: matchGroups[regexPatterNamespace], Name: matchGroups[regexPatternName], - } + }, nil } // GetOriginId provides the `ResourceIdentifier` to identify the upstream origin of a KRM resource. // This origin is generated and maintained by kpt pkg management and is stored in the `internal.kpt.dev/upstream-identiifer` annotation. // If a resource does not have an upstream origin, we use its current meta resource ID instead. -func (o *KubeObject) GetOriginId() *ResourceIdentifier { +func (o *KubeObject) GetOriginId() (*ResourceIdentifier, error) { upstreamId := o.GetAnnotation(UpstreamIdentifier) if upstreamId != "" { return parseUpstreamIdentifier(upstreamId) } - return o.GetId() + return o.GetId(), nil } // HasUpstreamOrigin tells whether a resource is sourced from an upstream package resource. diff --git a/go/fn/origin_test.go b/go/fn/origin_test.go index 6ce6563d4..7103a92a5 100644 --- a/go/fn/origin_test.go +++ b/go/fn/origin_test.go @@ -4,7 +4,7 @@ // 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 +// 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, @@ -35,17 +35,18 @@ metadata: func TestOrigin(t *testing.T) { noGroup, _ := ParseKubeObject(resource) - if noGroup.GetOriginId().String() != "|ConfigMap|example|example" { - t.Fatalf("GetOriginId() expect %v, got %v", "|ConfigMap|example|example", noGroup.GetOriginId()) + + if id, _ := noGroup.GetOriginId(); id.String() != "|ConfigMap|example|example" { + t.Fatalf("GetOriginId() expect %v, got %v", "|ConfigMap|example|example", id) } defaultNamespace, _ := ParseKubeObject(resource) if defaultNamespace.GetId().String() != "|ConfigMap|default|cm" { t.Fatalf("GetId() expect %v, got %v", "|ConfigMap|default|cm", defaultNamespace.GetId()) } sameIdAndOrigin, _ := ParseKubeObject(resourceCustom) - if sameIdAndOrigin.GetOriginId().String() != sameIdAndOrigin.GetId().String() { + if id, _ := sameIdAndOrigin.GetOriginId(); id.String() != sameIdAndOrigin.GetId().String() { t.Fatalf("expect the origin and id the same if upstream-identifier is not given, got OriginID %v, got ID %v", - sameIdAndOrigin.GetOriginId(), sameIdAndOrigin.GetId()) + id, sameIdAndOrigin.GetId()) } unknownNamespace, _ := ParseKubeObject(resourceCustom) if unknownNamespace.GetId().Namespace != UnknownNamespace { diff --git a/go/fn/resourcelist.go b/go/fn/resourcelist.go index 03791352b..e19dd4ec7 100644 --- a/go/fn/resourcelist.go +++ b/go/fn/resourcelist.go @@ -9,6 +9,7 @@ import ( "sort" "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn/internal" + "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -128,9 +129,13 @@ func ParseResourceList(in []byte) (*ResourceList, error) { // toYNode converts the ResourceList to the yaml.Node representation. func (rl *ResourceList) toYNode() (*yaml.Node, error) { reMap := internal.NewMap(nil) - reObj := &KubeObject{SubObject{reMap}} - reObj.SetAPIVersion(kio.ResourceListAPIVersion) - reObj.SetKind(kio.ResourceListKind) + reObj := &KubeObject{SubObject{obj: reMap, parentGVK: schema.GroupVersionKind{}, fieldpath: ""}} + if err := reObj.SetAPIVersion(kio.ResourceListAPIVersion); err != nil { + return nil, err + } + if err := reObj.SetKind(kio.ResourceListKind); err != nil { + return nil, err + } if rl.Items != nil && len(rl.Items) > 0 { itemsSlice := internal.NewSliceVariant() diff --git a/go/fn/result.go b/go/fn/result.go index 18074e65d..4cb66b8d0 100644 --- a/go/fn/result.go +++ b/go/fn/result.go @@ -140,6 +140,7 @@ func (r *Results) Errorf(format string, a ...any) { // ErrorE writes the `error` as an Error level `result` to the results slice. // e.g. +// // err := error.New("test) // results.ErrorE(err) func (r *Results) ErrorE(err error) { @@ -149,6 +150,7 @@ func (r *Results) ErrorE(err error) { // Infof writes an Info level `result` to the results slice. It accepts arguments according to a format specifier. // e.g. +// // results.Infof("update %v %q ", "ConfigMap", "kptfile.kpt.dev") func (r *Results) Infof(format string, a ...any) { infoResult := &Result{Severity: Info, Message: fmt.Sprintf(format, a...)} @@ -157,6 +159,7 @@ func (r *Results) Infof(format string, a ...any) { // Warningf writes a Warning level `result` to the results slice. It accepts arguments according to a format specifier. // e.g. +// // results.Warningf("bad kind %q", "invalid") func (r *Results) Warningf(format string, a ...any) { warnResult := &Result{Severity: Warning, Message: fmt.Sprintf(format, a...)} diff --git a/go/fn/run.go b/go/fn/run.go index d49acace4..a378648ac 100644 --- a/go/fn/run.go +++ b/go/fn/run.go @@ -64,39 +64,6 @@ func Run(p ResourceListProcessor, input []byte) (out []byte, err error) { if err != nil { return nil, err } - defer func() { - // if we run into a panic, we still need to log the error to Results, - // and return the ResourceList and error. - v := recover() - if v != nil { - switch t := v.(type) { - case errKubeObjectFields: - err = &t - case *errKubeObjectFields: - err = t - case errSubObjectFields: - err = &t - case *errSubObjectFields: - err = t - case errResultEnd: - err = &t - case *errResultEnd: - err = t - case ErrAttemptToTouchUpstreamIdentifier: - err = &t - case *ErrAttemptToTouchUpstreamIdentifier: - err = t - case ErrInternalAnnotation: - err = &t - case *ErrInternalAnnotation: - err = t - default: - panic(v) - } - rl.LogResult(err) - out, _ = rl.ToYAML() - } - }() success, fnErr := p.Process(rl) out, yamlErr := rl.ToYAML() if yamlErr != nil {