Skip to content

Commit

Permalink
Merge pull request #19 from micovery/feat_nested_template_rendering
Browse files Browse the repository at this point in the history
feat: add support for nested template rendering
  • Loading branch information
micovery authored Oct 29, 2024
2 parents 66c3c3f + a6b6133 commit f69787c
Show file tree
Hide file tree
Showing 31 changed files with 537 additions and 55 deletions.
3 changes: 3 additions & 0 deletions cmd/apigee-go-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions cmd/apigee-go-gen/render/apiproxy/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -42,15 +43,15 @@ 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")
}

createModelFunc := func(input string) (v1.Model, error) {
return v1.NewAPIProxyModel(input)
}

return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value)
return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value, bool(debug))
},
}

Expand All @@ -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" `)
Expand Down
8 changes: 5 additions & 3 deletions cmd/apigee-go-gen/render/sharedflow/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -42,15 +43,15 @@ 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")
}

createModelFunc := func(input string) (v1.Model, error) {
return v1.NewSharedFlowBundleModel(input)
}

return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value)
return render.GenerateBundle(createModelFunc, cFlags, bool(validate), dryRun.Value, bool(debug))
},
}

Expand All @@ -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" `)
Expand Down
3 changes: 2 additions & 1 deletion docs/render/commands/render-apiproxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 2 additions & 1 deletion docs/render/commands/render-sharedflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
12 changes: 11 additions & 1 deletion docs/render/using-built-in-helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,24 @@ 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.

```gotemplate
{{ 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
Expand Down
11 changes: 9 additions & 2 deletions docs/render/using-openapi-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions examples/templates/oas3/apiproxy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
14 changes: 3 additions & 11 deletions examples/templates/oas3/policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }}
23 changes: 23 additions & 0 deletions examples/templates/oas3/policies/message-logging.yaml
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions examples/templates/oas3/policies/spike-arrest.yaml
Original file line number Diff line number Diff line change
@@ -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" }}
15 changes: 14 additions & 1 deletion pkg/common/resources/helper_functions.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
12 changes: 10 additions & 2 deletions pkg/render/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
Loading

0 comments on commit f69787c

Please sign in to comment.