From c2b6dc57659e8871e8fb151fd8c9c72e9d7d8ad8 Mon Sep 17 00:00:00 2001 From: William Leese Date: Mon, 20 Feb 2023 13:22:39 +0100 Subject: [PATCH 1/2] Add a function to retrieve errors --- .../go/apply-replacements/generated/docs.go | 2 - functions/go/apply-replacements/run_js.go | 39 +++++++++++++--- .../applysetters/apply_setters.go | 6 +-- functions/go/apply-setters/generated/docs.go | 4 +- functions/go/apply-setters/main.go | 2 +- functions/go/set-labels/run_js.go | 44 ++++++++++++++----- functions/go/set-namespace/run_js.go | 43 ++++++++++++++---- functions/go/starlark/run_js.go | 41 ++++++++++++++--- 8 files changed, 139 insertions(+), 42 deletions(-) diff --git a/functions/go/apply-replacements/generated/docs.go b/functions/go/apply-replacements/generated/docs.go index 56163be92..d27f5c26a 100644 --- a/functions/go/apply-replacements/generated/docs.go +++ b/functions/go/apply-replacements/generated/docs.go @@ -1,5 +1,3 @@ - - // Code generated by "mdtogo"; DO NOT EDIT. package generated diff --git a/functions/go/apply-replacements/run_js.go b/functions/go/apply-replacements/run_js.go index 13a1058fe..9da33a156 100644 --- a/functions/go/apply-replacements/run_js.go +++ b/functions/go/apply-replacements/run_js.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "syscall/js" "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-replacements/replacements" @@ -25,8 +24,13 @@ import ( ) func run() error { + resourceList := []byte("") + // Register js function processResourceList to the globals. - js.Global().Set("processResourceList", resourceListProcessorWrapper()) + js.Global().Set("processResourceList", resourceListProcessorWrapper(&resourceList)) + // Provide a second function that serves purely to also return the resourceList, + // in case of the above function failing. + js.Global().Set("processResourceListErrors", resourceListProcessorErrors(&resourceList)) // We need to ensure that the Go program is running when JavaScript calls it. // Otherwise, it will complain the Go program has already exited. <-make(chan bool) @@ -37,19 +41,40 @@ func applyReplacements(input []byte) ([]byte, error) { return fn.Run(fn.ResourceListProcessorFunc(replacements.ApplyReplacements), []byte(input)) } -func resourceListProcessorWrapper() js.Func { - // TODO: figure out a better way to surface a golang error to JS environment. - // Currently error is surfaced as a string. - jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { +func resourceListProcessorWrapper(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { return "Invalid number of arguments passed" } input := args[0].String() applied, err := applyReplacements([]byte(input)) if err != nil { - return fmt.Errorf("unable to process resource list:", err.Error()) + *resourceList = applied + return "unable to process resource list: " + err.Error() } + *resourceList = applied return string(applied) }) + return jsonFunc } + +func resourceListProcessorErrors(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { + rl, err := fn.ParseResourceList(*resourceList) + if err != nil { + return "" + } + if len(rl.Results) == 0 { + return "" + } + errorMessages := "" + for _, r := range(rl.Results) { + if (r.Severity == "error") { + errorMessages += r.Message + } + } + return errorMessages + }) + return jsonFunc +} \ No newline at end of file diff --git a/functions/go/apply-setters/applysetters/apply_setters.go b/functions/go/apply-setters/applysetters/apply_setters.go index ae101ff27..0bcee7a4f 100644 --- a/functions/go/apply-setters/applysetters/apply_setters.go +++ b/functions/go/apply-setters/applysetters/apply_setters.go @@ -82,7 +82,6 @@ For input ApplySetters [name: env, value: "[stage, prod]"], qthe yaml node is tr environments: # kpt-set: ${env} - stage - prod - */ func (as *ApplySetters) visitMapping(object *yaml.RNode, path string) error { return object.VisitFields(func(node *yaml.MapNode) error { @@ -180,15 +179,16 @@ e.g.for input of scalar node 'nginx:1.7.1 # kpt-set: ${image}:${tag}' in the yam apiVersion: v1 ... - image: nginx:1.7.1 # kpt-set: ${image}:${tag} + + image: nginx:1.7.1 # kpt-set: ${image}:${tag} and for input ApplySetters [[name: image, value: ubuntu], [name: tag, value: 1.8.0]] The yaml node is transformed to apiVersion: v1 ... - image: ubuntu:1.8.0 # kpt-set: ${image}:${tag} + image: ubuntu:1.8.0 # kpt-set: ${image}:${tag} */ func (as *ApplySetters) visitScalar(object *yaml.RNode, path string) error { if object.IsNil() { diff --git a/functions/go/apply-setters/generated/docs.go b/functions/go/apply-setters/generated/docs.go index 181f319c6..aa93fbc28 100644 --- a/functions/go/apply-setters/generated/docs.go +++ b/functions/go/apply-setters/generated/docs.go @@ -1,5 +1,3 @@ - - // Code generated by "mdtogo"; DO NOT EDIT. package generated @@ -83,7 +81,7 @@ Invoke the function: Alternatively, setter values can be passed as key-value pairs in the CLI - $ kpt fn eval --image gcr.io/kpt-fn/apply-setters:unstable -- image=ubuntu replicas=3 + $ kpt fn eval --image gcr.io/kpt-fn/apply-setters:unstable -- tag=1.16.2 nginx-replicas=3 Modified resource looks like the following: diff --git a/functions/go/apply-setters/main.go b/functions/go/apply-setters/main.go index ad8fbf5d5..87b2ee1d5 100644 --- a/functions/go/apply-setters/main.go +++ b/functions/go/apply-setters/main.go @@ -11,7 +11,7 @@ import ( kyaml "sigs.k8s.io/kustomize/kyaml/yaml" ) -//nolint +// nolint func main() { asp := ApplySettersProcessor{} cmd := command.Build(&asp, command.StandaloneEnabled, false) diff --git a/functions/go/set-labels/run_js.go b/functions/go/set-labels/run_js.go index bfb8aa629..62c03129f 100644 --- a/functions/go/set-labels/run_js.go +++ b/functions/go/set-labels/run_js.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "syscall/js" "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-labels/setlabels" @@ -25,8 +24,12 @@ import ( ) func run() error { - // Register js function processResourceList to the globals. - js.Global().Set("processResourceList", resourceListProcessorWrapper()) + resourceList := []byte("") + + js.Global().Set("processResourceList", resourceListProcessorWrapper(&resourceList)) + // Provide a second function that serves purely to also return the resourceList, + // in case of the above function failing. + js.Global().Set("processResourceListErrors", resourceListProcessorErrors(&resourceList)) // We need to ensure that the Go program is running when JavaScript calls it. // Otherwise, it will complain the Go program has already exited. <-make(chan bool) @@ -38,19 +41,40 @@ func transformLabels(input []byte) ([]byte, error) { return fn.Run(runner, []byte(input)) } -func resourceListProcessorWrapper() js.Func { - // TODO: figure out a better way to surface a golang error to JS environment. - // Currently error is surfaced as a string. - jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { +func resourceListProcessorWrapper(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { return "Invalid number of arguments passed" } input := args[0].String() - transformed, err := transformLabels([]byte(input)) + applied, err := transformLabels([]byte(input)) + if err != nil { + *resourceList = applied + return "unable to process resource list: " + err.Error() + } + *resourceList = applied + return string(applied) + }) + + return jsonFunc +} + +func resourceListProcessorErrors(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { + rl, err := fn.ParseResourceList(*resourceList) if err != nil { - return fmt.Errorf("unable to process resource list:", err.Error()) + return "" + } + if len(rl.Results) == 0 { + return "" + } + errorMessages := "" + for _, r := range(rl.Results) { + if (r.Severity == "error") { + errorMessages += r.Message + } } - return string(transformed) + return errorMessages }) return jsonFunc } diff --git a/functions/go/set-namespace/run_js.go b/functions/go/set-namespace/run_js.go index b8cca0ccd..9a846a69e 100644 --- a/functions/go/set-namespace/run_js.go +++ b/functions/go/set-namespace/run_js.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "syscall/js" "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace/transformer" @@ -25,8 +24,13 @@ import ( ) func run() error { + resourceList := []byte("") + // Register js function processResourceList to the globals. - js.Global().Set("processResourceList", resourceListProcessorWrapper()) + js.Global().Set("processResourceList", resourceListProcessorWrapper(&resourceList)) + // Provide a second function that serves purely to also return the resourceList, + // in case of the above function failing. + js.Global().Set("processResourceListErrors", resourceListProcessorErrors(&resourceList)) // We need to ensure that the Go program is running when JavaScript calls it. // Otherwise, it will complain the Go program has already exited. <-make(chan bool) @@ -37,19 +41,40 @@ func transformNamespace(input []byte) ([]byte, error) { return fn.Run(fn.ResourceListProcessorFunc(transformer.Run), []byte(input)) } -func resourceListProcessorWrapper() js.Func { - // TODO: figure out a better way to surface a golang error to JS environment. - // Currently error is surfaced as a string. - jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { +func resourceListProcessorWrapper(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { return "Invalid number of arguments passed" } input := args[0].String() - transformed, err := transformNamespace([]byte(input)) + applied, err := transformNamespace([]byte(input)) + if err != nil { + *resourceList = applied + return "unable to process resource list: " + err.Error() + } + *resourceList = applied + return string(applied) + }) + + return jsonFunc +} + +func resourceListProcessorErrors(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { + rl, err := fn.ParseResourceList(*resourceList) if err != nil { - return fmt.Errorf("unable to process resource list:", err.Error()) + return "" + } + if len(rl.Results) == 0 { + return "" + } + errorMessages := "" + for _, r := range(rl.Results) { + if (r.Severity == "error") { + errorMessages += r.Message + } } - return string(transformed) + return errorMessages }) return jsonFunc } diff --git a/functions/go/starlark/run_js.go b/functions/go/starlark/run_js.go index 71279bc44..fa797c5a5 100644 --- a/functions/go/starlark/run_js.go +++ b/functions/go/starlark/run_js.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "syscall/js" "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/starlark/starlark" @@ -25,8 +24,15 @@ import ( ) func run() error { + resourceList := []byte("") + // Register js function processResourceList to the globals. - js.Global().Set("processResourceList", resourceListProcessorWrapper()) + js.Global().Set("processResourceList", resourceListProcessorWrapper(&resourceList)) + // Provide a second function that serves purely to also return the resourceList, + // in case of the above function failing. + js.Global().Set("processResourceListErrors", resourceListProcessorErrors(&resourceList)) + + // We need to ensure that the Go program is running when JavaScript calls it. // Otherwise, it will complain the Go program has already exited. <-make(chan bool) @@ -37,19 +43,40 @@ func executeStarlark(input []byte) ([]byte, error) { return fn.Run(fn.ResourceListProcessorFunc(starlark.Process), []byte(input)) } -func resourceListProcessorWrapper() js.Func { - // TODO: figure out a better way to surface a golang error to JS environment. - // Currently error is surfaced as a string. - jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { +func resourceListProcessorWrapper(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { return "Invalid number of arguments passed" } input := args[0].String() applied, err := executeStarlark([]byte(input)) if err != nil { - return fmt.Errorf("unable to process resource list:", err.Error()) + *resourceList = applied + return "unable to process resource list: " + err.Error() } + *resourceList = applied return string(applied) }) + return jsonFunc } + +func resourceListProcessorErrors(resourceList *[]byte) js.Func { + jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { + rl, err := fn.ParseResourceList(*resourceList) + if err != nil { + return "" + } + if len(rl.Results) == 0 { + return "" + } + errorMessages := "" + for _, r := range(rl.Results) { + if (r.Severity == "error") { + errorMessages += r.Message + } + } + return errorMessages + }) + return jsonFunc +} \ No newline at end of file From 33ab68237cc55c64e86b36cbc51d8a9bfbcff738 Mon Sep 17 00:00:00 2001 From: William Leese Date: Tue, 21 Feb 2023 21:03:44 +0100 Subject: [PATCH 2/2] address review comments --- functions/go/apply-replacements/run_js.go | 2 ++ functions/go/set-labels/run_js.go | 2 ++ functions/go/set-namespace/run_js.go | 2 ++ functions/go/starlark/run_js.go | 2 ++ 4 files changed, 8 insertions(+) diff --git a/functions/go/apply-replacements/run_js.go b/functions/go/apply-replacements/run_js.go index 9da33a156..b9e3e1416 100644 --- a/functions/go/apply-replacements/run_js.go +++ b/functions/go/apply-replacements/run_js.go @@ -59,6 +59,8 @@ func resourceListProcessorWrapper(resourceList *[]byte) js.Func { return jsonFunc } +// This funcion will return ALL Results with Severity error, +// meaning unrelated errors may also be included. func resourceListProcessorErrors(resourceList *[]byte) js.Func { jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { rl, err := fn.ParseResourceList(*resourceList) diff --git a/functions/go/set-labels/run_js.go b/functions/go/set-labels/run_js.go index 62c03129f..1b99583dd 100644 --- a/functions/go/set-labels/run_js.go +++ b/functions/go/set-labels/run_js.go @@ -41,6 +41,8 @@ func transformLabels(input []byte) ([]byte, error) { return fn.Run(runner, []byte(input)) } +// This funcion will return ALL Results with Severity error, +// meaning unrelated errors may also be included. func resourceListProcessorWrapper(resourceList *[]byte) js.Func { jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { diff --git a/functions/go/set-namespace/run_js.go b/functions/go/set-namespace/run_js.go index 9a846a69e..1e4af6409 100644 --- a/functions/go/set-namespace/run_js.go +++ b/functions/go/set-namespace/run_js.go @@ -41,6 +41,8 @@ func transformNamespace(input []byte) ([]byte, error) { return fn.Run(fn.ResourceListProcessorFunc(transformer.Run), []byte(input)) } +// This funcion will return ALL Results with Severity error, +// meaning unrelated errors may also be included. func resourceListProcessorWrapper(resourceList *[]byte) js.Func { jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { diff --git a/functions/go/starlark/run_js.go b/functions/go/starlark/run_js.go index fa797c5a5..94c46f07a 100644 --- a/functions/go/starlark/run_js.go +++ b/functions/go/starlark/run_js.go @@ -61,6 +61,8 @@ func resourceListProcessorWrapper(resourceList *[]byte) js.Func { return jsonFunc } +// This funcion will return ALL Results with Severity error, +// meaning unrelated errors may also be included. func resourceListProcessorErrors(resourceList *[]byte) js.Func { jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { rl, err := fn.ParseResourceList(*resourceList)