diff --git a/cmd/apigee-go-gen/main.go b/cmd/apigee-go-gen/main.go index 0e67715..768485f 100644 --- a/cmd/apigee-go-gen/main.go +++ b/cmd/apigee-go-gen/main.go @@ -37,6 +37,9 @@ func main() { } if showStack { + if isMultiErrors { + err = multiErrors.Errors[0] + } _, _ = fmt.Fprintf(os.Stderr, "%s\n", errors.Wrap(err, 0).Stack()) } os.Exit(1) diff --git a/cmd/apigee-go-gen/render/apiproxy/cmd.go b/cmd/apigee-go-gen/render/apiproxy/cmd.go index 0c82521..43e3e86 100644 --- a/cmd/apigee-go-gen/render/apiproxy/cmd.go +++ b/cmd/apigee-go-gen/render/apiproxy/cmd.go @@ -26,6 +26,7 @@ import ( ) var cFlags = render.NewCommonFlags() +var debug = flags.NewBool(false) var dryRun = flags.NewEnum([]string{"xml", "yaml"}) var validate = flags.NewBool(true) var setValue = flags.NewSetAny(cFlags.Values) @@ -42,7 +43,7 @@ var Cmd = &cobra.Command{ Short: "Generate an API proxy bundle from a template", Long: Usage(), RunE: func(cmd *cobra.Command, args []string) error { - if strings.TrimSpace(string(cFlags.OutputFile)) == "" && dryRun.IsUnset() { + if strings.TrimSpace(string(cFlags.OutputFile)) == "" && dryRun.IsUnset() && bool(debug) == false { return errors.New("required flag(s) \"output\" not set") } @@ -50,7 +51,7 @@ var Cmd = &cobra.Command{ return v1.NewAPIProxyModel(input) } - return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value) + return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value, bool(debug)) }, } @@ -59,7 +60,8 @@ func init() { Cmd.Flags().VarP(&cFlags.TemplateFile, "template", "t", `path to main template"`) Cmd.Flags().VarP(&cFlags.IncludeList, "include", "i", `path to helper templates (globs allowed)`) Cmd.Flags().VarP(&cFlags.OutputFile, "output", "o", `output directory or file`) - Cmd.Flags().VarP(&dryRun, "dry-run", "d", `prints rendered API proxy template to stdout"`) + Cmd.Flags().VarP(&debug, "debug", "", `prints rendered template before transforming into API proxy"`) + Cmd.Flags().VarP(&dryRun, "dry-run", "d", `prints rendered template after transforming into API Proxy"`) Cmd.Flags().VarP(&validate, "validate", "v", "check for unknown elements") Cmd.Flags().Var(&setValue, "set", `sets a key=value (bool,float,string), e.g. "use_ssl=true"`) Cmd.Flags().Var(&setValueStr, "set-string", `sets key=value (string), e.g. "base_path=/v1/hello" `) diff --git a/cmd/apigee-go-gen/render/sharedflow/cmd.go b/cmd/apigee-go-gen/render/sharedflow/cmd.go index 66f4791..28fb83b 100644 --- a/cmd/apigee-go-gen/render/sharedflow/cmd.go +++ b/cmd/apigee-go-gen/render/sharedflow/cmd.go @@ -26,6 +26,7 @@ import ( ) var cFlags = render.NewCommonFlags() +var debug = flags.NewBool(false) var dryRun = flags.NewEnum([]string{"xml", "yaml"}) var validate = flags.NewBool(true) var setValue = flags.NewSetAny(cFlags.Values) @@ -42,7 +43,7 @@ var Cmd = &cobra.Command{ Short: "Generate a shared flow bundle from a template", Long: Usage(), RunE: func(cmd *cobra.Command, args []string) error { - if strings.TrimSpace(string(cFlags.OutputFile)) == "" && dryRun.IsUnset() { + if strings.TrimSpace(string(cFlags.OutputFile)) == "" && dryRun.IsUnset() && bool(debug) == false { return errors.New("required flag(s) \"output\" not set") } @@ -50,7 +51,7 @@ var Cmd = &cobra.Command{ return v1.NewSharedFlowBundleModel(input) } - return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value) + return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value, bool(debug)) }, } @@ -59,7 +60,8 @@ func init() { Cmd.Flags().VarP(&cFlags.TemplateFile, "template", "t", `path to main template"`) Cmd.Flags().VarP(&cFlags.IncludeList, "include", "i", `path to helper templates (globs allowed)`) Cmd.Flags().VarP(&cFlags.OutputFile, "output", "o", `output directory or file`) - Cmd.Flags().VarP(&dryRun, "dry-run", "d", `prints rendered template to stdout"`) + Cmd.Flags().VarP(&debug, "debug", "", `prints rendered template before transforming into shared flow"`) + Cmd.Flags().VarP(&dryRun, "dry-run", "d", `prints rendered template after transforming into shared flow"`) Cmd.Flags().VarP(&validate, "validate", "v", "check for unknown elements") Cmd.Flags().Var(&setValue, "set", `sets a key=value (bool,float,string), e.g. "use_ssl=true"`) Cmd.Flags().Var(&setValueStr, "set-string", `sets key=value (string), e.g. "base_path=/v1/hello" `) diff --git a/docs/render/commands/render-apiproxy.md b/docs/render/commands/render-apiproxy.md index eb3cce5..5a7a8c5 100644 --- a/docs/render/commands/render-apiproxy.md +++ b/docs/render/commands/render-apiproxy.md @@ -39,7 +39,8 @@ The `render apiproxy` command takes the following parameters: -t, --template string path to main template" -i, --include string path to helper templates (globs allowed) -o, --output string output directory or file - -d, --dry-run enum(xml|yaml) prints rendered API proxy template to stdout" + --debug boolean prints rendered template before transforming into API proxy" + -d, --dry-run enum(xml|yaml) prints rendered template after transforming into API Proxy" -v, --validate boolean check for unknown elements --set string sets a key=value (bool,float,string), e.g. "use_ssl=true" --set-string string sets key=value (string), e.g. "base_path=/v1/hello" diff --git a/docs/render/commands/render-sharedflow.md b/docs/render/commands/render-sharedflow.md index 545e419..7f35289 100644 --- a/docs/render/commands/render-sharedflow.md +++ b/docs/render/commands/render-sharedflow.md @@ -31,7 +31,8 @@ The `render sharedflow` command takes the following parameters: -t, --template string path to main template" -i, --include string path to helper templates (globs allowed) -o, --output string output directory or file - -d, --dry-run enum(xml|yaml) prints rendered template to stdout" + --debug boolean prints rendered template before transforming into shared flow" + -d, --dry-run enum(xml|yaml) prints rendered template after transforming into shared flow" -v, --validate boolean check for unknown elements --set string sets a key=value (bool,float,string), e.g. "use_ssl=true" --set-string string sets key=value (string), e.g. "base_path=/v1/hello" diff --git a/docs/render/using-built-in-helpers.md b/docs/render/using-built-in-helpers.md index 7f122eb..b5b5b99 100644 --- a/docs/render/using-built-in-helpers.md +++ b/docs/render/using-built-in-helpers.md @@ -24,7 +24,7 @@ The template rendering commands include a set of built-in helper functions to as func include(template string, data any) string ``` -This function allows you to invoke your own [custom helper functions](./using-custom-helpers.md) +This function allows you to invoke your own [custom helper functions](./using-custom-helpers.md). e.g. @@ -32,6 +32,16 @@ e.g. {{ include "sayHello" $data }} ``` +This function can also be used to render a file. + +e.g. + +```shell +{{ include "./path/to/file.yaml" . }} +``` + +> The path to template file to render is relative to the parent template file. + ### **os_writefile** ```go diff --git a/docs/render/using-openapi-spec.md b/docs/render/using-openapi-spec.md index c20e827..6cdeaba 100644 --- a/docs/render/using-openapi-spec.md +++ b/docs/render/using-openapi-spec.md @@ -56,11 +56,18 @@ apigee-go-gen render apiproxy \ --output ./out/apiproxies/petstore ``` -## Dry run +## Dry run / Debug For rapid development, you can print the rendered template directly to stdout in your terminal. -Add the `--dry-run xml` or `--dry-run yaml` flag. e.g. +Add the `--dry-run xml` or `--dry-run yaml` flag. + +Note that dry-run is only useful when the rendered template produces valid YAML. + +If your template has issues, and it does not produce valid YAML, you can use the `--debug true` flag. + +This will print out the rendered template before even attempting to parse it as YAML. + === "XML output" ```shell diff --git a/examples/templates/oas3/apiproxy.yaml b/examples/templates/oas3/apiproxy.yaml index 7d58bf2..2c3980a 100755 --- a/examples/templates/oas3/apiproxy.yaml +++ b/examples/templates/oas3/apiproxy.yaml @@ -18,14 +18,15 @@ APIProxy: DisplayName: {{ $.Values.spec.info.title }} Description: |- {{ $.Values.spec.info.description | nindent 4 }} -Policies: - $ref: ./policies.yaml#/ +Policies: {{ include "./policies.yaml" . | nindent 2 }} ProxyEndpoints: - ProxyEndpoint: .name: default PreFlow: .name: PreFlow Request: + - Step: + Name: Spike-Arrest - Step: Name: OAS-Validate Flows: diff --git a/examples/templates/oas3/policies.yaml b/examples/templates/oas3/policies.yaml index d407f4b..e56a317 100644 --- a/examples/templates/oas3/policies.yaml +++ b/examples/templates/oas3/policies.yaml @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ---- + - OASValidation: .continueOnError: false .enabled: true @@ -37,13 +37,5 @@ StatusCode: 404 ReasonPhrase: Not found IgnoreUnresolvedVariables: true -- MessageLogging: - .name: ML-Logging-OK - Syslog: - Message: '[3f509b58 tag="{organization.name}.{apiproxy.name}.{environment.name}"] Weather request for WOEID {request.queryparam.w}.' - Host: example.loggly.com - Port: 514 - Protocol: TCP - FormatMessage: true - DateFormat: yyMMdd-HH:mm:ss.SSS - logLevel: ALERT +- {{ include "./policies/message-logging.yaml" . | indent 2 | trim }} +- {{ include "./policies/spike-arrest.yaml" . | indent 2 | trim }} \ No newline at end of file diff --git a/examples/templates/oas3/policies/message-logging.yaml b/examples/templates/oas3/policies/message-logging.yaml new file mode 100644 index 0000000..416adcd --- /dev/null +++ b/examples/templates/oas3/policies/message-logging.yaml @@ -0,0 +1,23 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +MessageLogging: + .name: ML-Logging-OK + Syslog: + Message: '[3f509b58 tag="{organization.name}.{apiproxy.name}.{environment.name}"] Weather request for WOEID {request.queryparam.w}.' + Host: example.loggly.com + Port: 514 + Protocol: TCP + FormatMessage: true + DateFormat: yyMMdd-HH:mm:ss.SSS + logLevel: ALERT \ No newline at end of file diff --git a/examples/templates/oas3/policies/spike-arrest.yaml b/examples/templates/oas3/policies/spike-arrest.yaml new file mode 100644 index 0000000..1a64e71 --- /dev/null +++ b/examples/templates/oas3/policies/spike-arrest.yaml @@ -0,0 +1,25 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +SpikeArrest: + .continueOnError: false + .enabled: true + .name: Spike-Arrest + DisplayName: Spike Arrest + Properties: {} + Identifier: + .ref: client.ip + # The example below sets the Rate value dynamically from the render context + # You can pass the value like this --set spike_arrest_rate=300pm in the command line + # If the value is unset, it defaults to 100pm + Rate: {{ or ($.Values.spike_arrest_rate) "100pm" }} \ No newline at end of file diff --git a/pkg/common/resources/helper_functions.txt b/pkg/common/resources/helper_functions.txt index b07bf6b..de72638 100644 --- a/pkg/common/resources/helper_functions.txt +++ b/pkg/common/resources/helper_functions.txt @@ -1,5 +1,18 @@ include(template string, data any) - Invoke an existing template e.g {{ include "sayHello" $data }} + Render a pre-defined template, e.g. + + {{ include "greet" "Miguel" }} + + The template must be defined ahead of time with a "define" block, e.g. + + {{- define "greet" -}} + {{- $name := . -}} + Hello {{ $name }} ! + {{- end -}} + + You can also use this function to render an existing file. e.g. + + {{ include "./path/to/file.yaml" . }} os_writefile(dest string, content string) Write a file to the output directory diff --git a/pkg/render/model.go b/pkg/render/model.go index a067f66..d5a7120 100644 --- a/pkg/render/model.go +++ b/pkg/render/model.go @@ -25,7 +25,7 @@ import ( "path/filepath" ) -func GenerateBundle(createModelFunc func(string) (v1.Model, error), cFlags *CommonFlags, validate bool, dryRun string) error { +func GenerateBundle(createModelFunc func(string) (v1.Model, error), cFlags *CommonFlags, validate bool, dryRun string, debug bool) error { var err error bundleOutputFile := cFlags.OutputFile @@ -51,9 +51,17 @@ func GenerateBundle(createModelFunc func(string) (v1.Model, error), cFlags *Comm return errors.New(err) } + if debug { + fmt.Println(string(rendered)) + return nil + } + rendered, err = ResolveYAML(rendered, templateFile) if err != nil { - return err + return utils.MultiError{ + Errors: []error{ + err, + errors.New("rendered template appears to not be valid YAML. Use --debug=true flag to inspect rendered output")}} } err = os.WriteFile(string(cFlags.OutputFile), rendered, os.ModePerm) diff --git a/pkg/render/render.go b/pkg/render/render.go index 8010663..bc9a7b5 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -19,7 +19,6 @@ import ( "fmt" "github.com/Masterminds/sprig/v3" "github.com/apigee/apigee-go-gen/pkg/flags" - "github.com/apigee/apigee-go-gen/pkg/utils" "github.com/bmatcuk/doublestar/v4" "github.com/go-errors/errors" "github.com/gosimple/slug" @@ -29,6 +28,7 @@ import ( "path/filepath" "reflect" "regexp" + "slices" "strings" "text/template" ) @@ -100,20 +100,6 @@ func CreateTemplate(templateFile string, includeList []string, outputFile string return nil, err } - //make a copy of the template to create a unique temporary main file - tmpFile, err := os.CreateTemp("", "tpl_*_"+filepath.Base(templateFile)) - if err != nil { - return nil, errors.New(err) - } - defer func() { utils.MustClose(tmpFile) }() - - err = utils.CopyFile(tmpFile.Name(), templateFile) - if err != nil { - return nil, err - } - - includeMatches = append([]string{tmpFile.Name()}, includeMatches...) - helperFuncs := map[string]any{} blankFunc := func(args ...any) string { @@ -209,23 +195,55 @@ func CreateTemplate(templateFile string, includeList []string, outputFile string return "" } + includeStack := []string{fmt.Sprintf("file:%s", templateFile)} + includeFunc := func(args ...any) string { if len(args) < 0 { panic("include function requires at least one argument") } - templateName := args[0].(string) - templateText := fmt.Sprintf(`{{- template "%s" . }}`, templateName) + arg0 := args[0].(string) + + var err error + var templateBytes []byte + var templateName string + + parentTemplateIndex := slices.IndexFunc(includeStack, func(elem string) bool { + return strings.Index(elem, "file:") == 0 + }) + + parentTemplateFile := strings.TrimPrefix(includeStack[parentTemplateIndex], "file:") + targetTemplateFile := filepath.Join(filepath.Dir(parentTemplateFile), arg0) + + if templateBytes, err = os.ReadFile(targetTemplateFile); err == nil { + // file was found, use its contents as template + templateName = arg0 + includeStack = slices.Insert(includeStack, 0, fmt.Sprintf("file:%s", targetTemplateFile)) + + } else { + //no such file, assume it's a named template + templateBytes = []byte(fmt.Sprintf(`{{- template "%s" . }}`, arg0)) + templateName = fmt.Sprintf("%s.tpl", arg0) + includeStack = slices.Insert(includeStack, 0, fmt.Sprintf("template:%s", templateName)) + } + + templateText := string(templateBytes) - tpl, _ := template.New(templateName + ".tpl"). + tpl, err := template.New(templateName). Funcs(helperFuncs). Funcs(sprig.FuncMap()). Parse(templateText) - tpl, err := tpl.ParseFiles(includeMatches...) if err != nil { panic(err) } + if len(includeMatches) > 0 { + tpl, err = tpl.ParseFiles(includeMatches...) + if err != nil { + panic(err) + } + } + var arg any if len(args) > 1 { //actual argument @@ -239,6 +257,9 @@ func CreateTemplate(templateFile string, includeList []string, outputFile string if err != nil { panic(err) } + + includeStack = slices.Delete(includeStack, 0, 1) + return tplOut.String() } @@ -254,14 +275,26 @@ func CreateTemplate(templateFile string, includeList []string, outputFile string helperFuncs["deref"] = derefFunc helperFuncs["slug_make"] = slugMakeFunc - tmpl, err := template.New(filepath.Base(tmpFile.Name())). + var templateText []byte + if templateText, err = os.ReadFile(templateFile); err != nil { + return nil, errors.New(err) + } + + tmpl, err := template.New(templateFile). Funcs(helperFuncs). Funcs(sprig.FuncMap()). - ParseFiles(includeMatches...) + Parse(string(templateText)) if err != nil { return nil, errors.New(err) } + if len(includeMatches) > 0 { + tmpl, err = tmpl.ParseFiles(includeMatches...) + if err != nil { + return nil, errors.New(err) + } + } + return tmpl, nil } diff --git a/pkg/render/render_test.go b/pkg/render/render_test.go new file mode 100644 index 0000000..a876794 --- /dev/null +++ b/pkg/render/render_test.go @@ -0,0 +1,115 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package render + +import ( + "fmt" + "github.com/apigee/apigee-go-gen/pkg/flags" + "github.com/apigee/apigee-go-gen/pkg/utils" + "github.com/stretchr/testify/require" + "os" + "path" + "path/filepath" + "testing" +) + +func TestRenderGeneric(t *testing.T) { + + tests := []struct { + dir string + templateFile string + valuesFile string + includesFile string + wantErr error + }{ + { + "using-files", + "input.yaml", + "", + "", + nil, + }, + { + "using-helpers", + "input.yaml", + "", + "_helpers.tmpl", + nil, + }, + { + "policies", + "apiproxy.yaml", + "values.yaml", + "", + nil, + }, + } + for _, tt := range tests { + t.Run(tt.dir, func(t *testing.T) { + + testDir := path.Join("testdata", "render", tt.dir) + templateFile := path.Join(testDir, tt.templateFile) + + outputFile := path.Join(testDir, fmt.Sprintf("out-%s", tt.templateFile)) + expectedFile := path.Join(testDir, fmt.Sprintf("exp-%s", tt.templateFile)) + + var err error + err = os.RemoveAll(outputFile) + require.NoError(t, err) + + type ctx struct{} + cFlags := NewCommonFlags() + cFlags.TemplateFile = flags.String(templateFile) + cFlags.OutputFile = flags.String(outputFile) + + if tt.valuesFile != "" { + v := flags.NewValues(cFlags.Values) + valuesFile := path.Join(testDir, tt.valuesFile) + err := v.Set(valuesFile) + require.NoError(t, err) + } + + if tt.includesFile != "" { + includesFile := path.Join(testDir, tt.includesFile) + err := cFlags.IncludeList.Set(includesFile) + require.NoError(t, err) + } + + err = RenderGenericTemplate(cFlags, false) + + if tt.wantErr != nil { + require.EqualError(t, err, tt.wantErr.Error()) + return + } + require.NoError(t, err) + + outputBytes := utils.MustReadFileBytes(outputFile) + expectedBytes := utils.MustReadFileBytes(expectedFile) + + if filepath.Ext(expectedFile) == ".txt" { + require.Equal(t, string(expectedBytes), string(outputBytes)) + } else if filepath.Ext(expectedFile) == ".json" { + require.JSONEq(t, string(expectedBytes), string(outputBytes)) + } else if filepath.Ext(expectedFile) == ".yaml" { + outputBytes = utils.RemoveYAMLComments(outputBytes) + expectedBytes = utils.RemoveYAMLComments(expectedBytes) + require.YAMLEq(t, string(expectedBytes), string(outputBytes)) + } else { + t.Error("unknown output format in testcase") + } + + }) + } +} diff --git a/pkg/render/testdata/.gitignore b/pkg/render/testdata/.gitignore new file mode 100644 index 0000000..edfdbc3 --- /dev/null +++ b/pkg/render/testdata/.gitignore @@ -0,0 +1,15 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +**/out-* \ No newline at end of file diff --git a/pkg/render/testdata/render/policies/apiproxy.yaml b/pkg/render/testdata/render/policies/apiproxy.yaml new file mode 100644 index 0000000..72652c9 --- /dev/null +++ b/pkg/render/testdata/render/policies/apiproxy.yaml @@ -0,0 +1,19 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +APIProxy: + .revision: 1 + .name: Example + DisplayName: Example + Description: Example +Policies: {{ include "policies.yaml" . | nindent 2 }} \ No newline at end of file diff --git a/pkg/render/testdata/render/policies/common/assign-message.yaml b/pkg/render/testdata/render/policies/common/assign-message.yaml new file mode 100644 index 0000000..ea91a7e --- /dev/null +++ b/pkg/render/testdata/render/policies/common/assign-message.yaml @@ -0,0 +1,29 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +AssignMessage: + .continueOnError: false + .enabled: true + .name: AM-SetHeader + DisplayName: AM-SetHeader + Properties: {} + Set: + Headers: + Header: + .name: Example + -Data: {{ $.Values.example_header }} + IgnoreUnresolvedVariables: true + AssignTo: + .createNew: false + .transport: http + .type: request \ No newline at end of file diff --git a/pkg/render/testdata/render/policies/common/spike-arrest.yaml b/pkg/render/testdata/render/policies/common/spike-arrest.yaml new file mode 100644 index 0000000..5039232 --- /dev/null +++ b/pkg/render/testdata/render/policies/common/spike-arrest.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +SpikeArrest: + .continueOnError: false + .enabled: true + .name: Spike-Arrest + DisplayName: Spike Arrest + Properties: {} + Identifier: + .ref: {{ $.Values.spike_arrest.identifier }} + Rate: {{ or ($.Values.spike_arrest.rate) "100pm" }} \ No newline at end of file diff --git a/pkg/render/testdata/render/policies/exp-apiproxy.yaml b/pkg/render/testdata/render/policies/exp-apiproxy.yaml new file mode 100755 index 0000000..c156721 --- /dev/null +++ b/pkg/render/testdata/render/policies/exp-apiproxy.yaml @@ -0,0 +1,44 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +APIProxy: + .revision: 1 + .name: Example + DisplayName: Example + Description: Example +Policies: + - SpikeArrest: + .continueOnError: false + .enabled: true + .name: Spike-Arrest + DisplayName: Spike Arrest + Properties: {} + Identifier: + .ref: client.ip + Rate: 400pm + - AssignMessage: + .continueOnError: false + .enabled: true + .name: AM-SetHeader + DisplayName: AM-SetHeader + Properties: {} + Set: + Headers: + Header: + .name: Example + -Data: example_value + IgnoreUnresolvedVariables: true + AssignTo: + .createNew: false + .transport: http + .type: request \ No newline at end of file diff --git a/pkg/render/testdata/render/policies/policies.yaml b/pkg/render/testdata/render/policies/policies.yaml new file mode 100644 index 0000000..bd62a7b --- /dev/null +++ b/pkg/render/testdata/render/policies/policies.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +- {{ include "./common/spike-arrest.yaml" . | indent 2 | trim }} +- {{ include "./common/assign-message.yaml" . | indent 2 | trim }} \ No newline at end of file diff --git a/pkg/render/testdata/render/policies/values.yaml b/pkg/render/testdata/render/policies/values.yaml new file mode 100644 index 0000000..f1a7718 --- /dev/null +++ b/pkg/render/testdata/render/policies/values.yaml @@ -0,0 +1,17 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +spike_arrest: + rate: 400pm + identifier: client.ip +example_header: example_value \ No newline at end of file diff --git a/pkg/render/testdata/render/using-files/exp-input.yaml b/pkg/render/testdata/render/using-files/exp-input.yaml new file mode 100644 index 0000000..4b6c586 --- /dev/null +++ b/pkg/render/testdata/render/using-files/exp-input.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +The quick brown fox jumped over the lazy dog \ No newline at end of file diff --git a/pkg/render/testdata/render/using-files/input.yaml b/pkg/render/testdata/render/using-files/input.yaml new file mode 100644 index 0000000..a9760fd --- /dev/null +++ b/pkg/render/testdata/render/using-files/input.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +The quick brown {{ include "./level1/input.yaml" }} \ No newline at end of file diff --git a/pkg/render/testdata/render/using-files/level1/input.yaml b/pkg/render/testdata/render/using-files/level1/input.yaml new file mode 100644 index 0000000..8202b59 --- /dev/null +++ b/pkg/render/testdata/render/using-files/level1/input.yaml @@ -0,0 +1 @@ +fox jumped over {{ include "./level2/input.yaml" }} \ No newline at end of file diff --git a/pkg/render/testdata/render/using-files/level1/level2/input.yaml b/pkg/render/testdata/render/using-files/level1/level2/input.yaml new file mode 100644 index 0000000..ae8968f --- /dev/null +++ b/pkg/render/testdata/render/using-files/level1/level2/input.yaml @@ -0,0 +1 @@ +the lazy dog \ No newline at end of file diff --git a/pkg/render/testdata/render/using-helpers/_helpers.tmpl b/pkg/render/testdata/render/using-helpers/_helpers.tmpl new file mode 100644 index 0000000..3104763 --- /dev/null +++ b/pkg/render/testdata/render/using-helpers/_helpers.tmpl @@ -0,0 +1,23 @@ +{{/* + Copyright 2024 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http:#www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/}} + +{{- define "level1" -}} + fox jumped over {{ include "level2" }} +{{- end -}} + +{{- define "level2" -}} + the lazy dog +{{- end -}} \ No newline at end of file diff --git a/pkg/render/testdata/render/using-helpers/exp-input.yaml b/pkg/render/testdata/render/using-helpers/exp-input.yaml new file mode 100644 index 0000000..4b6c586 --- /dev/null +++ b/pkg/render/testdata/render/using-helpers/exp-input.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +The quick brown fox jumped over the lazy dog \ No newline at end of file diff --git a/pkg/render/testdata/render/using-helpers/input.yaml b/pkg/render/testdata/render/using-helpers/input.yaml new file mode 100644 index 0000000..7d5af0c --- /dev/null +++ b/pkg/render/testdata/render/using-helpers/input.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +The quick brown {{ include "level1" . }} \ No newline at end of file diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 2ac732e..2363735 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -20,6 +20,7 @@ import ( "github.com/go-errors/errors" "gopkg.in/yaml.v3" "os" + "regexp" ) func MustReadFileBytes(path string) []byte { @@ -84,3 +85,9 @@ func PushDir(dir string) func() { return popDir } + +func RemoveYAMLComments(data []byte) []byte { + regex := regexp.MustCompile(`(?ms)^\s*#[^\n\r]*$[\r\n]*`) + replaced := regex.ReplaceAll(data, []byte{}) + return replaced +} diff --git a/pkg/utils/xml_test.go b/pkg/utils/xml_test.go index c0a434e..b066201 100644 --- a/pkg/utils/xml_test.go +++ b/pkg/utils/xml_test.go @@ -18,7 +18,6 @@ import ( "bytes" "github.com/stretchr/testify/assert" "path/filepath" - "regexp" "testing" ) @@ -83,9 +82,3 @@ func TestXMLText2YAMLText(t *testing.T) { }) } } - -func RemoveYAMLComments(data []byte) []byte { - regex := regexp.MustCompile(`(?ms)^\s*#[^\n\r]*$[\r\n]*`) - replaced := regex.ReplaceAll(data, []byte{}) - return replaced -}