mirror of
https://github.com/terraform-docs/terraform-docs.git
synced 2026-03-27 04:48:33 +07:00
Make terraform.Module available in content
Add one extra special variable the `content`:
- `{{ .Module }}`
As opposed to the other variables, which are generated sections based on
a selected formatter, the `{{ .Module }}` variable is just a `struct`
representing a Terraform module.
It can be used to build highly complex and highly customized content:
```yaml
content: |-
## Resources
{{ range .Module.Resources }}
- {{ .GetMode }}.{{ .Spec }} ({{ .Position.Filename }}#{{ .Position.Line }})
{{- end }}
```
Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com>
This commit is contained in:
@@ -312,11 +312,11 @@ func buildTerraformDocs(path string, tmpl string) (string, error) {
|
||||
|
||||
// // Note: if you don't intend to provide additional template for the generated
|
||||
// // content, or the target format doesn't provide templating (e.g. json, yaml,
|
||||
// // xml, or toml) you can use `Content()` function instead of `ExecuteTemplate()`.
|
||||
// // xml, or toml) you can use `Content()` function instead of `Render()`.
|
||||
// // `Content()` returns all the sections combined with predefined order.
|
||||
// return formatter.Content(), nil
|
||||
|
||||
return formatter.ExecuteTemplate(tmpl)
|
||||
return formatter.Render(tmpl)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -29,19 +29,27 @@ will be ignored for other formatters.
|
||||
- `{{ .Requirements }}`
|
||||
- `{{ .Resources }}`
|
||||
|
||||
and following functions:
|
||||
|
||||
- `{{ include "relative/path/to/file" }}`
|
||||
|
||||
These variables are the generated output of individual sections in the selected
|
||||
formatter. For example `{{ .Inputs }}` is Markdown Table representation of _inputs_
|
||||
when formatter is set to `markdown table`.
|
||||
|
||||
{{< alert type="info" >}}
|
||||
Sections visibility (i.e. `sections.show` and `sections.hide`) takes
|
||||
precedence over the `content`.
|
||||
Sections visibility (i.e. `sections.show` and `sections.hide`) takes precedence
|
||||
over the `content`.
|
||||
{{< /alert >}}
|
||||
|
||||
`content` also has the following function:
|
||||
|
||||
- `{{ include "relative/path/to/file" }}`
|
||||
|
||||
Additionally there's also one extra special variable avaialble to the `content`:
|
||||
|
||||
- `{{ .Module }}`
|
||||
|
||||
As opposed to the other variables mentioned above, which are generated sections
|
||||
based on a selected formatter, the `{{ .Module }}` variable is just a `struct`
|
||||
representing a [Terraform module].
|
||||
|
||||
## Options
|
||||
|
||||
Available options with their default values.
|
||||
@@ -93,7 +101,7 @@ content: |-
|
||||
````
|
||||
|
||||
In the following example, although `{{ .Providers }}` is defined it won't be
|
||||
rendered because `providers` is not set to be shown in `sections.show`.
|
||||
rendered because `providers` is not set to be shown in `sections.show`:
|
||||
|
||||
```yaml
|
||||
sections:
|
||||
@@ -113,3 +121,16 @@ content: |-
|
||||
|
||||
{{ .Outputs }}
|
||||
```
|
||||
|
||||
Building highly complex and highly customized content using `{{ .Module }}` struct:
|
||||
|
||||
```yaml
|
||||
content: |-
|
||||
## Resources
|
||||
|
||||
{{ range .Module.Resources }}
|
||||
- {{ .GetMode }}.{{ .Spec }} ({{ .Position.Filename }}#{{ .Position.Line }})
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
[Terraform module]: https://pkg.go.dev/github.com/terraform-docs/terraform-docs/terraform#Module
|
||||
@@ -32,6 +32,11 @@ sections:
|
||||
#
|
||||
# and even in between sections
|
||||
#
|
||||
# ## Resources
|
||||
# {{ range .Module.Resources }}
|
||||
# - {{ .GetMode }}.{{ .Spec }} ({{ .Position.Filename }}#{{ .Position.Line }})
|
||||
# {{- end }}
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# ```hcl
|
||||
|
||||
@@ -24,7 +24,7 @@ var asciidocsDocumentFS embed.FS
|
||||
|
||||
// asciidocDocument represents AsciiDoc Document format.
|
||||
type asciidocDocument struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
template *template.Template
|
||||
@@ -61,7 +61,7 @@ func NewAsciidocDocument(config *print.Config) Type {
|
||||
})
|
||||
|
||||
return &asciidocDocument{
|
||||
Generator: print.NewGenerator("json", config.ModuleRoot),
|
||||
generator: newGenerator(config, true),
|
||||
config: config,
|
||||
template: tt,
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func NewAsciidocDocument(config *print.Config) Type {
|
||||
|
||||
// Generate a Terraform module as AsciiDoc document.
|
||||
func (d *asciidocDocument) Generate(module *terraform.Module) error {
|
||||
err := d.Generator.ForEach(func(name string) (string, error) {
|
||||
err := d.generator.forEach(func(name string) (string, error) {
|
||||
rendered, err := d.template.Render(name, module)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -77,6 +77,8 @@ func (d *asciidocDocument) Generate(module *terraform.Module) error {
|
||||
return sanitize(rendered), nil
|
||||
})
|
||||
|
||||
d.generator.funcs(withModule(module))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -153,10 +153,7 @@ func TestAsciidocDocument(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ var asciidocTableFS embed.FS
|
||||
|
||||
// asciidocTable represents AsciiDoc Table format.
|
||||
type asciidocTable struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
template *template.Template
|
||||
@@ -52,7 +52,7 @@ func NewAsciidocTable(config *print.Config) Type {
|
||||
})
|
||||
|
||||
return &asciidocTable{
|
||||
Generator: print.NewGenerator("json", config.ModuleRoot),
|
||||
generator: newGenerator(config, true),
|
||||
config: config,
|
||||
template: tt,
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func NewAsciidocTable(config *print.Config) Type {
|
||||
|
||||
// Generate a Terraform module as AsciiDoc tables.
|
||||
func (t *asciidocTable) Generate(module *terraform.Module) error {
|
||||
err := t.Generator.ForEach(func(name string) (string, error) {
|
||||
err := t.generator.forEach(func(name string) (string, error) {
|
||||
rendered, err := t.template.Render(name, module)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -68,6 +68,8 @@ func (t *asciidocTable) Generate(module *terraform.Module) error {
|
||||
return sanitize(rendered), nil
|
||||
})
|
||||
|
||||
t.generator.funcs(withModule(module))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -153,10 +153,7 @@ func TestAsciidocTable(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,15 +28,15 @@ the root directory of this source tree.
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// output, err := formatter.ExecuteTemplate("")
|
||||
// output, err := formatter.Render"")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// Note: if you don't intend to provide additional template for the generated
|
||||
// content, or the target format doesn't provide templating (e.g. json, yaml,
|
||||
// xml, or toml) you can use `Content()` function instead of `ExecuteTemplate()`.
|
||||
// `Content()` returns all the sections combined with predefined order.
|
||||
// xml, or toml) you can use `Content()` function instead of `Render)`. Note
|
||||
// that `Content()` returns all the sections combined with predefined order.
|
||||
//
|
||||
// output := formatter.Content()
|
||||
//
|
||||
|
||||
267
format/generator.go
Normal file
267
format/generator.go
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
Copyright 2021 The terraform-docs Authors.
|
||||
|
||||
Licensed under the MIT license (the "License"); you may not
|
||||
use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at the LICENSE file in
|
||||
the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package format
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
gotemplate "text/template"
|
||||
|
||||
"github.com/terraform-docs/terraform-docs/print"
|
||||
"github.com/terraform-docs/terraform-docs/template"
|
||||
"github.com/terraform-docs/terraform-docs/terraform"
|
||||
)
|
||||
|
||||
// generateFunc configures generator.
|
||||
type generateFunc func(*generator)
|
||||
|
||||
// withContent specifies how the generator should add content.
|
||||
func withContent(content string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.content = content
|
||||
}
|
||||
}
|
||||
|
||||
// withHeader specifies how the generator should add Header.
|
||||
func withHeader(header string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.header = header
|
||||
}
|
||||
}
|
||||
|
||||
// withFooter specifies how the generator should add Footer.
|
||||
func withFooter(footer string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.footer = footer
|
||||
}
|
||||
}
|
||||
|
||||
// withInputs specifies how the generator should add Inputs.
|
||||
func withInputs(inputs string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.inputs = inputs
|
||||
}
|
||||
}
|
||||
|
||||
// withModules specifies how the generator should add Modules.
|
||||
func withModules(modules string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.modules = modules
|
||||
}
|
||||
}
|
||||
|
||||
// withOutputs specifies how the generator should add Outputs.
|
||||
func withOutputs(outputs string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.outputs = outputs
|
||||
}
|
||||
}
|
||||
|
||||
// withProviders specifies how the generator should add Providers.
|
||||
func withProviders(providers string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.providers = providers
|
||||
}
|
||||
}
|
||||
|
||||
// withRequirements specifies how the generator should add Requirements.
|
||||
func withRequirements(requirements string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.requirements = requirements
|
||||
}
|
||||
}
|
||||
|
||||
// withResources specifies how the generator should add Resources.
|
||||
func withResources(resources string) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.resources = resources
|
||||
}
|
||||
}
|
||||
|
||||
// withModule specifies how the generator should add Resources.
|
||||
func withModule(module *terraform.Module) generateFunc {
|
||||
return func(g *generator) {
|
||||
g.module = module
|
||||
}
|
||||
}
|
||||
|
||||
// generator represents all the sections that can be generated for a Terraform
|
||||
// modules (e.g. header, footer, inputs, etc). All these sections are being
|
||||
// generated individually and if no content template was passed they will be
|
||||
// combined together with a predefined order.
|
||||
//
|
||||
// On the other hand these sections can individually be used in content template
|
||||
// to form a custom format (and order).
|
||||
//
|
||||
// Note that the notion of custom content template will be ignored for incompatible
|
||||
// formatters and custom plugins. Compatible formatters are:
|
||||
//
|
||||
// - asciidoc document
|
||||
// - asciidoc table
|
||||
// - markdown document
|
||||
// - markdown table
|
||||
type generator struct {
|
||||
// all the content combined
|
||||
content string
|
||||
|
||||
// individual sections
|
||||
header string
|
||||
footer string
|
||||
inputs string
|
||||
modules string
|
||||
outputs string
|
||||
providers string
|
||||
requirements string
|
||||
resources string
|
||||
|
||||
config *print.Config
|
||||
module *terraform.Module
|
||||
|
||||
path string // module's path
|
||||
fns []generateFunc // generator helper functions
|
||||
|
||||
canRender bool // indicates if the generator can render with custom template
|
||||
}
|
||||
|
||||
// newGenerator returns a generator for specific formatter name and with
|
||||
// provided sets of GeneratorFunc functions to build and add individual
|
||||
// sections.
|
||||
func newGenerator(config *print.Config, canRender bool, fns ...generateFunc) *generator {
|
||||
g := &generator{
|
||||
config: config,
|
||||
|
||||
path: config.ModuleRoot,
|
||||
fns: []generateFunc{},
|
||||
|
||||
canRender: canRender,
|
||||
}
|
||||
|
||||
g.funcs(fns...)
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
// Content returns generted all the sections combined based on the underlying format.
|
||||
func (g *generator) Content() string { return g.content }
|
||||
|
||||
// Header returns generted header section based on the underlying format.
|
||||
func (g *generator) Header() string { return g.header }
|
||||
|
||||
// Footer returns generted footer section based on the underlying format.
|
||||
func (g *generator) Footer() string { return g.footer }
|
||||
|
||||
// Inputs returns generted inputs section based on the underlying format.
|
||||
func (g *generator) Inputs() string { return g.inputs }
|
||||
|
||||
// Modules returns generted modules section based on the underlying format.
|
||||
func (g *generator) Modules() string { return g.modules }
|
||||
|
||||
// Outputs returns generted outputs section based on the underlying format.
|
||||
func (g *generator) Outputs() string { return g.outputs }
|
||||
|
||||
// Providers returns generted providers section based on the underlying format.
|
||||
func (g *generator) Providers() string { return g.providers }
|
||||
|
||||
// Requirements returns generted resources section based on the underlying format.
|
||||
func (g *generator) Requirements() string { return g.requirements }
|
||||
|
||||
// Resources returns generted requirements section based on the underlying format.
|
||||
func (g *generator) Resources() string { return g.resources }
|
||||
|
||||
// Module returns generted requirements section based on the underlying format.
|
||||
func (g *generator) Module() *terraform.Module { return g.module }
|
||||
|
||||
// funcs adds GenerateFunc to the list of available functions, for further use
|
||||
// if need be, and then runs them.
|
||||
func (g *generator) funcs(fns ...generateFunc) {
|
||||
for _, fn := range fns {
|
||||
g.fns = append(g.fns, fn)
|
||||
fn(g)
|
||||
}
|
||||
}
|
||||
|
||||
// Path set path of module's root directory.
|
||||
func (g *generator) Path(root string) {
|
||||
g.path = root
|
||||
}
|
||||
|
||||
func (g *generator) Render(tpl string) (string, error) {
|
||||
if !g.canRender {
|
||||
return g.content, nil
|
||||
}
|
||||
|
||||
if tpl == "" {
|
||||
return g.content, nil
|
||||
}
|
||||
|
||||
tt := template.New(g.config, &template.Item{
|
||||
Name: "content",
|
||||
Text: tpl,
|
||||
})
|
||||
tt.CustomFunc(gotemplate.FuncMap{
|
||||
"include": func(s string) string {
|
||||
content, err := os.ReadFile(filepath.Join(g.path, s))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.TrimSuffix(string(content), "\n")
|
||||
},
|
||||
})
|
||||
|
||||
data := struct {
|
||||
*generator
|
||||
Config *print.Config
|
||||
Module *terraform.Module
|
||||
}{
|
||||
generator: g,
|
||||
Config: g.config,
|
||||
Module: g.module,
|
||||
}
|
||||
|
||||
rendered, err := tt.RenderContent("content", data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSuffix(rendered, "\n"), nil
|
||||
}
|
||||
|
||||
// generatorCallback renders a Terraform module and creates a GenerateFunc.
|
||||
type generatorCallback func(string) generateFunc
|
||||
|
||||
// forEach section executes generatorCallback to render the content for that
|
||||
// section and create corresponding GeneratorFunc. If there is any error in
|
||||
// executing the template for the section forEach function immediately returns
|
||||
// it and exits.
|
||||
func (g *generator) forEach(render func(string) (string, error)) error {
|
||||
mappings := map[string]generatorCallback{
|
||||
"all": withContent,
|
||||
"header": withHeader,
|
||||
"footer": withFooter,
|
||||
"inputs": withInputs,
|
||||
"modules": withModules,
|
||||
"outputs": withOutputs,
|
||||
"providers": withProviders,
|
||||
"requirements": withRequirements,
|
||||
"resources": withResources,
|
||||
}
|
||||
for name, callback := range mappings {
|
||||
result, err := render(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fn := callback(result)
|
||||
g.fns = append(g.fns, fn)
|
||||
fn(g)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -8,128 +8,80 @@ You may obtain a copy of the License at the LICENSE file in
|
||||
the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package print
|
||||
package format
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/terraform-docs/terraform-docs/print"
|
||||
"github.com/terraform-docs/terraform-docs/terraform"
|
||||
)
|
||||
|
||||
func TestIsCompatible(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
expected bool
|
||||
}{
|
||||
"asciidoc document": {
|
||||
expected: true,
|
||||
},
|
||||
"asciidoc table": {
|
||||
expected: true,
|
||||
},
|
||||
"markdown document": {
|
||||
expected: true,
|
||||
},
|
||||
"markdown table": {
|
||||
expected: true,
|
||||
},
|
||||
"markdown": {
|
||||
expected: false,
|
||||
},
|
||||
"markdown-table": {
|
||||
expected: false,
|
||||
},
|
||||
"md": {
|
||||
expected: false,
|
||||
},
|
||||
"md tbl": {
|
||||
expected: false,
|
||||
},
|
||||
"md-tbl": {
|
||||
expected: false,
|
||||
},
|
||||
"json": {
|
||||
expected: false,
|
||||
},
|
||||
"yaml": {
|
||||
expected: false,
|
||||
},
|
||||
"xml": {
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
generator := NewGenerator(name, "")
|
||||
actual := generator.isCompatible()
|
||||
|
||||
assert.Equal(tt.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteTemplate(t *testing.T) {
|
||||
header := "this is the header"
|
||||
footer := "this is the footer"
|
||||
tests := map[string]struct {
|
||||
name string
|
||||
complex bool
|
||||
content string
|
||||
template string
|
||||
expected string
|
||||
wantErr bool
|
||||
}{
|
||||
"Compatible without template": {
|
||||
name: "markdown table",
|
||||
complex: true,
|
||||
content: "this is the header\nthis is the footer",
|
||||
template: "",
|
||||
expected: "this is the header\nthis is the footer",
|
||||
wantErr: false,
|
||||
},
|
||||
"Compatible with template not empty section": {
|
||||
name: "markdown table",
|
||||
complex: true,
|
||||
content: "this is the header\nthis is the footer",
|
||||
template: "{{ .Header }}",
|
||||
expected: "this is the header",
|
||||
wantErr: false,
|
||||
},
|
||||
"Compatible with template empty section": {
|
||||
name: "markdown table",
|
||||
complex: true,
|
||||
content: "this is the header\nthis is the footer",
|
||||
template: "{{ .Inputs }}",
|
||||
expected: "",
|
||||
wantErr: false,
|
||||
},
|
||||
"Compatible with template and unknown section": {
|
||||
name: "markdown table",
|
||||
complex: true,
|
||||
content: "this is the header\nthis is the footer",
|
||||
template: "{{ .Unknown }}",
|
||||
expected: "",
|
||||
wantErr: true,
|
||||
},
|
||||
"Compatible with template include file": {
|
||||
name: "markdown table",
|
||||
complex: true,
|
||||
content: "this is the header\nthis is the footer",
|
||||
template: "{{ include \"testdata/sample-file.txt\" }}",
|
||||
expected: "Sample file to be included.\n",
|
||||
template: "{{ include \"testdata/generator/sample-file.txt\" }}",
|
||||
expected: "Sample file to be included.",
|
||||
wantErr: false,
|
||||
},
|
||||
"Compatible with template include unknown file": {
|
||||
name: "markdown table",
|
||||
complex: true,
|
||||
content: "this is the header\nthis is the footer",
|
||||
template: "{{ include \"file-not-found\" }}",
|
||||
expected: "",
|
||||
wantErr: true,
|
||||
},
|
||||
"Incompatible without template": {
|
||||
name: "yaml",
|
||||
complex: false,
|
||||
content: "header: \"this is the header\"\nfooter: \"this is the footer\"",
|
||||
template: "",
|
||||
expected: "header: \"this is the header\"\nfooter: \"this is the footer\"",
|
||||
wantErr: false,
|
||||
},
|
||||
"Incompatible with template": {
|
||||
name: "yaml",
|
||||
complex: false,
|
||||
content: "header: \"this is the header\"\nfooter: \"this is the footer\"",
|
||||
template: "{{ .Header }}",
|
||||
expected: "header: \"this is the header\"\nfooter: \"this is the footer\"",
|
||||
@@ -140,12 +92,14 @@ func TestExecuteTemplate(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
generator := NewGenerator(tt.name, "")
|
||||
config := print.DefaultConfig()
|
||||
|
||||
generator := newGenerator(config, tt.complex)
|
||||
generator.content = tt.content
|
||||
generator.header = header
|
||||
generator.footer = footer
|
||||
|
||||
actual, err := generator.ExecuteTemplate(tt.template)
|
||||
actual, err := generator.Render(tt.template)
|
||||
|
||||
if tt.wantErr {
|
||||
assert.NotNil(err)
|
||||
@@ -160,60 +114,92 @@ func TestExecuteTemplate(t *testing.T) {
|
||||
func TestGeneratorFunc(t *testing.T) {
|
||||
text := "foo"
|
||||
tests := map[string]struct {
|
||||
fn func(string) GenerateFunc
|
||||
actual func(*Generator) string
|
||||
fn func(string) generateFunc
|
||||
actual func(*generator) string
|
||||
}{
|
||||
"WithContent": {
|
||||
fn: WithContent,
|
||||
actual: func(r *Generator) string { return r.content },
|
||||
"withContent": {
|
||||
fn: withContent,
|
||||
actual: func(r *generator) string { return r.content },
|
||||
},
|
||||
"WithHeader": {
|
||||
fn: WithHeader,
|
||||
actual: func(r *Generator) string { return r.header },
|
||||
"withHeader": {
|
||||
fn: withHeader,
|
||||
actual: func(r *generator) string { return r.header },
|
||||
},
|
||||
"WithFooter": {
|
||||
fn: WithFooter,
|
||||
actual: func(r *Generator) string { return r.footer },
|
||||
"withFooter": {
|
||||
fn: withFooter,
|
||||
actual: func(r *generator) string { return r.footer },
|
||||
},
|
||||
"WithInputs": {
|
||||
fn: WithInputs,
|
||||
actual: func(r *Generator) string { return r.inputs },
|
||||
"withInputs": {
|
||||
fn: withInputs,
|
||||
actual: func(r *generator) string { return r.inputs },
|
||||
},
|
||||
"WithModules": {
|
||||
fn: WithModules,
|
||||
actual: func(r *Generator) string { return r.modules },
|
||||
"withModules": {
|
||||
fn: withModules,
|
||||
actual: func(r *generator) string { return r.modules },
|
||||
},
|
||||
"WithOutputs": {
|
||||
fn: WithOutputs,
|
||||
actual: func(r *Generator) string { return r.outputs },
|
||||
"withOutputs": {
|
||||
fn: withOutputs,
|
||||
actual: func(r *generator) string { return r.outputs },
|
||||
},
|
||||
"WithProviders": {
|
||||
fn: WithProviders,
|
||||
actual: func(r *Generator) string { return r.providers },
|
||||
"withProviders": {
|
||||
fn: withProviders,
|
||||
actual: func(r *generator) string { return r.providers },
|
||||
},
|
||||
"WithRequirements": {
|
||||
fn: WithRequirements,
|
||||
actual: func(r *Generator) string { return r.requirements },
|
||||
"withRequirements": {
|
||||
fn: withRequirements,
|
||||
actual: func(r *generator) string { return r.requirements },
|
||||
},
|
||||
"WithResources": {
|
||||
fn: WithResources,
|
||||
actual: func(r *Generator) string { return r.resources },
|
||||
"withResources": {
|
||||
fn: withResources,
|
||||
actual: func(r *generator) string { return r.resources },
|
||||
},
|
||||
}
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
generator := NewGenerator(name, "", tt.fn(text))
|
||||
config := print.DefaultConfig()
|
||||
config.Sections.Footer = true
|
||||
|
||||
generator := newGenerator(config, false, tt.fn(text))
|
||||
|
||||
assert.Equal(text, tt.actual(generator))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratorFuncModule(t *testing.T) {
|
||||
t.Run("withModule", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
config := print.DefaultConfig()
|
||||
config.ModuleRoot = filepath.Join("..", "terraform", "testdata", "full-example")
|
||||
|
||||
module, err := terraform.LoadWithOptions(config)
|
||||
|
||||
assert.Nil(err)
|
||||
|
||||
generator := newGenerator(config, true, withModule(module))
|
||||
|
||||
path := filepath.Join("..", "terraform", "testdata", "expected", "full-example-mainTf-Header.golden")
|
||||
data, err := ioutil.ReadFile(path)
|
||||
|
||||
assert.Nil(err)
|
||||
|
||||
expected := string(data)
|
||||
|
||||
assert.Equal(expected, generator.module.Header)
|
||||
assert.Equal("", generator.module.Footer)
|
||||
assert.Equal(7, len(generator.module.Inputs))
|
||||
assert.Equal(3, len(generator.module.Outputs))
|
||||
})
|
||||
}
|
||||
|
||||
func TestForEach(t *testing.T) {
|
||||
generator := NewGenerator("foo", "")
|
||||
generator.ForEach(func(name string) (string, error) {
|
||||
config := print.DefaultConfig()
|
||||
|
||||
generator := newGenerator(config, false)
|
||||
generator.forEach(func(name string) (string, error) {
|
||||
return name, nil
|
||||
})
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
// json represents JSON format.
|
||||
type json struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
}
|
||||
@@ -29,7 +29,7 @@ type json struct {
|
||||
// NewJSON returns new instance of JSON.
|
||||
func NewJSON(config *print.Config) Type {
|
||||
return &json{
|
||||
Generator: print.NewGenerator("json", config.ModuleRoot),
|
||||
generator: newGenerator(config, false),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (j *json) Generate(module *terraform.Module) error {
|
||||
return err
|
||||
}
|
||||
|
||||
j.Generator.Funcs(print.WithContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
j.generator.funcs(withContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -105,10 +105,7 @@ func TestJson(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ var markdownDocumentFS embed.FS
|
||||
|
||||
// markdownDocument represents Markdown Document format.
|
||||
type markdownDocument struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
template *template.Template
|
||||
@@ -59,7 +59,7 @@ func NewMarkdownDocument(config *print.Config) Type {
|
||||
})
|
||||
|
||||
return &markdownDocument{
|
||||
Generator: print.NewGenerator("json", config.ModuleRoot),
|
||||
generator: newGenerator(config, true),
|
||||
config: config,
|
||||
template: tt,
|
||||
}
|
||||
@@ -67,7 +67,7 @@ func NewMarkdownDocument(config *print.Config) Type {
|
||||
|
||||
// Generate a Terraform module as Markdown document.
|
||||
func (d *markdownDocument) Generate(module *terraform.Module) error {
|
||||
err := d.Generator.ForEach(func(name string) (string, error) {
|
||||
err := d.generator.forEach(func(name string) (string, error) {
|
||||
rendered, err := d.template.Render(name, module)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -75,6 +75,8 @@ func (d *markdownDocument) Generate(module *terraform.Module) error {
|
||||
return sanitize(rendered), nil
|
||||
})
|
||||
|
||||
d.generator.funcs(withModule(module))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -190,10 +190,7 @@ func TestMarkdownDocument(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ var markdownTableFS embed.FS
|
||||
|
||||
// markdownTable represents Markdown Table format.
|
||||
type markdownTable struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
template *template.Template
|
||||
@@ -50,7 +50,7 @@ func NewMarkdownTable(config *print.Config) Type {
|
||||
})
|
||||
|
||||
return &markdownTable{
|
||||
Generator: print.NewGenerator("markdown table", config.ModuleRoot),
|
||||
generator: newGenerator(config, true),
|
||||
config: config,
|
||||
template: tt,
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func NewMarkdownTable(config *print.Config) Type {
|
||||
|
||||
// Generate a Terraform module as Markdown tables.
|
||||
func (t *markdownTable) Generate(module *terraform.Module) error {
|
||||
err := t.Generator.ForEach(func(name string) (string, error) {
|
||||
err := t.generator.forEach(func(name string) (string, error) {
|
||||
rendered, err := t.template.Render(name, module)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -66,6 +66,8 @@ func (t *markdownTable) Generate(module *terraform.Module) error {
|
||||
return sanitize(rendered), nil
|
||||
})
|
||||
|
||||
t.generator.funcs(withModule(module))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -190,10 +190,7 @@ func TestMarkdownTable(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ var prettyTpl []byte
|
||||
|
||||
// pretty represents colorized pretty format.
|
||||
type pretty struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
template *template.Template
|
||||
@@ -50,7 +50,7 @@ func NewPretty(config *print.Config) Type {
|
||||
})
|
||||
|
||||
return &pretty{
|
||||
Generator: print.NewGenerator("pretty", config.ModuleRoot),
|
||||
generator: newGenerator(config, true),
|
||||
config: config,
|
||||
template: tt,
|
||||
}
|
||||
@@ -63,7 +63,8 @@ func (p *pretty) Generate(module *terraform.Module) error {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Generator.Funcs(print.WithContent(regexp.MustCompile(`(\r?\n)*$`).ReplaceAllString(rendered, "")))
|
||||
p.generator.funcs(withContent(regexp.MustCompile(`(\r?\n)*$`).ReplaceAllString(rendered, "")))
|
||||
p.generator.funcs(withModule(module))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -105,10 +105,7 @@ func TestPretty(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ var tfvarsHCLTpl []byte
|
||||
|
||||
// tfvarsHCL represents Terraform tfvars HCL format.
|
||||
type tfvarsHCL struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
template *template.Template
|
||||
@@ -60,7 +60,7 @@ func NewTfvarsHCL(config *print.Config) Type {
|
||||
})
|
||||
|
||||
return &tfvarsHCL{
|
||||
Generator: print.NewGenerator("tfvars hcl", config.ModuleRoot),
|
||||
generator: newGenerator(config, false),
|
||||
config: config,
|
||||
template: tt,
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func (h *tfvarsHCL) Generate(module *terraform.Module) error {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Generator.Funcs(print.WithContent(strings.TrimSuffix(sanitize(rendered), "\n")))
|
||||
h.generator.funcs(withContent(strings.TrimSuffix(sanitize(rendered), "\n")))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -97,10 +97,7 @@ func TestTfvarsHcl(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
// tfvarsJSON represents Terraform tfvars JSON format.
|
||||
type tfvarsJSON struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
}
|
||||
@@ -31,7 +31,7 @@ type tfvarsJSON struct {
|
||||
// NewTfvarsJSON returns new instance of TfvarsJSON.
|
||||
func NewTfvarsJSON(config *print.Config) Type {
|
||||
return &tfvarsJSON{
|
||||
Generator: print.NewGenerator("tfvars json", config.ModuleRoot),
|
||||
generator: newGenerator(config, false),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
@@ -53,10 +53,9 @@ func (j *tfvarsJSON) Generate(module *terraform.Module) error {
|
||||
return err
|
||||
}
|
||||
|
||||
j.Generator.Funcs(print.WithContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
j.generator.funcs(withContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -88,10 +88,7 @@ func TestTfvarsJson(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
// toml represents TOML format.
|
||||
type toml struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
}
|
||||
@@ -30,7 +30,7 @@ type toml struct {
|
||||
// NewTOML returns new instance of TOML.
|
||||
func NewTOML(config *print.Config) Type {
|
||||
return &toml{
|
||||
Generator: print.NewGenerator("toml", config.ModuleRoot),
|
||||
generator: newGenerator(config, false),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func (t *toml) Generate(module *terraform.Module) error {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Generator.Funcs(print.WithContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
t.generator.funcs(withContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
|
||||
return nil
|
||||
|
||||
|
||||
@@ -98,10 +98,7 @@ func TestToml(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ type Type interface {
|
||||
Requirements() string // requirements section based on the underlying format
|
||||
Resources() string // resources section based on the underlying format
|
||||
|
||||
ExecuteTemplate(contentTmpl string) (string, error)
|
||||
Render(tmpl string) (string, error)
|
||||
}
|
||||
|
||||
// initializerFn returns a concrete implementation of an Engine.
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
// xml represents XML format.
|
||||
type xml struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
}
|
||||
@@ -28,7 +28,7 @@ type xml struct {
|
||||
// NewXML returns new instance of XML.
|
||||
func NewXML(config *print.Config) Type {
|
||||
return &xml{
|
||||
Generator: print.NewGenerator("xml", config.ModuleRoot),
|
||||
generator: newGenerator(config, false),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ func (x *xml) Generate(module *terraform.Module) error {
|
||||
return err
|
||||
}
|
||||
|
||||
x.Generator.Funcs(print.WithContent(strings.TrimSuffix(string(out), "\n")))
|
||||
x.generator.funcs(withContent(strings.TrimSuffix(string(out), "\n")))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -98,10 +98,7 @@ func TestXml(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
// yaml represents YAML format.
|
||||
type yaml struct {
|
||||
*print.Generator
|
||||
*generator
|
||||
|
||||
config *print.Config
|
||||
}
|
||||
@@ -30,7 +30,7 @@ type yaml struct {
|
||||
// NewYAML returns new instance of YAML.
|
||||
func NewYAML(config *print.Config) Type {
|
||||
return &yaml{
|
||||
Generator: print.NewGenerator("yaml", config.ModuleRoot),
|
||||
generator: newGenerator(config, false),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (y *yaml) Generate(module *terraform.Module) error {
|
||||
return err
|
||||
}
|
||||
|
||||
y.Generator.Funcs(print.WithContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
y.generator.funcs(withContent(strings.TrimSuffix(buffer.String(), "\n")))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -98,10 +98,7 @@ func TestYaml(t *testing.T) {
|
||||
err = formatter.Generate(module)
|
||||
assert.Nil(err)
|
||||
|
||||
actual, err := formatter.ExecuteTemplate("")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(expected, actual)
|
||||
assert.Equal(expected, formatter.Content())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ func generateContent(config *print.Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
content, err := formatter.ExecuteTemplate(config.Content)
|
||||
content, err := formatter.Render(config.Content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -34,9 +34,8 @@ the root directory of this source tree.
|
||||
// Generator holds a reference to all the sections (e.g. header, footer, inputs, etc)
|
||||
// and also it renders all of them, in a predefined order, in `Content()`.
|
||||
//
|
||||
// It also provides `ExecuteTemplate(string)` function to process and render the
|
||||
// template to generate the final output content. Following variables and functions are
|
||||
// available:
|
||||
// It also provides `Render(string)` function to process and render the template to generate
|
||||
// the final output content. Following variables and functions are available:
|
||||
//
|
||||
// • `{{ .Header }}`
|
||||
// • `{{ .Footer }}`
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 The terraform-docs Authors.
|
||||
|
||||
Licensed under the MIT license (the "License"); you may not
|
||||
use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at the LICENSE file in
|
||||
the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package print
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// GenerateFunc configures Generator.
|
||||
type GenerateFunc func(*Generator)
|
||||
|
||||
// WithContent specifies how the Generator should add content.
|
||||
func WithContent(content string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.content = content
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeader specifies how the Generator should add Header.
|
||||
func WithHeader(header string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.header = header
|
||||
}
|
||||
}
|
||||
|
||||
// WithFooter specifies how the Generator should add Footer.
|
||||
func WithFooter(footer string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.footer = footer
|
||||
}
|
||||
}
|
||||
|
||||
// WithInputs specifies how the Generator should add Inputs.
|
||||
func WithInputs(inputs string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.inputs = inputs
|
||||
}
|
||||
}
|
||||
|
||||
// WithModules specifies how the Generator should add Modules.
|
||||
func WithModules(modules string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.modules = modules
|
||||
}
|
||||
}
|
||||
|
||||
// WithOutputs specifies how the Generator should add Outputs.
|
||||
func WithOutputs(outputs string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.outputs = outputs
|
||||
}
|
||||
}
|
||||
|
||||
// WithProviders specifies how the Generator should add Providers.
|
||||
func WithProviders(providers string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.providers = providers
|
||||
}
|
||||
}
|
||||
|
||||
// WithRequirements specifies how the Generator should add Requirements.
|
||||
func WithRequirements(requirements string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.requirements = requirements
|
||||
}
|
||||
}
|
||||
|
||||
// WithResources specifies how the Generator should add Resources.
|
||||
func WithResources(resources string) GenerateFunc {
|
||||
return func(g *Generator) {
|
||||
g.resources = resources
|
||||
}
|
||||
}
|
||||
|
||||
// Generator represents all the sections that can be generated for a Terraform
|
||||
// modules (e.g. header, footer, inputs, etc). All these sections are being
|
||||
// generated individually and if no content template was passed they will be
|
||||
// combined together with a predefined order.
|
||||
//
|
||||
// On the other hand these sections can individually be used in content template
|
||||
// to form a custom format (and order).
|
||||
//
|
||||
// Note that the notion of custom content template will be ignored for incompatible
|
||||
// formatters and custom plugins. Compatible formatters are:
|
||||
//
|
||||
// - asciidoc document
|
||||
// - asciidoc table
|
||||
// - markdown document
|
||||
// - markdown table
|
||||
type Generator struct {
|
||||
// all the content combined
|
||||
content string
|
||||
|
||||
// individual sections
|
||||
header string
|
||||
footer string
|
||||
inputs string
|
||||
modules string
|
||||
outputs string
|
||||
providers string
|
||||
requirements string
|
||||
resources string
|
||||
|
||||
path string // module's path
|
||||
formatter string // formatter name
|
||||
|
||||
funcs []GenerateFunc
|
||||
}
|
||||
|
||||
// NewGenerator returns a Generator for specific formatter name and with
|
||||
// provided sets of GeneratorFunc functions to build and add individual
|
||||
// sections.
|
||||
func NewGenerator(name string, root string, fns ...GenerateFunc) *Generator {
|
||||
g := &Generator{
|
||||
path: root,
|
||||
formatter: name,
|
||||
funcs: []GenerateFunc{},
|
||||
}
|
||||
|
||||
g.Funcs(fns...)
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
// Content returns generted all the sections combined based on the underlying format.
|
||||
func (g *Generator) Content() string { return g.content }
|
||||
|
||||
// Header returns generted header section based on the underlying format.
|
||||
func (g *Generator) Header() string { return g.header }
|
||||
|
||||
// Footer returns generted footer section based on the underlying format.
|
||||
func (g *Generator) Footer() string { return g.footer }
|
||||
|
||||
// Inputs returns generted inputs section based on the underlying format.
|
||||
func (g *Generator) Inputs() string { return g.inputs }
|
||||
|
||||
// Modules returns generted modules section based on the underlying format.
|
||||
func (g *Generator) Modules() string { return g.modules }
|
||||
|
||||
// Outputs returns generted outputs section based on the underlying format.
|
||||
func (g *Generator) Outputs() string { return g.outputs }
|
||||
|
||||
// Providers returns generted providers section based on the underlying format.
|
||||
func (g *Generator) Providers() string { return g.providers }
|
||||
|
||||
// Requirements returns generted resources section based on the underlying format.
|
||||
func (g *Generator) Requirements() string { return g.requirements }
|
||||
|
||||
// Resources returns generted requirements section based on the underlying format.
|
||||
func (g *Generator) Resources() string { return g.resources }
|
||||
|
||||
// Funcs adds GenerateFunc to the list of available functions, for further use
|
||||
// if need be, and then runs them.
|
||||
func (g *Generator) Funcs(fns ...GenerateFunc) {
|
||||
for _, fn := range fns {
|
||||
g.funcs = append(g.funcs, fn)
|
||||
fn(g)
|
||||
}
|
||||
}
|
||||
|
||||
// Path set path of module's root directory.
|
||||
func (g *Generator) Path(root string) {
|
||||
g.path = root
|
||||
}
|
||||
|
||||
// ExecuteTemplate applies the template with Renderer known items. If template
|
||||
// is empty Renderer.content is returned as is. If template is not empty this
|
||||
// still returns Renderer.content for incompatible formatters.
|
||||
// func (g *Renderer) Render(contentTmpl string) (string, error) {
|
||||
func (g *Generator) ExecuteTemplate(contentTmpl string) (string, error) {
|
||||
if !g.isCompatible() {
|
||||
return g.content, nil
|
||||
}
|
||||
|
||||
if contentTmpl == "" {
|
||||
return g.content, nil
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
tmpl := template.New("content")
|
||||
tmpl.Funcs(template.FuncMap{
|
||||
"include": func(s string) string {
|
||||
content, err := os.ReadFile(filepath.Join(g.path, s))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(content)
|
||||
},
|
||||
})
|
||||
template.Must(tmpl.Parse(contentTmpl))
|
||||
|
||||
if err := tmpl.ExecuteTemplate(&buf, "content", g); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func (g *Generator) isCompatible() bool {
|
||||
switch g.formatter {
|
||||
case "asciidoc document", "asciidoc table", "markdown document", "markdown table":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// generatorCallback renders a Terraform module and creates a GenerateFunc.
|
||||
type generatorCallback func(string) GenerateFunc
|
||||
|
||||
// ForEach section executes generatorCallback to render the content for that
|
||||
// section and create corresponding GeneratorFunc. If there is any error in
|
||||
// the executing the template for the section ForEach function immediately
|
||||
// returns it and exit.
|
||||
func (g *Generator) ForEach(render func(string) (string, error)) error {
|
||||
mappings := map[string]generatorCallback{
|
||||
"all": WithContent,
|
||||
"header": WithHeader,
|
||||
"footer": WithFooter,
|
||||
"inputs": WithInputs,
|
||||
"modules": WithModules,
|
||||
"outputs": WithOutputs,
|
||||
"providers": WithProviders,
|
||||
"requirements": WithRequirements,
|
||||
"resources": WithResources,
|
||||
}
|
||||
for name, callback := range mappings {
|
||||
result, err := render(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fn := callback(result)
|
||||
g.funcs = append(g.funcs, fn)
|
||||
fn(g)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -74,6 +74,19 @@ func (t *Template) applyCustomFunc() {
|
||||
|
||||
// Render template with given Module struct.
|
||||
func (t *Template) Render(name string, module *terraform.Module) (string, error) {
|
||||
data := struct {
|
||||
Config *print.Config
|
||||
Module *terraform.Module
|
||||
}{
|
||||
Config: t.config,
|
||||
Module: module,
|
||||
}
|
||||
return t.RenderContent(name, data)
|
||||
}
|
||||
|
||||
// RenderContent template with given data. It can contain anything but most
|
||||
// probably it will only contain terraform.Module and print.generator.
|
||||
func (t *Template) RenderContent(name string, data interface{}) (string, error) {
|
||||
if len(t.items) < 1 {
|
||||
return "", fmt.Errorf("base template not found")
|
||||
}
|
||||
@@ -95,13 +108,7 @@ func (t *Template) Render(name string, module *terraform.Module) (string, error)
|
||||
gotemplate.Must(tt.Parse(normalize(ii.Text)))
|
||||
}
|
||||
|
||||
if err := tmpl.ExecuteTemplate(&buffer, item.Name, struct {
|
||||
Module *terraform.Module
|
||||
Config *print.Config
|
||||
}{
|
||||
Module: module,
|
||||
Config: t.config,
|
||||
}); err != nil {
|
||||
if err := tmpl.ExecuteTemplate(&buffer, item.Name, data); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user