From aa1e6bbf59b191e2028c865ff9d0b2bbf27179b2 Mon Sep 17 00:00:00 2001 From: Simon Clifford Date: Mon, 8 Feb 2021 12:19:49 +0000 Subject: [PATCH] Add support for footer docs Enables a footer to be appended to the end of a generated document sourced from tf files or documents in the same way as the header Adds the `footer-from` field to the config yml Adds the `--footer-from` flag to the cli Signed-off-by: Simon Clifford Signed-off-by: Khosrow Moossavi --- .editorconfig | 2 +- cmd/root.go | 1 + docs/reference/asciidoc-document.md | 11 +- docs/reference/asciidoc-table.md | 11 +- docs/reference/asciidoc.md | 5 +- docs/reference/json.md | 8 +- docs/reference/markdown-document.md | 11 +- docs/reference/markdown-table.md | 11 +- docs/reference/markdown.md | 5 +- docs/reference/pretty.md | 11 +- docs/reference/terraform-docs.md | 5 +- docs/reference/tfvars-hcl.md | 7 +- docs/reference/tfvars-json.md | 7 +- docs/reference/tfvars.md | 5 +- docs/reference/toml.md | 8 +- docs/reference/xml.md | 8 +- docs/reference/yaml.md | 11 +- docs/user-guide/configuration.md | 6 + docs/user-guide/how-to.md | 7 + examples/.terraform-docs.yml | 3 + examples/footer.md | 3 + go.mod | 2 +- go.sum | 4 +- internal/cli/config.go | 32 +- internal/cli/reader.go | 2 +- internal/cli/reader_test.go | 9 + internal/format/asciidoc_document_test.go | 27 +- internal/format/asciidoc_table_test.go | 27 +- internal/format/common_test.go | 47 +++ internal/format/json.go | 4 + internal/format/json_test.go | 17 +- internal/format/markdown_document_test.go | 32 +- internal/format/markdown_table_test.go | 32 +- internal/format/pretty_test.go | 17 +- .../format/templates/asciidoc_document.tmpl | 9 +- internal/format/templates/asciidoc_table.tmpl | 9 +- .../format/templates/markdown_document.tmpl | 9 +- internal/format/templates/markdown_table.tmpl | 9 +- internal/format/templates/pretty.tmpl | 7 + .../testdata/asciidoc/document-Base.golden | 6 +- .../document-IndentationOfFour.golden | 6 +- .../asciidoc/document-OnlyFooter.golden | 3 + .../asciidoc/document-WithAnchor.golden | 6 +- .../asciidoc/document-WithRequired.golden | 6 +- .../testdata/asciidoc/table-Base.golden | 6 +- .../asciidoc/table-IndentationOfFour.golden | 6 +- .../testdata/asciidoc/table-OnlyFooter.golden | 3 + .../testdata/asciidoc/table-WithAnchor.golden | 6 +- .../asciidoc/table-WithRequired.golden | 6 +- .../common/footer-FooterFromADOCFile.golden | 8 + .../common/footer-FooterFromMDFile.golden | 8 + .../common/footer-FooterFromTFFile.golden | 8 + .../common/footer-FooterFromTXTFile.golden | 8 + .../format/testdata/json/json-Base.golden | 1 + .../format/testdata/json/json-Empty.golden | 1 + .../json/json-EscapeCharacters.golden | 1 + .../format/testdata/json/json-HideAll.golden | 1 + .../testdata/json/json-OnlyFooter.golden | 10 + .../testdata/json/json-OnlyHeader.golden | 1 + .../testdata/json/json-OnlyInputs.golden | 1 + .../testdata/json/json-OnlyModulecalls.golden | 1 + .../testdata/json/json-OnlyOutputs.golden | 1 + .../testdata/json/json-OnlyProviders.golden | 1 + .../json/json-OnlyRequirements.golden | 1 + .../testdata/json/json-OnlyResources.golden | 1 + .../testdata/json/json-OutputValues.golden | 1 + .../testdata/markdown/document-Base.golden | 6 +- .../markdown/document-EscapeCharacters.golden | 6 +- .../document-IndentationOfFour.golden | 6 +- .../markdown/document-OnlyFooter.golden | 3 + .../markdown/document-WithAnchor.golden | 6 +- .../markdown/document-WithRequired.golden | 6 +- .../testdata/markdown/table-Base.golden | 6 +- .../markdown/table-EscapeCharacters.golden | 6 +- .../markdown/table-IndentationOfFour.golden | 6 +- .../testdata/markdown/table-OnlyFooter.golden | 3 + .../testdata/markdown/table-WithAnchor.golden | 6 +- .../markdown/table-WithRequired.golden | 6 +- .../format/testdata/pretty/pretty-Base.golden | 6 +- .../testdata/pretty/pretty-OnlyFooter.golden | 3 + .../testdata/pretty/pretty-WithColor.golden | 6 +- .../format/testdata/toml/toml-Base.golden | 1 + .../format/testdata/toml/toml-Empty.golden | 1 + .../format/testdata/toml/toml-HideAll.golden | 1 + .../testdata/toml/toml-OnlyFooter.golden | 8 + .../testdata/toml/toml-OnlyHeader.golden | 1 + .../testdata/toml/toml-OnlyInputs.golden | 1 + .../testdata/toml/toml-OnlyModulecalls.golden | 1 + .../testdata/toml/toml-OnlyOutputs.golden | 1 + .../testdata/toml/toml-OnlyProviders.golden | 1 + .../toml/toml-OnlyRequirements.golden | 1 + .../testdata/toml/toml-OnlyResources.golden | 1 + .../testdata/toml/toml-OutputValues.golden | 1 + internal/format/testdata/xml/xml-Base.golden | 1 + internal/format/testdata/xml/xml-Empty.golden | 1 + .../format/testdata/xml/xml-HideAll.golden | 1 + .../format/testdata/xml/xml-OnlyFooter.golden | 10 + .../format/testdata/xml/xml-OnlyHeader.golden | 1 + .../format/testdata/xml/xml-OnlyInputs.golden | 1 + .../testdata/xml/xml-OnlyModulecalls.golden | 1 + .../testdata/xml/xml-OnlyOutputs.golden | 1 + .../testdata/xml/xml-OnlyProviders.golden | 1 + .../testdata/xml/xml-OnlyRequirements.golden | 1 + .../testdata/xml/xml-OnlyResources.golden | 1 + .../testdata/xml/xml-OutputValues.golden | 1 + .../format/testdata/yaml/yaml-Base.golden | 4 + .../format/testdata/yaml/yaml-Empty.golden | 1 + .../format/testdata/yaml/yaml-HideAll.golden | 1 + .../testdata/yaml/yaml-OnlyFooter.golden | 11 + .../testdata/yaml/yaml-OnlyHeader.golden | 1 + .../testdata/yaml/yaml-OnlyInputs.golden | 1 + .../testdata/yaml/yaml-OnlyModulecalls.golden | 1 + .../testdata/yaml/yaml-OnlyOutputs.golden | 1 + .../testdata/yaml/yaml-OnlyProviders.golden | 1 + .../yaml/yaml-OnlyRequirements.golden | 1 + .../testdata/yaml/yaml-OnlyResources.golden | 1 + .../testdata/yaml/yaml-OutputValues.golden | 1 + internal/format/toml.go | 4 + internal/format/toml_test.go | 12 +- internal/format/xml.go | 4 + internal/format/xml_test.go | 12 +- internal/format/yaml.go | 4 + internal/format/yaml_test.go | 12 +- internal/print/settings.go | 8 + internal/template/sanitizer.go | 11 +- internal/template/sanitizer_test.go | 14 +- internal/template/template.go | 4 +- internal/template/template_test.go | 14 +- .../{header => section}/codeblock.expected | 0 .../{header => section}/codeblock.golden | 0 .../{header => section}/complex.expected | 0 .../{header => section}/complex.golden | 0 .../{header => section}/empty.expected | 0 .../testdata/{header => section}/empty.golden | 0 internal/terraform/module.go | 56 ++- internal/terraform/module_test.go | 341 +++++++++++++----- internal/terraform/options.go | 4 + .../full-example-mainTf-Header.golden | 7 + internal/testutil/settings.go | 1 + scripts/docs/generate.go | 7 +- 140 files changed, 984 insertions(+), 226 deletions(-) create mode 100644 examples/footer.md create mode 100644 internal/format/testdata/asciidoc/document-OnlyFooter.golden create mode 100644 internal/format/testdata/asciidoc/table-OnlyFooter.golden create mode 100644 internal/format/testdata/common/footer-FooterFromADOCFile.golden create mode 100644 internal/format/testdata/common/footer-FooterFromMDFile.golden create mode 100644 internal/format/testdata/common/footer-FooterFromTFFile.golden create mode 100644 internal/format/testdata/common/footer-FooterFromTXTFile.golden create mode 100644 internal/format/testdata/json/json-OnlyFooter.golden create mode 100644 internal/format/testdata/markdown/document-OnlyFooter.golden create mode 100644 internal/format/testdata/markdown/table-OnlyFooter.golden create mode 100644 internal/format/testdata/pretty/pretty-OnlyFooter.golden create mode 100644 internal/format/testdata/toml/toml-OnlyFooter.golden create mode 100644 internal/format/testdata/xml/xml-OnlyFooter.golden create mode 100644 internal/format/testdata/yaml/yaml-OnlyFooter.golden rename internal/template/testdata/{header => section}/codeblock.expected (100%) rename internal/template/testdata/{header => section}/codeblock.golden (100%) rename internal/template/testdata/{header => section}/complex.expected (100%) rename internal/template/testdata/{header => section}/complex.golden (100%) rename internal/template/testdata/{header => section}/empty.expected (100%) rename internal/template/testdata/{header => section}/empty.golden (100%) create mode 100644 internal/terraform/testdata/expected/full-example-mainTf-Header.golden diff --git a/.editorconfig b/.editorconfig index c1d75b2..50b04ac 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,7 +19,7 @@ indent_size = 4 [*.md] trim_trailing_whitespace = true -[examples/doc.{adoc,md,tf,txt}] +[examples/doc.{adoc,md,tf,txt};examples/footer.md] trim_trailing_whitespace = false insert_final_newline = false diff --git a/cmd/root.go b/cmd/root.go index 5952bea..7698160 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -71,6 +71,7 @@ func NewCommand() *cobra.Command { cmd.PersistentFlags().BoolVar(&config.Sort.By.Type, "sort-by-type", false, "sort items by type of them (default false)") cmd.PersistentFlags().StringVar(&config.HeaderFrom, "header-from", "main.tf", "relative path of a file to read header from") + cmd.PersistentFlags().StringVar(&config.FooterFrom, "footer-from", "", "relative path of a file to read footer from (default \"\")") cmd.PersistentFlags().BoolVar(&config.OutputValues.Enabled, "output-values", false, "inject output values into outputs (default false)") cmd.PersistentFlags().StringVar(&config.OutputValues.From, "output-values-from", "", "inject output values from file into outputs (default \"\")") diff --git a/docs/reference/asciidoc-document.md b/docs/reference/asciidoc-document.md index 166702d..51e5849 100644 --- a/docs/reference/asciidoc-document.md +++ b/docs/reference/asciidoc-document.md @@ -28,8 +28,9 @@ terraform-docs asciidoc document [PATH] [flags] --anchor create anchor links (default true) -c, --config string config file name (default ".terraform-docs.yml") --default show Default column or section (default true) + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --indent int indention level of AsciiDoc sections [1, 2, 3, 4, 5] (default 2) --output-file string File in module directory to insert output into (default "") @@ -39,7 +40,7 @@ terraform-docs asciidoc document [PATH] [flags] --output-values-from string inject output values from file into outputs (default "") --required show Required column or section (default true) --sensitive show Sensitive column or section (default true) - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -52,7 +53,7 @@ terraform-docs asciidoc document [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs asciidoc document ./examples/ +terraform-docs asciidoc document --footer-from footer.md ./examples/ ``` generates the following output: @@ -469,4 +470,8 @@ generates the following output: Description: It's unquoted output. + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document + [examples]: https://github.com/terraform-docs/terraform-docs/tree/master/examples diff --git a/docs/reference/asciidoc-table.md b/docs/reference/asciidoc-table.md index c06a14e..0878ab5 100644 --- a/docs/reference/asciidoc-table.md +++ b/docs/reference/asciidoc-table.md @@ -28,8 +28,9 @@ terraform-docs asciidoc table [PATH] [flags] --anchor create anchor links (default true) -c, --config string config file name (default ".terraform-docs.yml") --default show Default column or section (default true) + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --indent int indention level of AsciiDoc sections [1, 2, 3, 4, 5] (default 2) --output-file string File in module directory to insert output into (default "") @@ -39,7 +40,7 @@ terraform-docs asciidoc table [PATH] [flags] --output-values-from string inject output values from file into outputs (default "") --required show Required column or section (default true) --sensitive show Sensitive column or section (default true) - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -52,7 +53,7 @@ terraform-docs asciidoc table [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs asciidoc table ./examples/ +terraform-docs asciidoc table --footer-from footer.md ./examples/ ``` generates the following output: @@ -413,4 +414,8 @@ generates the following output: |[[output_unquoted]] <> |It's unquoted output. |=== + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document + [examples]: https://github.com/terraform-docs/terraform-docs/tree/master/examples diff --git a/docs/reference/asciidoc.md b/docs/reference/asciidoc.md index 5fb504f..97a7e73 100644 --- a/docs/reference/asciidoc.md +++ b/docs/reference/asciidoc.md @@ -32,15 +32,16 @@ terraform-docs asciidoc [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) diff --git a/docs/reference/json.md b/docs/reference/json.md index 45303ae..c302ec7 100644 --- a/docs/reference/json.md +++ b/docs/reference/json.md @@ -27,15 +27,16 @@ terraform-docs json [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -47,13 +48,14 @@ terraform-docs json [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs json ./examples/ +terraform-docs json --footer-from footer.md ./examples/ ``` generates the following output: { "header": "Usage:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)\n\n* list item 3\n* list item 4\n\n```hcl\nmodule \"foo_bar\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n```\n\nHere is some trailing text after code block,\nfollowed by another line of text.\n\n| Name | Description |\n|------|-----------------|\n| Foo | Foo description |\n| Bar | Bar description |", + "footer": "## This is an example of a footer\n\nIt looks exactly like a header, but is placed at the end of the document", "inputs": [ { "name": "bool-1", diff --git a/docs/reference/markdown-document.md b/docs/reference/markdown-document.md index e2af9b2..ba74efa 100644 --- a/docs/reference/markdown-document.md +++ b/docs/reference/markdown-document.md @@ -29,8 +29,9 @@ terraform-docs markdown document [PATH] [flags] -c, --config string config file name (default ".terraform-docs.yml") --default show Default column or section (default true) --escape escape special characters (default true) + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --indent int indention level of Markdown sections [1, 2, 3, 4, 5] (default 2) --output-file string File in module directory to insert output into (default "") @@ -40,7 +41,7 @@ terraform-docs markdown document [PATH] [flags] --output-values-from string inject output values from file into outputs (default "") --required show Required column or section (default true) --sensitive show Sensitive column or section (default true) - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -53,7 +54,7 @@ terraform-docs markdown document [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs markdown document ./examples/ +terraform-docs markdown document --footer-from footer.md ./examples/ ``` generates the following output: @@ -470,4 +471,8 @@ generates the following output: Description: It's unquoted output. + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document + [examples]: https://github.com/terraform-docs/terraform-docs/tree/master/examples diff --git a/docs/reference/markdown-table.md b/docs/reference/markdown-table.md index 414f374..17b9386 100644 --- a/docs/reference/markdown-table.md +++ b/docs/reference/markdown-table.md @@ -29,8 +29,9 @@ terraform-docs markdown table [PATH] [flags] -c, --config string config file name (default ".terraform-docs.yml") --default show Default column or section (default true) --escape escape special characters (default true) + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --indent int indention level of Markdown sections [1, 2, 3, 4, 5] (default 2) --output-file string File in module directory to insert output into (default "") @@ -40,7 +41,7 @@ terraform-docs markdown table [PATH] [flags] --output-values-from string inject output values from file into outputs (default "") --required show Required column or section (default true) --sensitive show Sensitive column or section (default true) - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -53,7 +54,7 @@ terraform-docs markdown table [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs markdown table ./examples/ +terraform-docs markdown table --footer-from footer.md ./examples/ ``` generates the following output: @@ -175,4 +176,8 @@ generates the following output: | [output-2](#output\_output-2) | It's output number two. | | [unquoted](#output\_unquoted) | It's unquoted output. | + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document + [examples]: https://github.com/terraform-docs/terraform-docs/tree/master/examples diff --git a/docs/reference/markdown.md b/docs/reference/markdown.md index 757de8e..6907a07 100644 --- a/docs/reference/markdown.md +++ b/docs/reference/markdown.md @@ -33,15 +33,16 @@ terraform-docs markdown [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) diff --git a/docs/reference/pretty.md b/docs/reference/pretty.md index 290f9fe..b747a3c 100644 --- a/docs/reference/pretty.md +++ b/docs/reference/pretty.md @@ -27,15 +27,16 @@ terraform-docs pretty [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -47,7 +48,7 @@ terraform-docs pretty [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs pretty --no-color ./examples/ +terraform-docs pretty --footer-from footer.md --no-color ./examples/ ``` generates the following output: @@ -252,4 +253,8 @@ generates the following output: output.unquoted It's unquoted output. + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document + [examples]: https://github.com/terraform-docs/terraform-docs/tree/master/examples diff --git a/docs/reference/terraform-docs.md b/docs/reference/terraform-docs.md index 4e8bcd9..b118cf1 100644 --- a/docs/reference/terraform-docs.md +++ b/docs/reference/terraform-docs.md @@ -20,16 +20,17 @@ terraform-docs [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") -h, --help help for terraform-docs - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) diff --git a/docs/reference/tfvars-hcl.md b/docs/reference/tfvars-hcl.md index 0fac8db..6eab334 100644 --- a/docs/reference/tfvars-hcl.md +++ b/docs/reference/tfvars-hcl.md @@ -26,15 +26,16 @@ terraform-docs tfvars hcl [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -46,7 +47,7 @@ terraform-docs tfvars hcl [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs tfvars hcl ./examples/ +terraform-docs tfvars hcl --footer-from footer.md ./examples/ ``` generates the following output: diff --git a/docs/reference/tfvars-json.md b/docs/reference/tfvars-json.md index a3b1f49..448f16e 100644 --- a/docs/reference/tfvars-json.md +++ b/docs/reference/tfvars-json.md @@ -26,15 +26,16 @@ terraform-docs tfvars json [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -46,7 +47,7 @@ terraform-docs tfvars json [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs tfvars json ./examples/ +terraform-docs tfvars json --footer-from footer.md ./examples/ ``` generates the following output: diff --git a/docs/reference/tfvars.md b/docs/reference/tfvars.md index 7ac87dd..9d6f522 100644 --- a/docs/reference/tfvars.md +++ b/docs/reference/tfvars.md @@ -22,15 +22,16 @@ Generate terraform.tfvars of inputs. ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) diff --git a/docs/reference/toml.md b/docs/reference/toml.md index 665b4b9..0284a2d 100644 --- a/docs/reference/toml.md +++ b/docs/reference/toml.md @@ -26,15 +26,16 @@ terraform-docs toml [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -46,12 +47,13 @@ terraform-docs toml [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs toml ./examples/ +terraform-docs toml --footer-from footer.md ./examples/ ``` generates the following output: header = "Usage:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)\n\n* list item 3\n* list item 4\n\n```hcl\nmodule \"foo_bar\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n```\n\nHere is some trailing text after code block,\nfollowed by another line of text.\n\n| Name | Description |\n|------|-----------------|\n| Foo | Foo description |\n| Bar | Bar description |" + footer = "## This is an example of a footer\n\nIt looks exactly like a header, but is placed at the end of the document" [[inputs]] name = "bool-1" diff --git a/docs/reference/xml.md b/docs/reference/xml.md index 28d2285..ebaffae 100644 --- a/docs/reference/xml.md +++ b/docs/reference/xml.md @@ -26,15 +26,16 @@ terraform-docs xml [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -46,13 +47,14 @@ terraform-docs xml [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs xml ./examples/ +terraform-docs xml --footer-from footer.md ./examples/ ``` generates the following output:
Usage: Example of 'foo_bar' module in `foo_bar.tf`. - list item 1 - list item 2 Even inline **formatting** in _here_ is possible. and some [link](https://domain.com/) * list item 3 * list item 4 ```hcl module "foo_bar" { source = "github.com/foo/bar" id = "1234567890" name = "baz" zones = ["us-east-1", "us-west-1"] tags = { Name = "baz" Created-By = "first.last@email.com" Date-Created = "20180101" } } ``` Here is some trailing text after code block, followed by another line of text. | Name | Description | |------|-----------------| | Foo | Foo description | | Bar | Bar description |
+
## This is an example of a footer It looks exactly like a header, but is placed at the end of the document
bool-1 diff --git a/docs/reference/yaml.md b/docs/reference/yaml.md index e6d18f5..91f7343 100644 --- a/docs/reference/yaml.md +++ b/docs/reference/yaml.md @@ -26,15 +26,16 @@ terraform-docs yaml [PATH] [flags] ```console -c, --config string config file name (default ".terraform-docs.yml") + --footer-from string relative path of a file to read footer from (default "") --header-from string relative path of a file to read header from (default "main.tf") - --hide strings hide section [header, inputs, modules, outputs, providers, requirements, resources] + --hide strings hide section [footer, header, inputs, modules, outputs, providers, requirements, resources] --hide-all hide all sections (default false) --output-file string File in module directory to insert output into (default "") --output-mode string Output to file method [inject, replace] (default "inject") --output-template string Output template (default "\n{{ .Content }}\n") --output-values inject output values into outputs (default false) --output-values-from string inject output values from file into outputs (default "") - --show strings show section [header, inputs, modules, outputs, providers, requirements, resources] + --show strings show section [footer, header, inputs, modules, outputs, providers, requirements, resources] --show-all show all sections (default true) --sort sort items (default true) --sort-by-required sort items by name and print required ones first (default false) @@ -46,7 +47,7 @@ terraform-docs yaml [PATH] [flags] Given the [`examples`][examples] module: ```shell -terraform-docs yaml ./examples/ +terraform-docs yaml --footer-from footer.md ./examples/ ``` generates the following output: @@ -89,6 +90,10 @@ generates the following output: |------|-----------------| | Foo | Foo description | | Bar | Bar description | + footer: |- + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document inputs: - name: bool-1 type: bool diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md index 0d85f9b..0c48423 100644 --- a/docs/user-guide/configuration.md +++ b/docs/user-guide/configuration.md @@ -45,6 +45,7 @@ corresponding default values (if applicable). ```yaml formatter: header-from: main.tf +footer-from: "" sections: hide-all: false @@ -117,6 +118,11 @@ formatter name must be set to `foo`. Relative path to a file to extract header for the generated output from. Supported file formats are `.adoc`, `.md`, `.tf`, and `.txt`. Default value is `main.tf`. +## footer-from + +Relative path to a file to extract footer for the generated output from. Supported +file formats are `.adoc`, `.md`, `.tf`, and `.txt`. Default value is `""`. + ## Sections The following options are supported and can be used for `sections.show` and diff --git a/docs/user-guide/how-to.md b/docs/user-guide/how-to.md index a21586c..f9f0d9c 100644 --- a/docs/user-guide/how-to.md +++ b/docs/user-guide/how-to.md @@ -62,6 +62,13 @@ before any `resource`, `variable`, `module`, etc. whatever extracted is intended as is. It's up to you to apply any kind of Markdown formatting to them (i.e. adding `` at the end of lines for break, etc.) +## Module Footer + +Extracting module footer works exactly like header with one exception. There is no +default file to attempt extraction from, you need to explicitly specify desired file +to extract content from with `--footer-from FILE` or corresponding `footer-from` in +configuration file. + ## Insert Output To File Since `v0.12.0` generated output can be insterted directly into the file. There diff --git a/examples/.terraform-docs.yml b/examples/.terraform-docs.yml index fe28c1d..f3ff1f3 100644 --- a/examples/.terraform-docs.yml +++ b/examples/.terraform-docs.yml @@ -1,5 +1,7 @@ formatter: markdown table header-from: doc.txt +footer-from: footer.md + sections: hide-all: true show: @@ -7,6 +9,7 @@ sections: - inputs - providers - modules + - footer # output: # file: README.md diff --git a/examples/footer.md b/examples/footer.md new file mode 100644 index 0000000..fdc9ab7 --- /dev/null +++ b/examples/footer.md @@ -0,0 +1,3 @@ +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/go.mod b/go.mod index cd0f992..3279b85 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/spf13/cobra v1.1.3 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.7.0 - github.com/terraform-docs/plugin-sdk v0.1.1-0.20210308171055-c824968635cd + github.com/terraform-docs/plugin-sdk v0.1.1-0.20210315181351-354f95b748c2 github.com/terraform-docs/terraform-config-inspect v0.0.0-20210126151735-6ef25af8884f gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b honnef.co/go/tools v0.1.2 diff --git a/go.sum b/go.sum index 0010648..55576fa 100644 --- a/go.sum +++ b/go.sum @@ -221,8 +221,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/terraform-docs/plugin-sdk v0.1.1-0.20210308171055-c824968635cd h1:8pCJh7PJHkyR9yF5aiWItGwyHem7DTvtqlZOIt9D0cw= -github.com/terraform-docs/plugin-sdk v0.1.1-0.20210308171055-c824968635cd/go.mod h1:3G+0nZTeaMF1c5CZh8cOEYeNq0kUL6+DlQOVcxK7eCQ= +github.com/terraform-docs/plugin-sdk v0.1.1-0.20210315181351-354f95b748c2 h1:sRiFTk/RE2vdLu4/Qm7NN0wNvIuj7vFblBfYDOuQ7qg= +github.com/terraform-docs/plugin-sdk v0.1.1-0.20210315181351-354f95b748c2/go.mod h1:3G+0nZTeaMF1c5CZh8cOEYeNq0kUL6+DlQOVcxK7eCQ= github.com/terraform-docs/terraform-config-inspect v0.0.0-20210126151735-6ef25af8884f h1:WXgHENMC8JOyj6aRpOlnAnJkZ3ZAkPBOhqYrJ5GOhDE= github.com/terraform-docs/terraform-config-inspect v0.0.0-20210126151735-6ef25af8884f/go.mod h1:GtanFwTsRRXScYHOMb5h4K18XQBFeS2tXat9/LrPtPc= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= diff --git a/internal/cli/config.go b/internal/cli/config.go index 96ce788..9e4c10d 100644 --- a/internal/cli/config.go +++ b/internal/cli/config.go @@ -19,6 +19,7 @@ import ( ) const ( + sectionFooter = "footer" sectionHeader = "header" sectionInputs = "inputs" sectionModules = "modules" @@ -28,7 +29,7 @@ const ( sectionResources = "resources" ) -var allSections = []string{sectionHeader, sectionInputs, sectionModules, sectionOutputs, sectionProviders, sectionRequirements, sectionResources} +var allSections = []string{sectionFooter, sectionHeader, sectionInputs, sectionModules, sectionOutputs, sectionProviders, sectionRequirements, sectionResources} // AllSections list. var AllSections = strings.Join(allSections, ", ") @@ -40,6 +41,7 @@ type sections struct { HideAll bool `yaml:"hide-all"` header bool `yaml:"-"` + footer bool `yaml:"-"` inputs bool `yaml:"-"` modulecalls bool `yaml:"-"` outputs bool `yaml:"-"` @@ -56,6 +58,7 @@ func defaultSections() sections { HideAll: false, header: false, + footer: false, inputs: false, modulecalls: false, outputs: false, @@ -68,14 +71,14 @@ func defaultSections() sections { func (s *sections) validate() error { for _, item := range s.Show { switch item { - case allSections[0], allSections[1], allSections[2], allSections[3], allSections[4], allSections[5], allSections[6]: + case allSections[0], allSections[1], allSections[2], allSections[3], allSections[4], allSections[5], allSections[6], allSections[7]: default: return fmt.Errorf("'%s' is not a valid section", item) } } for _, item := range s.Hide { switch item { - case allSections[0], allSections[1], allSections[2], allSections[3], allSections[4], allSections[5], allSections[6]: + case allSections[0], allSections[1], allSections[2], allSections[3], allSections[4], allSections[5], allSections[6], allSections[7]: default: return fmt.Errorf("'%s' is not a valid section", item) } @@ -273,6 +276,7 @@ type Config struct { File string `yaml:"-"` Formatter string `yaml:"formatter"` HeaderFrom string `yaml:"header-from"` + FooterFrom string `yaml:"footer-from"` Sections sections `yaml:"sections"` Output output `yaml:"output"` OutputValues outputvalues `yaml:"output-values"` @@ -287,6 +291,7 @@ func DefaultConfig() *Config { File: "", Formatter: "", HeaderFrom: "main.tf", + FooterFrom: "", Sections: defaultSections(), Output: defaultOutput(), OutputValues: defaultOutputValues(), @@ -304,13 +309,20 @@ func (c *Config) process() { if !c.Sections.ShowAll && !changedfs["hide-all"] { c.Sections.HideAll = true } + c.Sections.header = c.Sections.visibility("header") + c.Sections.footer = c.Sections.visibility("footer") c.Sections.inputs = c.Sections.visibility("inputs") c.Sections.modulecalls = c.Sections.visibility("modules") c.Sections.outputs = c.Sections.visibility("outputs") c.Sections.providers = c.Sections.visibility("providers") c.Sections.requirements = c.Sections.visibility("requirements") c.Sections.resources = c.Sections.visibility("resources") + + // Footer section optional and should not cause error with --show-all + if c.Sections.ShowAll && c.Sections.footer { + c.Sections.footer = false + } } // validate config and check for any misuse or misconfiguration @@ -325,6 +337,15 @@ func (c *Config) validate() error { return fmt.Errorf("value of '--header-from' can't be empty") } + // footer-from, not a 'default' section so can be empty even if show-all enabled + if c.Sections.footer && !c.Sections.ShowAll && c.FooterFrom == "" { + return fmt.Errorf("value of '--footer-from' can't be empty") + } + + if c.FooterFrom == c.HeaderFrom { + return fmt.Errorf("value of '--footer-from' can't equal value of '--header-from") + } + // sections if err := c.Sections.validate(); err != nil { return err @@ -362,8 +383,13 @@ func (c *Config) extract() (*print.Settings, *terraform.Options) { options.ShowHeader = settings.ShowHeader options.HeaderFromFile = c.HeaderFrom + // footer-from + options.ShowFooter = settings.ShowFooter + options.FooterFromFile = c.FooterFrom + // sections settings.ShowHeader = c.Sections.header + settings.ShowFooter = c.Sections.footer settings.ShowInputs = c.Sections.inputs settings.ShowModuleCalls = c.Sections.modulecalls settings.ShowOutputs = c.Sections.outputs diff --git a/internal/cli/reader.go b/internal/cli/reader.go index 44cbae3..a639a80 100644 --- a/internal/cli/reader.go +++ b/internal/cli/reader.go @@ -63,7 +63,7 @@ func (c *cfgreader) parse() error { } switch flag { - case "header-from": + case "header-from", "footer-from": if err := c.overrideValue(flag, c.config, &c.overrides); err != nil { return err } diff --git a/internal/cli/reader_test.go b/internal/cli/reader_test.go index 712cdc8..98ddd17 100644 --- a/internal/cli/reader_test.go +++ b/internal/cli/reader_test.go @@ -92,6 +92,15 @@ func TestOverrideValue(t *testing.T) { wantErr: false, errMsg: "", }, + { + name: "override values of given field", + tag: "footer-from", + to: func() interface{} { return config }, + from: func() interface{} { return override }, + overrideFn: func() { override.FooterFrom = "bar.txt" }, + wantErr: false, + errMsg: "", + }, { name: "override values of given field", tag: "enabled", diff --git a/internal/format/asciidoc_document_test.go b/internal/format/asciidoc_document_test.go index 2df23dd..a1a03e9 100644 --- a/internal/format/asciidoc_document_test.go +++ b/internal/format/asciidoc_document_test.go @@ -28,7 +28,10 @@ func TestAsciidocDocument(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -51,7 +54,10 @@ func TestAsciidocDocument(t *testing.T) { ShowRequired: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithAnchor": { settings: testutil.WithSections( @@ -59,7 +65,10 @@ func TestAsciidocDocument(t *testing.T) { ShowAnchor: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithoutDefault": { settings: print.Settings{ @@ -83,7 +92,10 @@ func TestAsciidocDocument(t *testing.T) { IndentLevel: 4, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "OutputValues": { settings: print.Settings{ @@ -113,6 +125,13 @@ func TestAsciidocDocument(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ ShowInputs: true, diff --git a/internal/format/asciidoc_table_test.go b/internal/format/asciidoc_table_test.go index 33e2a0f..da9c424 100644 --- a/internal/format/asciidoc_table_test.go +++ b/internal/format/asciidoc_table_test.go @@ -28,7 +28,10 @@ func TestAsciidocTable(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -51,7 +54,10 @@ func TestAsciidocTable(t *testing.T) { ShowRequired: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithAnchor": { settings: testutil.WithSections( @@ -59,7 +65,10 @@ func TestAsciidocTable(t *testing.T) { ShowAnchor: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithoutDefault": { settings: print.Settings{ @@ -83,7 +92,10 @@ func TestAsciidocTable(t *testing.T) { IndentLevel: 4, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "OutputValues": { settings: print.Settings{ @@ -113,6 +125,13 @@ func TestAsciidocTable(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ ShowInputs: true, diff --git a/internal/format/common_test.go b/internal/format/common_test.go index b4ddb34..6bb7c86 100644 --- a/internal/format/common_test.go +++ b/internal/format/common_test.go @@ -140,3 +140,50 @@ func TestCommonHeaderFrom(t *testing.T) { }) } } + +func TestCommonFooterFrom(t *testing.T) { + tests := map[string]struct { + options terraform.Options + }{ + "FooterFromADOCFile": { + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "doc.adoc", + }, + }, + "FooterFromMDFile": { + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "doc.md", + }, + }, + "FooterFromTFFile": { + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "doc.tf", + }, + }, + "FooterFromTXTFile": { + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "doc.txt", + }, + }, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + + expected, err := testutil.GetExpected("common", "footer-"+name) + assert.Nil(err) + + options, err := terraform.NewOptions().WithOverwrite(&tt.options) + assert.Nil(err) + + module, err := testutil.GetModule(options) + assert.Nil(err) + + assert.Equal(expected, module.Footer) + }) + } +} diff --git a/internal/format/json.go b/internal/format/json.go index a380063..b863b61 100644 --- a/internal/format/json.go +++ b/internal/format/json.go @@ -31,6 +31,7 @@ func NewJSON(settings *print.Settings) print.Engine { func (j *JSON) Print(module *terraform.Module, settings *print.Settings) (string, error) { copy := &terraform.Module{ Header: "", + Footer: "", Inputs: make([]*terraform.Input, 0), ModuleCalls: make([]*terraform.ModuleCall, 0), Outputs: make([]*terraform.Output, 0), @@ -42,6 +43,9 @@ func (j *JSON) Print(module *terraform.Module, settings *print.Settings) (string if settings.ShowHeader { copy.Header = module.Header } + if settings.ShowFooter { + copy.Footer = module.Footer + } if settings.ShowInputs { copy.Inputs = module.Inputs } diff --git a/internal/format/json_test.go b/internal/format/json_test.go index 6bc2010..37b5952 100644 --- a/internal/format/json_test.go +++ b/internal/format/json_test.go @@ -28,7 +28,10 @@ func TestJson(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -51,7 +54,10 @@ func TestJson(t *testing.T) { EscapeCharacters: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "OutputValues": { settings: print.Settings{ @@ -70,6 +76,13 @@ func TestJson(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ShowInputs: true}, options: terraform.Options{}, diff --git a/internal/format/markdown_document_test.go b/internal/format/markdown_document_test.go index 55d9ed9..daf5316 100644 --- a/internal/format/markdown_document_test.go +++ b/internal/format/markdown_document_test.go @@ -28,7 +28,10 @@ func TestMarkdownDocument(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -51,7 +54,10 @@ func TestMarkdownDocument(t *testing.T) { ShowRequired: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithAnchor": { settings: testutil.WithSections( @@ -59,7 +65,10 @@ func TestMarkdownDocument(t *testing.T) { ShowAnchor: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithoutDefault": { settings: print.Settings{ @@ -83,7 +92,10 @@ func TestMarkdownDocument(t *testing.T) { EscapeCharacters: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "IndentationOfFour": { settings: testutil.WithSections( @@ -91,7 +103,10 @@ func TestMarkdownDocument(t *testing.T) { IndentLevel: 4, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "OutputValues": { settings: print.Settings{ @@ -121,6 +136,13 @@ func TestMarkdownDocument(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ ShowInputs: true, diff --git a/internal/format/markdown_table_test.go b/internal/format/markdown_table_test.go index 9fe6b36..8903a4a 100644 --- a/internal/format/markdown_table_test.go +++ b/internal/format/markdown_table_test.go @@ -28,7 +28,10 @@ func TestMarkdownTable(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -51,7 +54,10 @@ func TestMarkdownTable(t *testing.T) { ShowRequired: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithAnchor": { settings: testutil.WithSections( @@ -59,7 +65,10 @@ func TestMarkdownTable(t *testing.T) { ShowAnchor: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "WithoutDefault": { settings: print.Settings{ @@ -83,7 +92,10 @@ func TestMarkdownTable(t *testing.T) { EscapeCharacters: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "IndentationOfFour": { settings: testutil.WithSections( @@ -91,7 +103,10 @@ func TestMarkdownTable(t *testing.T) { IndentLevel: 4, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "OutputValues": { settings: print.Settings{ @@ -121,6 +136,13 @@ func TestMarkdownTable(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ ShowInputs: true, diff --git a/internal/format/pretty_test.go b/internal/format/pretty_test.go index 154ea9b..edf0a22 100644 --- a/internal/format/pretty_test.go +++ b/internal/format/pretty_test.go @@ -28,7 +28,10 @@ func TestPretty(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -51,7 +54,10 @@ func TestPretty(t *testing.T) { ShowColor: true, }, ), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "OutputValues": { settings: print.Settings{ @@ -70,6 +76,13 @@ func TestPretty(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ShowInputs: true}, options: terraform.Options{}, diff --git a/internal/format/templates/asciidoc_document.tmpl b/internal/format/templates/asciidoc_document.tmpl index 34ff3f3..6dd88ca 100644 --- a/internal/format/templates/asciidoc_document.tmpl +++ b/internal/format/templates/asciidoc_document.tmpl @@ -1,6 +1,6 @@ {{- if .Settings.ShowHeader -}} {{- with .Module.Header -}} - {{ sanitizeHeader . }} + {{ sanitizeSection . }} {{ printf "\n" }} {{- end -}} {{ end -}} @@ -158,4 +158,11 @@ {{ end }} {{ end }} {{ end }} +{{ end -}} + +{{- if .Settings.ShowFooter -}} + {{- with .Module.Footer -}} + {{ sanitizeSection . }} + {{ printf "\n" }} + {{- end -}} {{ end -}} \ No newline at end of file diff --git a/internal/format/templates/asciidoc_table.tmpl b/internal/format/templates/asciidoc_table.tmpl index 29beec7..7dd7dbc 100644 --- a/internal/format/templates/asciidoc_table.tmpl +++ b/internal/format/templates/asciidoc_table.tmpl @@ -1,6 +1,6 @@ {{- if .Settings.ShowHeader -}} {{- with .Module.Header -}} - {{ sanitizeHeader . }} + {{ sanitizeSection . }} {{ printf "\n" }} {{- end -}} {{ end -}} @@ -111,4 +111,11 @@ {{- end }} |=== {{ end }} +{{ end -}} + +{{- if .Settings.ShowFooter -}} + {{- with .Module.Footer -}} + {{ sanitizeSection . }} + {{ printf "\n" }} + {{- end -}} {{ end -}} \ No newline at end of file diff --git a/internal/format/templates/markdown_document.tmpl b/internal/format/templates/markdown_document.tmpl index eb06066..4217f04 100644 --- a/internal/format/templates/markdown_document.tmpl +++ b/internal/format/templates/markdown_document.tmpl @@ -1,6 +1,6 @@ {{- if .Settings.ShowHeader -}} {{- with .Module.Header -}} - {{ sanitizeHeader . }} + {{ sanitizeSection . }} {{ printf "\n" }} {{- end -}} {{ end -}} @@ -159,4 +159,11 @@ {{ end }} {{ end }} {{ end }} +{{ end -}} + +{{- if .Settings.ShowFooter -}} + {{- with .Module.Footer -}} + {{ sanitizeSection . }} + {{ printf "\n" }} + {{- end -}} {{ end -}} \ No newline at end of file diff --git a/internal/format/templates/markdown_table.tmpl b/internal/format/templates/markdown_table.tmpl index fbbca36..87748da 100644 --- a/internal/format/templates/markdown_table.tmpl +++ b/internal/format/templates/markdown_table.tmpl @@ -1,6 +1,6 @@ {{- if .Settings.ShowHeader -}} {{- with .Module.Header -}} - {{ sanitizeHeader . }} + {{ sanitizeSection . }} {{ printf "\n" }} {{- end -}} {{ end -}} @@ -108,3 +108,10 @@ {{- end }} {{ end }} {{ end -}} + +{{- if .Settings.ShowFooter -}} + {{- with .Module.Footer -}} + {{ sanitizeSection . }} + {{ printf "\n" }} + {{- end -}} +{{ end -}} \ No newline at end of file diff --git a/internal/format/templates/pretty.tmpl b/internal/format/templates/pretty.tmpl index 7914fd2..0c918b1 100644 --- a/internal/format/templates/pretty.tmpl +++ b/internal/format/templates/pretty.tmpl @@ -70,4 +70,11 @@ {{- printf "\n\n" -}} {{ end -}} {{ end -}} +{{ end -}} + +{{- if .Settings.ShowFooter -}} + {{- with .Module.Footer -}} + {{ colorize "\033[90m" . }} + {{ end -}} + {{- printf "\n\n" -}} {{ end -}} \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/document-Base.golden b/internal/format/testdata/asciidoc/document-Base.golden index 646a9ad..ae2f12b 100644 --- a/internal/format/testdata/asciidoc/document-Base.golden +++ b/internal/format/testdata/asciidoc/document-Base.golden @@ -418,4 +418,8 @@ Description: It's output number one. === output-0.12 -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/document-IndentationOfFour.golden b/internal/format/testdata/asciidoc/document-IndentationOfFour.golden index cb31196..112affe 100644 --- a/internal/format/testdata/asciidoc/document-IndentationOfFour.golden +++ b/internal/format/testdata/asciidoc/document-IndentationOfFour.golden @@ -418,4 +418,8 @@ Description: It's output number one. ===== output-0.12 -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/document-OnlyFooter.golden b/internal/format/testdata/asciidoc/document-OnlyFooter.golden new file mode 100644 index 0000000..fdc9ab7 --- /dev/null +++ b/internal/format/testdata/asciidoc/document-OnlyFooter.golden @@ -0,0 +1,3 @@ +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/document-WithAnchor.golden b/internal/format/testdata/asciidoc/document-WithAnchor.golden index 5dd88df..03e0506 100644 --- a/internal/format/testdata/asciidoc/document-WithAnchor.golden +++ b/internal/format/testdata/asciidoc/document-WithAnchor.golden @@ -418,4 +418,8 @@ Description: It's output number one. === [[output_output-0.12]] <> -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/document-WithRequired.golden b/internal/format/testdata/asciidoc/document-WithRequired.golden index 9b6ea14..8879f88 100644 --- a/internal/format/testdata/asciidoc/document-WithRequired.golden +++ b/internal/format/testdata/asciidoc/document-WithRequired.golden @@ -408,4 +408,8 @@ Description: It's output number one. === output-0.12 -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/table-Base.golden b/internal/format/testdata/asciidoc/table-Base.golden index b29d34f..b76c5d3 100644 --- a/internal/format/testdata/asciidoc/table-Base.golden +++ b/internal/format/testdata/asciidoc/table-Base.golden @@ -317,4 +317,8 @@ object({ |output-2 |It's output number two. |output-1 |It's output number one. |output-0.12 |terraform 0.12 only -|=== \ No newline at end of file +|=== + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/table-IndentationOfFour.golden b/internal/format/testdata/asciidoc/table-IndentationOfFour.golden index d85b6b0..3f98adf 100644 --- a/internal/format/testdata/asciidoc/table-IndentationOfFour.golden +++ b/internal/format/testdata/asciidoc/table-IndentationOfFour.golden @@ -317,4 +317,8 @@ object({ |output-2 |It's output number two. |output-1 |It's output number one. |output-0.12 |terraform 0.12 only -|=== \ No newline at end of file +|=== + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/table-OnlyFooter.golden b/internal/format/testdata/asciidoc/table-OnlyFooter.golden new file mode 100644 index 0000000..fdc9ab7 --- /dev/null +++ b/internal/format/testdata/asciidoc/table-OnlyFooter.golden @@ -0,0 +1,3 @@ +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/table-WithAnchor.golden b/internal/format/testdata/asciidoc/table-WithAnchor.golden index cb0b374..1c01e55 100644 --- a/internal/format/testdata/asciidoc/table-WithAnchor.golden +++ b/internal/format/testdata/asciidoc/table-WithAnchor.golden @@ -317,4 +317,8 @@ object({ |[[output_output-2]] <> |It's output number two. |[[output_output-1]] <> |It's output number one. |[[output_output-0.12]] <> |terraform 0.12 only -|=== \ No newline at end of file +|=== + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/asciidoc/table-WithRequired.golden b/internal/format/testdata/asciidoc/table-WithRequired.golden index 942ad64..2b23ef6 100644 --- a/internal/format/testdata/asciidoc/table-WithRequired.golden +++ b/internal/format/testdata/asciidoc/table-WithRequired.golden @@ -352,4 +352,8 @@ object({ |output-2 |It's output number two. |output-1 |It's output number one. |output-0.12 |terraform 0.12 only -|=== \ No newline at end of file +|=== + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/common/footer-FooterFromADOCFile.golden b/internal/format/testdata/common/footer-FooterFromADOCFile.golden new file mode 100644 index 0000000..9412641 --- /dev/null +++ b/internal/format/testdata/common/footer-FooterFromADOCFile.golden @@ -0,0 +1,8 @@ += This header comes from a custom AsciiDoc file + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna +aliqua. Ut enim ad minim veniam, quis nostrud exercitation +ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit +esse cillum dolore eu fugiat nulla pariatur. \ No newline at end of file diff --git a/internal/format/testdata/common/footer-FooterFromMDFile.golden b/internal/format/testdata/common/footer-FooterFromMDFile.golden new file mode 100644 index 0000000..1ef23fb --- /dev/null +++ b/internal/format/testdata/common/footer-FooterFromMDFile.golden @@ -0,0 +1,8 @@ +# This header comes from a custom Markdown file + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna +aliqua. Ut enim ad minim veniam, quis nostrud exercitation +ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit +esse cillum dolore eu fugiat nulla pariatur. \ No newline at end of file diff --git a/internal/format/testdata/common/footer-FooterFromTFFile.golden b/internal/format/testdata/common/footer-FooterFromTFFile.golden new file mode 100644 index 0000000..f1e78ee --- /dev/null +++ b/internal/format/testdata/common/footer-FooterFromTFFile.golden @@ -0,0 +1,8 @@ +This header comes from a custom file + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna +aliqua. Ut enim ad minim veniam, quis nostrud exercitation +ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit +esse cillum dolore eu fugiat nulla pariatur. \ No newline at end of file diff --git a/internal/format/testdata/common/footer-FooterFromTXTFile.golden b/internal/format/testdata/common/footer-FooterFromTXTFile.golden new file mode 100644 index 0000000..0cea7bc --- /dev/null +++ b/internal/format/testdata/common/footer-FooterFromTXTFile.golden @@ -0,0 +1,8 @@ +# This header comes from a custom Text file + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna +aliqua. Ut enim ad minim veniam, quis nostrud exercitation +ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit +esse cillum dolore eu fugiat nulla pariatur. \ No newline at end of file diff --git a/internal/format/testdata/json/json-Base.golden b/internal/format/testdata/json/json-Base.golden index 780cd45..dd5c44e 100644 --- a/internal/format/testdata/json/json-Base.golden +++ b/internal/format/testdata/json/json-Base.golden @@ -1,5 +1,6 @@ { "header": "Usage:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)\n\n* list item 3\n* list item 4\n\n```hcl\nmodule \"foo_bar\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n```\n\nHere is some trailing text after code block,\nfollowed by another line of text.\n\n| Name | Description |\n|------|-----------------|\n| Foo | Foo description |\n| Bar | Bar description |", + "footer": "## This is an example of a footer\n\nIt looks exactly like a header, but is placed at the end of the document", "inputs": [ { "name": "unquoted", diff --git a/internal/format/testdata/json/json-Empty.golden b/internal/format/testdata/json/json-Empty.golden index b015014..f35ea73 100644 --- a/internal/format/testdata/json/json-Empty.golden +++ b/internal/format/testdata/json/json-Empty.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [], "outputs": [], diff --git a/internal/format/testdata/json/json-EscapeCharacters.golden b/internal/format/testdata/json/json-EscapeCharacters.golden index af3f21e..5121d0d 100644 --- a/internal/format/testdata/json/json-EscapeCharacters.golden +++ b/internal/format/testdata/json/json-EscapeCharacters.golden @@ -1,5 +1,6 @@ { "header": "Usage:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)\n\n* list item 3\n* list item 4\n\n```hcl\nmodule \"foo_bar\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n```\n\nHere is some trailing text after code block,\nfollowed by another line of text.\n\n| Name | Description |\n|------|-----------------|\n| Foo | Foo description |\n| Bar | Bar description |", + "footer": "## This is an example of a footer\n\nIt looks exactly like a header, but is placed at the end of the document", "inputs": [ { "name": "unquoted", diff --git a/internal/format/testdata/json/json-HideAll.golden b/internal/format/testdata/json/json-HideAll.golden index b015014..f35ea73 100644 --- a/internal/format/testdata/json/json-HideAll.golden +++ b/internal/format/testdata/json/json-HideAll.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [], "outputs": [], diff --git a/internal/format/testdata/json/json-OnlyFooter.golden b/internal/format/testdata/json/json-OnlyFooter.golden new file mode 100644 index 0000000..48ffd0a --- /dev/null +++ b/internal/format/testdata/json/json-OnlyFooter.golden @@ -0,0 +1,10 @@ +{ + "header": "", + "footer": "## This is an example of a footer\n\nIt looks exactly like a header, but is placed at the end of the document", + "inputs": [], + "modules": [], + "outputs": [], + "providers": [], + "requirements": [], + "resources": [] +} \ No newline at end of file diff --git a/internal/format/testdata/json/json-OnlyHeader.golden b/internal/format/testdata/json/json-OnlyHeader.golden index 52eceb8..b6655c4 100644 --- a/internal/format/testdata/json/json-OnlyHeader.golden +++ b/internal/format/testdata/json/json-OnlyHeader.golden @@ -1,5 +1,6 @@ { "header": "Usage:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)\n\n* list item 3\n* list item 4\n\n```hcl\nmodule \"foo_bar\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n```\n\nHere is some trailing text after code block,\nfollowed by another line of text.\n\n| Name | Description |\n|------|-----------------|\n| Foo | Foo description |\n| Bar | Bar description |", + "footer": "", "inputs": [], "modules": [], "outputs": [], diff --git a/internal/format/testdata/json/json-OnlyInputs.golden b/internal/format/testdata/json/json-OnlyInputs.golden index 21feb1e..7056cd9 100644 --- a/internal/format/testdata/json/json-OnlyInputs.golden +++ b/internal/format/testdata/json/json-OnlyInputs.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [ { "name": "unquoted", diff --git a/internal/format/testdata/json/json-OnlyModulecalls.golden b/internal/format/testdata/json/json-OnlyModulecalls.golden index a39754a..de2fc4b 100644 --- a/internal/format/testdata/json/json-OnlyModulecalls.golden +++ b/internal/format/testdata/json/json-OnlyModulecalls.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [ { diff --git a/internal/format/testdata/json/json-OnlyOutputs.golden b/internal/format/testdata/json/json-OnlyOutputs.golden index 20aa34e..d715cfa 100644 --- a/internal/format/testdata/json/json-OnlyOutputs.golden +++ b/internal/format/testdata/json/json-OnlyOutputs.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [], "outputs": [ diff --git a/internal/format/testdata/json/json-OnlyProviders.golden b/internal/format/testdata/json/json-OnlyProviders.golden index f96a17c..e6d8420 100644 --- a/internal/format/testdata/json/json-OnlyProviders.golden +++ b/internal/format/testdata/json/json-OnlyProviders.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [], "outputs": [], diff --git a/internal/format/testdata/json/json-OnlyRequirements.golden b/internal/format/testdata/json/json-OnlyRequirements.golden index 0f50432..fcb2002 100644 --- a/internal/format/testdata/json/json-OnlyRequirements.golden +++ b/internal/format/testdata/json/json-OnlyRequirements.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [], "outputs": [], diff --git a/internal/format/testdata/json/json-OnlyResources.golden b/internal/format/testdata/json/json-OnlyResources.golden index 00cfe83..f3c0709 100644 --- a/internal/format/testdata/json/json-OnlyResources.golden +++ b/internal/format/testdata/json/json-OnlyResources.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [], "outputs": [], diff --git a/internal/format/testdata/json/json-OutputValues.golden b/internal/format/testdata/json/json-OutputValues.golden index 3666e86..4f54bc8 100644 --- a/internal/format/testdata/json/json-OutputValues.golden +++ b/internal/format/testdata/json/json-OutputValues.golden @@ -1,5 +1,6 @@ { "header": "", + "footer": "", "inputs": [], "modules": [], "outputs": [ diff --git a/internal/format/testdata/markdown/document-Base.golden b/internal/format/testdata/markdown/document-Base.golden index cb2f69d..69bafbc 100644 --- a/internal/format/testdata/markdown/document-Base.golden +++ b/internal/format/testdata/markdown/document-Base.golden @@ -418,4 +418,8 @@ Description: It's output number one. ### output-0.12 -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/document-EscapeCharacters.golden b/internal/format/testdata/markdown/document-EscapeCharacters.golden index ebe127f..a3c0cca 100644 --- a/internal/format/testdata/markdown/document-EscapeCharacters.golden +++ b/internal/format/testdata/markdown/document-EscapeCharacters.golden @@ -418,4 +418,8 @@ Description: It's output number one. ### output-0.12 -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/document-IndentationOfFour.golden b/internal/format/testdata/markdown/document-IndentationOfFour.golden index e2eafbe..9af45b9 100644 --- a/internal/format/testdata/markdown/document-IndentationOfFour.golden +++ b/internal/format/testdata/markdown/document-IndentationOfFour.golden @@ -418,4 +418,8 @@ Description: It's output number one. ##### output-0.12 -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/document-OnlyFooter.golden b/internal/format/testdata/markdown/document-OnlyFooter.golden new file mode 100644 index 0000000..fdc9ab7 --- /dev/null +++ b/internal/format/testdata/markdown/document-OnlyFooter.golden @@ -0,0 +1,3 @@ +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/document-WithAnchor.golden b/internal/format/testdata/markdown/document-WithAnchor.golden index 0fc337a..552b5ab 100644 --- a/internal/format/testdata/markdown/document-WithAnchor.golden +++ b/internal/format/testdata/markdown/document-WithAnchor.golden @@ -418,4 +418,8 @@ Description: It's output number one. ### [output-0.12](#output_output-0.12) -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/document-WithRequired.golden b/internal/format/testdata/markdown/document-WithRequired.golden index 3870413..d85f733 100644 --- a/internal/format/testdata/markdown/document-WithRequired.golden +++ b/internal/format/testdata/markdown/document-WithRequired.golden @@ -408,4 +408,8 @@ Description: It's output number one. ### output-0.12 -Description: terraform 0.12 only \ No newline at end of file +Description: terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/table-Base.golden b/internal/format/testdata/markdown/table-Base.golden index 4d082f7..dea8630 100644 --- a/internal/format/testdata/markdown/table-Base.golden +++ b/internal/format/testdata/markdown/table-Base.golden @@ -113,4 +113,8 @@ followed by another line of text. | unquoted | It's unquoted output. | | output-2 | It's output number two. | | output-1 | It's output number one. | -| output-0.12 | terraform 0.12 only | \ No newline at end of file +| output-0.12 | terraform 0.12 only | + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/table-EscapeCharacters.golden b/internal/format/testdata/markdown/table-EscapeCharacters.golden index 1f100d7..70e750e 100644 --- a/internal/format/testdata/markdown/table-EscapeCharacters.golden +++ b/internal/format/testdata/markdown/table-EscapeCharacters.golden @@ -113,4 +113,8 @@ followed by another line of text. | unquoted | It's unquoted output. | | output-2 | It's output number two. | | output-1 | It's output number one. | -| output-0.12 | terraform 0.12 only | \ No newline at end of file +| output-0.12 | terraform 0.12 only | + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/table-IndentationOfFour.golden b/internal/format/testdata/markdown/table-IndentationOfFour.golden index 0d58440..969010c 100644 --- a/internal/format/testdata/markdown/table-IndentationOfFour.golden +++ b/internal/format/testdata/markdown/table-IndentationOfFour.golden @@ -113,4 +113,8 @@ followed by another line of text. | unquoted | It's unquoted output. | | output-2 | It's output number two. | | output-1 | It's output number one. | -| output-0.12 | terraform 0.12 only | \ No newline at end of file +| output-0.12 | terraform 0.12 only | + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/table-OnlyFooter.golden b/internal/format/testdata/markdown/table-OnlyFooter.golden new file mode 100644 index 0000000..fdc9ab7 --- /dev/null +++ b/internal/format/testdata/markdown/table-OnlyFooter.golden @@ -0,0 +1,3 @@ +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/table-WithAnchor.golden b/internal/format/testdata/markdown/table-WithAnchor.golden index 0ce7265..a1951f8 100644 --- a/internal/format/testdata/markdown/table-WithAnchor.golden +++ b/internal/format/testdata/markdown/table-WithAnchor.golden @@ -113,4 +113,8 @@ followed by another line of text. | [unquoted](#output_unquoted) | It's unquoted output. | | [output-2](#output_output-2) | It's output number two. | | [output-1](#output_output-1) | It's output number one. | -| [output-0.12](#output_output-0.12) | terraform 0.12 only | \ No newline at end of file +| [output-0.12](#output_output-0.12) | terraform 0.12 only | + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/markdown/table-WithRequired.golden b/internal/format/testdata/markdown/table-WithRequired.golden index c0ee289..656ddee 100644 --- a/internal/format/testdata/markdown/table-WithRequired.golden +++ b/internal/format/testdata/markdown/table-WithRequired.golden @@ -113,4 +113,8 @@ followed by another line of text. | unquoted | It's unquoted output. | | output-2 | It's output number two. | | output-1 | It's output number one. | -| output-0.12 | terraform 0.12 only | \ No newline at end of file +| output-0.12 | terraform 0.12 only | + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/pretty/pretty-Base.golden b/internal/format/testdata/pretty/pretty-Base.golden index ae47a50..b67532c 100644 --- a/internal/format/testdata/pretty/pretty-Base.golden +++ b/internal/format/testdata/pretty/pretty-Base.golden @@ -196,4 +196,8 @@ output.output-1 It's output number one. output.output-0.12 -terraform 0.12 only \ No newline at end of file +terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/pretty/pretty-OnlyFooter.golden b/internal/format/testdata/pretty/pretty-OnlyFooter.golden new file mode 100644 index 0000000..fdc9ab7 --- /dev/null +++ b/internal/format/testdata/pretty/pretty-OnlyFooter.golden @@ -0,0 +1,3 @@ +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/pretty/pretty-WithColor.golden b/internal/format/testdata/pretty/pretty-WithColor.golden index 6448fff..09f1812 100644 --- a/internal/format/testdata/pretty/pretty-WithColor.golden +++ b/internal/format/testdata/pretty/pretty-WithColor.golden @@ -196,4 +196,8 @@ It spans over multiple lines. It's output number one. output.output-0.12 -terraform 0.12 only \ No newline at end of file +terraform 0.12 only + +## This is an example of a footer + +It looks exactly like a header, but is placed at the end of the document \ No newline at end of file diff --git a/internal/format/testdata/toml/toml-Base.golden b/internal/format/testdata/toml/toml-Base.golden index 479c194..ffc011e 100644 --- a/internal/format/testdata/toml/toml-Base.golden +++ b/internal/format/testdata/toml/toml-Base.golden @@ -1,4 +1,5 @@ header = "Usage:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)\n\n* list item 3\n* list item 4\n\n```hcl\nmodule \"foo_bar\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n```\n\nHere is some trailing text after code block,\nfollowed by another line of text.\n\n| Name | Description |\n|------|-----------------|\n| Foo | Foo description |\n| Bar | Bar description |" +footer = "## This is an example of a footer\n\nIt looks exactly like a header, but is placed at the end of the document" [[inputs]] name = "unquoted" diff --git a/internal/format/testdata/toml/toml-Empty.golden b/internal/format/testdata/toml/toml-Empty.golden index 9852941..332e127 100644 --- a/internal/format/testdata/toml/toml-Empty.golden +++ b/internal/format/testdata/toml/toml-Empty.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] modules = [] outputs = [] diff --git a/internal/format/testdata/toml/toml-HideAll.golden b/internal/format/testdata/toml/toml-HideAll.golden index 9852941..332e127 100644 --- a/internal/format/testdata/toml/toml-HideAll.golden +++ b/internal/format/testdata/toml/toml-HideAll.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] modules = [] outputs = [] diff --git a/internal/format/testdata/toml/toml-OnlyFooter.golden b/internal/format/testdata/toml/toml-OnlyFooter.golden new file mode 100644 index 0000000..b3da1e7 --- /dev/null +++ b/internal/format/testdata/toml/toml-OnlyFooter.golden @@ -0,0 +1,8 @@ +header = "" +footer = "## This is an example of a footer\n\nIt looks exactly like a header, but is placed at the end of the document" +inputs = [] +modules = [] +outputs = [] +providers = [] +requirements = [] +resources = [] \ No newline at end of file diff --git a/internal/format/testdata/toml/toml-OnlyHeader.golden b/internal/format/testdata/toml/toml-OnlyHeader.golden index 002880f..64836e7 100644 --- a/internal/format/testdata/toml/toml-OnlyHeader.golden +++ b/internal/format/testdata/toml/toml-OnlyHeader.golden @@ -1,4 +1,5 @@ header = "Usage:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)\n\n* list item 3\n* list item 4\n\n```hcl\nmodule \"foo_bar\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n```\n\nHere is some trailing text after code block,\nfollowed by another line of text.\n\n| Name | Description |\n|------|-----------------|\n| Foo | Foo description |\n| Bar | Bar description |" +footer = "" inputs = [] modules = [] outputs = [] diff --git a/internal/format/testdata/toml/toml-OnlyInputs.golden b/internal/format/testdata/toml/toml-OnlyInputs.golden index fbf8143..9eef1a1 100644 --- a/internal/format/testdata/toml/toml-OnlyInputs.golden +++ b/internal/format/testdata/toml/toml-OnlyInputs.golden @@ -1,4 +1,5 @@ header = "" +footer = "" modules = [] outputs = [] providers = [] diff --git a/internal/format/testdata/toml/toml-OnlyModulecalls.golden b/internal/format/testdata/toml/toml-OnlyModulecalls.golden index c181506..4506541 100644 --- a/internal/format/testdata/toml/toml-OnlyModulecalls.golden +++ b/internal/format/testdata/toml/toml-OnlyModulecalls.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] outputs = [] providers = [] diff --git a/internal/format/testdata/toml/toml-OnlyOutputs.golden b/internal/format/testdata/toml/toml-OnlyOutputs.golden index 5a1defe..c362997 100644 --- a/internal/format/testdata/toml/toml-OnlyOutputs.golden +++ b/internal/format/testdata/toml/toml-OnlyOutputs.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] modules = [] providers = [] diff --git a/internal/format/testdata/toml/toml-OnlyProviders.golden b/internal/format/testdata/toml/toml-OnlyProviders.golden index 5286455..ba815b5 100644 --- a/internal/format/testdata/toml/toml-OnlyProviders.golden +++ b/internal/format/testdata/toml/toml-OnlyProviders.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] modules = [] outputs = [] diff --git a/internal/format/testdata/toml/toml-OnlyRequirements.golden b/internal/format/testdata/toml/toml-OnlyRequirements.golden index 3fb1e1e..8e0158f 100644 --- a/internal/format/testdata/toml/toml-OnlyRequirements.golden +++ b/internal/format/testdata/toml/toml-OnlyRequirements.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] modules = [] outputs = [] diff --git a/internal/format/testdata/toml/toml-OnlyResources.golden b/internal/format/testdata/toml/toml-OnlyResources.golden index c3b719d..9c36fef 100644 --- a/internal/format/testdata/toml/toml-OnlyResources.golden +++ b/internal/format/testdata/toml/toml-OnlyResources.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] modules = [] outputs = [] diff --git a/internal/format/testdata/toml/toml-OutputValues.golden b/internal/format/testdata/toml/toml-OutputValues.golden index 86462c1..38f34ab 100644 --- a/internal/format/testdata/toml/toml-OutputValues.golden +++ b/internal/format/testdata/toml/toml-OutputValues.golden @@ -1,4 +1,5 @@ header = "" +footer = "" inputs = [] modules = [] providers = [] diff --git a/internal/format/testdata/xml/xml-Base.golden b/internal/format/testdata/xml/xml-Base.golden index d844fb8..a6b7809 100644 --- a/internal/format/testdata/xml/xml-Base.golden +++ b/internal/format/testdata/xml/xml-Base.golden @@ -1,5 +1,6 @@
Usage: Example of 'foo_bar' module in `foo_bar.tf`. - list item 1 - list item 2 Even inline **formatting** in _here_ is possible. and some [link](https://domain.com/) * list item 3 * list item 4 ```hcl module "foo_bar" { source = "github.com/foo/bar" id = "1234567890" name = "baz" zones = ["us-east-1", "us-west-1"] tags = { Name = "baz" Created-By = "first.last@email.com" Date-Created = "20180101" } } ``` Here is some trailing text after code block, followed by another line of text. | Name | Description | |------|-----------------| | Foo | Foo description | | Bar | Bar description |
+
## This is an example of a footer It looks exactly like a header, but is placed at the end of the document
unquoted diff --git a/internal/format/testdata/xml/xml-Empty.golden b/internal/format/testdata/xml/xml-Empty.golden index 1a9f4d7..0939a4f 100644 --- a/internal/format/testdata/xml/xml-Empty.golden +++ b/internal/format/testdata/xml/xml-Empty.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/xml/xml-HideAll.golden b/internal/format/testdata/xml/xml-HideAll.golden index 1a9f4d7..0939a4f 100644 --- a/internal/format/testdata/xml/xml-HideAll.golden +++ b/internal/format/testdata/xml/xml-HideAll.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/xml/xml-OnlyFooter.golden b/internal/format/testdata/xml/xml-OnlyFooter.golden new file mode 100644 index 0000000..e40d381 --- /dev/null +++ b/internal/format/testdata/xml/xml-OnlyFooter.golden @@ -0,0 +1,10 @@ + +
+
## This is an example of a footer It looks exactly like a header, but is placed at the end of the document
+ + + + + + +
\ No newline at end of file diff --git a/internal/format/testdata/xml/xml-OnlyHeader.golden b/internal/format/testdata/xml/xml-OnlyHeader.golden index ca60ccb..312f81a 100644 --- a/internal/format/testdata/xml/xml-OnlyHeader.golden +++ b/internal/format/testdata/xml/xml-OnlyHeader.golden @@ -1,5 +1,6 @@
Usage: Example of 'foo_bar' module in `foo_bar.tf`. - list item 1 - list item 2 Even inline **formatting** in _here_ is possible. and some [link](https://domain.com/) * list item 3 * list item 4 ```hcl module "foo_bar" { source = "github.com/foo/bar" id = "1234567890" name = "baz" zones = ["us-east-1", "us-west-1"] tags = { Name = "baz" Created-By = "first.last@email.com" Date-Created = "20180101" } } ``` Here is some trailing text after code block, followed by another line of text. | Name | Description | |------|-----------------| | Foo | Foo description | | Bar | Bar description |
+
diff --git a/internal/format/testdata/xml/xml-OnlyInputs.golden b/internal/format/testdata/xml/xml-OnlyInputs.golden index 54b6088..a735596 100644 --- a/internal/format/testdata/xml/xml-OnlyInputs.golden +++ b/internal/format/testdata/xml/xml-OnlyInputs.golden @@ -1,5 +1,6 @@
+
unquoted diff --git a/internal/format/testdata/xml/xml-OnlyModulecalls.golden b/internal/format/testdata/xml/xml-OnlyModulecalls.golden index 7a8fc28..bf9e212 100644 --- a/internal/format/testdata/xml/xml-OnlyModulecalls.golden +++ b/internal/format/testdata/xml/xml-OnlyModulecalls.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/xml/xml-OnlyOutputs.golden b/internal/format/testdata/xml/xml-OnlyOutputs.golden index 626c559..1e1fb27 100644 --- a/internal/format/testdata/xml/xml-OnlyOutputs.golden +++ b/internal/format/testdata/xml/xml-OnlyOutputs.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/xml/xml-OnlyProviders.golden b/internal/format/testdata/xml/xml-OnlyProviders.golden index 6891d5b..6da7f3c 100644 --- a/internal/format/testdata/xml/xml-OnlyProviders.golden +++ b/internal/format/testdata/xml/xml-OnlyProviders.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/xml/xml-OnlyRequirements.golden b/internal/format/testdata/xml/xml-OnlyRequirements.golden index 1f79a16..4f1803c 100644 --- a/internal/format/testdata/xml/xml-OnlyRequirements.golden +++ b/internal/format/testdata/xml/xml-OnlyRequirements.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/xml/xml-OnlyResources.golden b/internal/format/testdata/xml/xml-OnlyResources.golden index ec374ce..f120250 100644 --- a/internal/format/testdata/xml/xml-OnlyResources.golden +++ b/internal/format/testdata/xml/xml-OnlyResources.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/xml/xml-OutputValues.golden b/internal/format/testdata/xml/xml-OutputValues.golden index f3802dd..95d3d31 100644 --- a/internal/format/testdata/xml/xml-OutputValues.golden +++ b/internal/format/testdata/xml/xml-OutputValues.golden @@ -1,5 +1,6 @@
+
diff --git a/internal/format/testdata/yaml/yaml-Base.golden b/internal/format/testdata/yaml/yaml-Base.golden index b6c7205..b4fa5a5 100644 --- a/internal/format/testdata/yaml/yaml-Base.golden +++ b/internal/format/testdata/yaml/yaml-Base.golden @@ -36,6 +36,10 @@ header: |- |------|-----------------| | Foo | Foo description | | Bar | Bar description | +footer: |- + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document inputs: - name: unquoted type: any diff --git a/internal/format/testdata/yaml/yaml-Empty.golden b/internal/format/testdata/yaml/yaml-Empty.golden index 4a62352..1871762 100644 --- a/internal/format/testdata/yaml/yaml-Empty.golden +++ b/internal/format/testdata/yaml/yaml-Empty.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: [] outputs: [] diff --git a/internal/format/testdata/yaml/yaml-HideAll.golden b/internal/format/testdata/yaml/yaml-HideAll.golden index 4a62352..1871762 100644 --- a/internal/format/testdata/yaml/yaml-HideAll.golden +++ b/internal/format/testdata/yaml/yaml-HideAll.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: [] outputs: [] diff --git a/internal/format/testdata/yaml/yaml-OnlyFooter.golden b/internal/format/testdata/yaml/yaml-OnlyFooter.golden new file mode 100644 index 0000000..5688225 --- /dev/null +++ b/internal/format/testdata/yaml/yaml-OnlyFooter.golden @@ -0,0 +1,11 @@ +header: "" +footer: |- + ## This is an example of a footer + + It looks exactly like a header, but is placed at the end of the document +inputs: [] +modules: [] +outputs: [] +providers: [] +requirements: [] +resources: [] \ No newline at end of file diff --git a/internal/format/testdata/yaml/yaml-OnlyHeader.golden b/internal/format/testdata/yaml/yaml-OnlyHeader.golden index b388973..d0a56f2 100644 --- a/internal/format/testdata/yaml/yaml-OnlyHeader.golden +++ b/internal/format/testdata/yaml/yaml-OnlyHeader.golden @@ -36,6 +36,7 @@ header: |- |------|-----------------| | Foo | Foo description | | Bar | Bar description | +footer: "" inputs: [] modules: [] outputs: [] diff --git a/internal/format/testdata/yaml/yaml-OnlyInputs.golden b/internal/format/testdata/yaml/yaml-OnlyInputs.golden index da19324..ae07a1b 100644 --- a/internal/format/testdata/yaml/yaml-OnlyInputs.golden +++ b/internal/format/testdata/yaml/yaml-OnlyInputs.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: - name: unquoted type: any diff --git a/internal/format/testdata/yaml/yaml-OnlyModulecalls.golden b/internal/format/testdata/yaml/yaml-OnlyModulecalls.golden index d571e9d..c0cb028 100644 --- a/internal/format/testdata/yaml/yaml-OnlyModulecalls.golden +++ b/internal/format/testdata/yaml/yaml-OnlyModulecalls.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: - name: foo diff --git a/internal/format/testdata/yaml/yaml-OnlyOutputs.golden b/internal/format/testdata/yaml/yaml-OnlyOutputs.golden index 4eaf60f..a8efb93 100644 --- a/internal/format/testdata/yaml/yaml-OnlyOutputs.golden +++ b/internal/format/testdata/yaml/yaml-OnlyOutputs.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: [] outputs: diff --git a/internal/format/testdata/yaml/yaml-OnlyProviders.golden b/internal/format/testdata/yaml/yaml-OnlyProviders.golden index 4746e4e..93ae90c 100644 --- a/internal/format/testdata/yaml/yaml-OnlyProviders.golden +++ b/internal/format/testdata/yaml/yaml-OnlyProviders.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: [] outputs: [] diff --git a/internal/format/testdata/yaml/yaml-OnlyRequirements.golden b/internal/format/testdata/yaml/yaml-OnlyRequirements.golden index 2707ce0..e7e51c3 100644 --- a/internal/format/testdata/yaml/yaml-OnlyRequirements.golden +++ b/internal/format/testdata/yaml/yaml-OnlyRequirements.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: [] outputs: [] diff --git a/internal/format/testdata/yaml/yaml-OnlyResources.golden b/internal/format/testdata/yaml/yaml-OnlyResources.golden index 5224a14..c786d9d 100644 --- a/internal/format/testdata/yaml/yaml-OnlyResources.golden +++ b/internal/format/testdata/yaml/yaml-OnlyResources.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: [] outputs: [] diff --git a/internal/format/testdata/yaml/yaml-OutputValues.golden b/internal/format/testdata/yaml/yaml-OutputValues.golden index 5a23c88..de11f2a 100644 --- a/internal/format/testdata/yaml/yaml-OutputValues.golden +++ b/internal/format/testdata/yaml/yaml-OutputValues.golden @@ -1,4 +1,5 @@ header: "" +footer: "" inputs: [] modules: [] outputs: diff --git a/internal/format/toml.go b/internal/format/toml.go index 8420a58..e92eb3b 100644 --- a/internal/format/toml.go +++ b/internal/format/toml.go @@ -32,6 +32,7 @@ func NewTOML(settings *print.Settings) print.Engine { func (t *TOML) Print(module *terraform.Module, settings *print.Settings) (string, error) { copy := terraform.Module{ Header: "", + Footer: "", Providers: make([]*terraform.Provider, 0), Inputs: make([]*terraform.Input, 0), ModuleCalls: make([]*terraform.ModuleCall, 0), @@ -43,6 +44,9 @@ func (t *TOML) Print(module *terraform.Module, settings *print.Settings) (string if settings.ShowHeader { copy.Header = module.Header } + if settings.ShowFooter { + copy.Footer = module.Footer + } if settings.ShowInputs { copy.Inputs = module.Inputs } diff --git a/internal/format/toml_test.go b/internal/format/toml_test.go index 128cca6..0379543 100644 --- a/internal/format/toml_test.go +++ b/internal/format/toml_test.go @@ -28,7 +28,10 @@ func TestToml(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -62,6 +65,13 @@ func TestToml(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ShowInputs: true}, options: terraform.Options{}, diff --git a/internal/format/xml.go b/internal/format/xml.go index 277fff8..17991ba 100644 --- a/internal/format/xml.go +++ b/internal/format/xml.go @@ -30,6 +30,7 @@ func NewXML(settings *print.Settings) print.Engine { func (x *XML) Print(module *terraform.Module, settings *print.Settings) (string, error) { copy := &terraform.Module{ Header: "", + Footer: "", Inputs: make([]*terraform.Input, 0), ModuleCalls: make([]*terraform.ModuleCall, 0), Outputs: make([]*terraform.Output, 0), @@ -41,6 +42,9 @@ func (x *XML) Print(module *terraform.Module, settings *print.Settings) (string, if settings.ShowHeader { copy.Header = module.Header } + if settings.ShowFooter { + copy.Footer = module.Footer + } if settings.ShowInputs { copy.Inputs = module.Inputs } diff --git a/internal/format/xml_test.go b/internal/format/xml_test.go index e3f46b3..36400ee 100644 --- a/internal/format/xml_test.go +++ b/internal/format/xml_test.go @@ -28,7 +28,10 @@ func TestXml(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -62,6 +65,13 @@ func TestXml(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ShowInputs: true}, options: terraform.Options{}, diff --git a/internal/format/yaml.go b/internal/format/yaml.go index 0e42e0b..7e2773f 100644 --- a/internal/format/yaml.go +++ b/internal/format/yaml.go @@ -32,6 +32,7 @@ func NewYAML(settings *print.Settings) print.Engine { func (y *YAML) Print(module *terraform.Module, settings *print.Settings) (string, error) { copy := &terraform.Module{ Header: "", + Footer: "", Inputs: make([]*terraform.Input, 0), ModuleCalls: make([]*terraform.ModuleCall, 0), Outputs: make([]*terraform.Output, 0), @@ -43,6 +44,9 @@ func (y *YAML) Print(module *terraform.Module, settings *print.Settings) (string if settings.ShowHeader { copy.Header = module.Header } + if settings.ShowFooter { + copy.Footer = module.Footer + } if settings.ShowInputs { copy.Inputs = module.Inputs } diff --git a/internal/format/yaml_test.go b/internal/format/yaml_test.go index 14fceed..1b93485 100644 --- a/internal/format/yaml_test.go +++ b/internal/format/yaml_test.go @@ -28,7 +28,10 @@ func TestYaml(t *testing.T) { // Base "Base": { settings: testutil.WithSections(), - options: terraform.Options{}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, }, "Empty": { settings: testutil.WithSections(), @@ -62,6 +65,13 @@ func TestYaml(t *testing.T) { settings: print.Settings{ShowHeader: true}, options: terraform.Options{}, }, + "OnlyFooter": { + settings: print.Settings{ShowFooter: true}, + options: terraform.Options{ + ShowFooter: true, + FooterFromFile: "footer.md", + }, + }, "OnlyInputs": { settings: print.Settings{ShowInputs: true}, options: terraform.Options{}, diff --git a/internal/print/settings.go b/internal/print/settings.go index e97071d..b6fd9b3 100644 --- a/internal/print/settings.go +++ b/internal/print/settings.go @@ -52,6 +52,12 @@ type Settings struct { // scope: Asciidoc, Markdown ShowDefault bool + // ShowFooter show "Footer" module information + // + // default: false + // scope: Global + ShowFooter bool + // ShowHeader show "Header" module information // // default: true @@ -122,6 +128,7 @@ func DefaultSettings() *Settings { ShowAnchor: true, ShowColor: true, ShowDefault: true, + ShowFooter: false, ShowHeader: true, ShowInputs: true, ShowModuleCalls: true, @@ -143,6 +150,7 @@ func (s *Settings) Convert() *printsdk.Settings { OutputValues: s.OutputValues, ShowColor: s.ShowColor, ShowDefault: s.ShowDefault, + ShowFooter: s.ShowFooter, ShowHeader: s.ShowHeader, ShowInputs: s.ShowInputs, ShowOutputs: s.ShowOutputs, diff --git a/internal/template/sanitizer.go b/internal/template/sanitizer.go index 3176eae..30ac136 100644 --- a/internal/template/sanitizer.go +++ b/internal/template/sanitizer.go @@ -30,12 +30,13 @@ func sanitizeName(name string, settings *print.Settings) string { return name } -// sanitizeHeader converts passed 'string' to suitable Markdown representation -// for a document. (including line-break, illegal characters, code blocks etc) +// sanitizeSection converts passed 'string' to suitable Markdown or AsciiDoc +// representation for a document. (including line-break, illegal characters, +// code blocks etc). This is in particular being used for header and footer. // -// IMPORTANT: sanitizeHeader will never change the line-endings and preserve them -// as they are provided by the users. -func sanitizeHeader(s string, settings *print.Settings) string { +// IMPORTANT: sanitizeSection will never change the line-endings and preserve +// them as they are provided by the users. +func sanitizeSection(s string, settings *print.Settings) string { if s == "" { return "n/a" } diff --git a/internal/template/sanitizer_test.go b/internal/template/sanitizer_test.go index 3014f68..056d272 100644 --- a/internal/template/sanitizer_test.go +++ b/internal/template/sanitizer_test.go @@ -107,24 +107,24 @@ func TestSanitizeName(t *testing.T) { } } -func TestSanitizeHeader(t *testing.T) { +func TestSanitizeSection(t *testing.T) { tests := []struct { name string filename string escape bool }{ { - name: "sanitize header item empty", + name: "sanitize section item empty", filename: "empty", escape: true, }, { - name: "sanitize header item complex", + name: "sanitize section item complex", filename: "complex", escape: true, }, { - name: "sanitize header item codeblock", + name: "sanitize section item codeblock", filename: "codeblock", escape: true, }, @@ -136,12 +136,12 @@ func TestSanitizeHeader(t *testing.T) { EscapeCharacters: tt.escape, } - bytes, err := ioutil.ReadFile(filepath.Join("testdata", "header", tt.filename+".golden")) + bytes, err := ioutil.ReadFile(filepath.Join("testdata", "section", tt.filename+".golden")) assert.Nil(err) - actual := sanitizeHeader(string(bytes), settings) + actual := sanitizeSection(string(bytes), settings) - expected, err := ioutil.ReadFile(filepath.Join("testdata", "header", tt.filename+".expected")) + expected, err := ioutil.ReadFile(filepath.Join("testdata", "section", tt.filename+".expected")) assert.Nil(err) assert.Equal(string(expected), actual) diff --git a/internal/template/template.go b/internal/template/template.go index 2a1ac6b..40c3a5c 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -46,8 +46,8 @@ func New(settings *print.Settings, items ...*Item) *Template { "tostring": func(s types.String) string { return string(s) }, - "sanitizeHeader": func(s string) string { - return sanitizeHeader(s, settings) + "sanitizeSection": func(s string) string { + return sanitizeSection(s, settings) }, "sanitizeDoc": func(s string) string { return sanitizeDocument(s, settings) diff --git a/internal/template/template_test.go b/internal/template/template_test.go index 3bd9038..8469bd2 100644 --- a/internal/template/template_test.go +++ b/internal/template/template_test.go @@ -346,24 +346,24 @@ func TestBuiltinFunc(t *testing.T) { expected: "", }, - // sanitizeHeader + // sanitizeSection { - name: "template builtin functions sanitizeHeader", - funcName: "sanitizeHeader", + name: "template builtin functions sanitizeSection", + funcName: "sanitizeSection", funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\n|-----|-----|\n| foo | bar |\""}, escape: true, expected: "Example of 'foo\\_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\n|-----|-----|\n| foo | bar |", }, { - name: "template builtin functions sanitizeHeader", - funcName: "sanitizeHeader", + name: "template builtin functions sanitizeSection", + funcName: "sanitizeSection", funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\""}, escape: false, expected: "Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |", }, { - name: "template builtin functions sanitizeHeader", - funcName: "sanitizeHeader", + name: "template builtin functions sanitizeSection", + funcName: "sanitizeSection", funcArgs: []string{`""`}, escape: true, expected: "n/a", diff --git a/internal/template/testdata/header/codeblock.expected b/internal/template/testdata/section/codeblock.expected similarity index 100% rename from internal/template/testdata/header/codeblock.expected rename to internal/template/testdata/section/codeblock.expected diff --git a/internal/template/testdata/header/codeblock.golden b/internal/template/testdata/section/codeblock.golden similarity index 100% rename from internal/template/testdata/header/codeblock.golden rename to internal/template/testdata/section/codeblock.golden diff --git a/internal/template/testdata/header/complex.expected b/internal/template/testdata/section/complex.expected similarity index 100% rename from internal/template/testdata/header/complex.expected rename to internal/template/testdata/section/complex.expected diff --git a/internal/template/testdata/header/complex.golden b/internal/template/testdata/section/complex.golden similarity index 100% rename from internal/template/testdata/header/complex.golden rename to internal/template/testdata/section/complex.golden diff --git a/internal/template/testdata/header/empty.expected b/internal/template/testdata/section/empty.expected similarity index 100% rename from internal/template/testdata/header/empty.expected rename to internal/template/testdata/section/empty.expected diff --git a/internal/template/testdata/header/empty.golden b/internal/template/testdata/section/empty.golden similarity index 100% rename from internal/template/testdata/header/empty.golden rename to internal/template/testdata/section/empty.golden diff --git a/internal/terraform/module.go b/internal/terraform/module.go index 61a36a3..68e023f 100644 --- a/internal/terraform/module.go +++ b/internal/terraform/module.go @@ -13,6 +13,7 @@ package terraform import ( "encoding/json" "encoding/xml" + "errors" "fmt" "io/ioutil" "os" @@ -30,7 +31,8 @@ import ( // Module represents a Terraform module. It consists of // -// - Header ('header' json key): Module header found in shape of multi line comments at the beginning of 'main.tf' +// - Header ('header' json key): Module header found in shape of multi line '*.tf' comments or an entire file +// - Footer ('footer' json key): Module footer found in shape of multi line '*.tf' comments or an entire file // - Inputs ('inputs' json key): List of input 'variables' extracted from the Terraform module .tf files // - ModuleCalls ('modules' json key): List of 'modules' extracted from the Terraform module .tf files // - Outputs ('outputs' json key): List of 'outputs' extracted from Terraform module .tf files @@ -41,6 +43,7 @@ type Module struct { XMLName xml.Name `json:"-" toml:"-" xml:"module" yaml:"-"` Header string `json:"header" toml:"header" xml:"header" yaml:"header"` + Footer string `json:"footer" toml:"footer" xml:"footer" yaml:"footer"` Inputs []*Input `json:"inputs" toml:"inputs" xml:"inputs>input" yaml:"inputs"` ModuleCalls []*ModuleCall `json:"modules" toml:"modules" xml:"modules>module" yaml:"modules"` Outputs []*Output `json:"outputs" toml:"outputs" xml:"outputs>output" yaml:"outputs"` @@ -57,6 +60,11 @@ func (m *Module) HasHeader() bool { return len(m.Header) > 0 } +// HasFooter indicates if the module has footer. +func (m *Module) HasFooter() bool { + return len(m.Footer) > 0 +} + // HasInputs indicates if the module has inputs. func (m *Module) HasInputs() bool { return len(m.Inputs) > 0 @@ -91,6 +99,7 @@ func (m *Module) HasResources() bool { func (m *Module) Convert() terraformsdk.Module { return terraformsdk.NewModule( terraformsdk.WithHeader(m.Header), + terraformsdk.WithFooter(m.Footer), terraformsdk.WithInputs(inputs(m.Inputs).convert()), terraformsdk.WithModuleCalls(modulecalls(m.ModuleCalls).convert()), terraformsdk.WithOutputs(outputs(m.Outputs).convert()), @@ -131,6 +140,11 @@ func loadModuleItems(tfmodule *tfconfig.Module, options *Options) (*Module, erro return nil, err } + footer, err := loadFooter(options) + if err != nil { + return nil, err + } + inputs, required, optional := loadInputs(tfmodule) modulecalls := loadModulecalls(tfmodule) outputs, err := loadOutputs(tfmodule, options) @@ -143,6 +157,7 @@ func loadModuleItems(tfmodule *tfconfig.Module, options *Options) (*Module, erro return &Module{ Header: header, + Footer: footer, Inputs: inputs, ModuleCalls: modulecalls, Outputs: outputs, @@ -165,32 +180,49 @@ func getFileFormat(filename string) string { } return filename[last:] } -func isFileFormatSupported(filename string) (bool, error) { +func isFileFormatSupported(filename string, section string) (bool, error) { + if section == "" { + return false, errors.New("section is missing") + } if filename == "" { - return false, fmt.Errorf("--header-from value is missing") + return false, fmt.Errorf("--%s-from value is missing", section) } switch getFileFormat(filename) { case ".adoc", ".md", ".tf", ".txt": return true, nil } - return false, fmt.Errorf("only .adoc, .md, .tf and .txt formats are supported to read header from") + return false, fmt.Errorf("only .adoc, .md, .tf and .txt formats are supported to read %s from", section) } func loadHeader(options *Options) (string, error) { if !options.ShowHeader { return "", nil } - if ok, err := isFileFormatSupported(options.HeaderFromFile); !ok { + return loadSection(options, options.HeaderFromFile, "header") +} + +func loadFooter(options *Options) (string, error) { + if !options.ShowFooter { + return "", nil + } + return loadSection(options, options.FooterFromFile, "footer") +} + +func loadSection(options *Options, file string, section string) (string, error) { + if section == "" { + return "", errors.New("section is missing") + } + filename := filepath.Join(options.Path, file) + if ok, err := isFileFormatSupported(file, section); !ok { return "", err } - filename := filepath.Join(options.Path, options.HeaderFromFile) if info, err := os.Stat(filename); os.IsNotExist(err) || info.IsDir() { - if options.HeaderFromFile != "main.tf" { - return "", err // user explicitly asked for a file which doesn't exist + if section == "header" && file == "main.tf" { + return "", nil // absorb the error to not break workflow for default value of header and missing 'main.tf' } - return "", nil // absorb the error to not break workflow of users who don't have 'main.tf at all + return "", err // user explicitly asked for a file which doesn't exist } - if getFileFormat(options.HeaderFromFile) != ".tf" { + if getFileFormat(file) != ".tf" { content, err := ioutil.ReadFile(filename) if err != nil { return "", err @@ -218,11 +250,11 @@ func loadHeader(options *Options) (string, error) { return line, true }, } - header, err := lines.Extract() + sectionText, err := lines.Extract() if err != nil { return "", err } - return strings.Join(header, "\n"), nil + return strings.Join(sectionText, "\n"), nil } func loadInputs(tfmodule *tfconfig.Module) ([]*Input, []*Input, []*Input) { diff --git a/internal/terraform/module_test.go b/internal/terraform/module_test.go index f26ea70..49aefc9 100644 --- a/internal/terraform/module_test.go +++ b/internal/terraform/module_test.go @@ -11,6 +11,7 @@ the root directory of this source tree. package terraform import ( + "io/ioutil" "path/filepath" "testing" @@ -27,11 +28,23 @@ func TestLoadModuleWithOptions(t *testing.T) { assert.Nil(err) assert.Equal(true, module.HasHeader()) + assert.Equal(false, module.HasFooter()) assert.Equal(true, module.HasInputs()) assert.Equal(true, module.HasOutputs()) assert.Equal(true, module.HasModuleCalls()) assert.Equal(true, module.HasProviders()) assert.Equal(true, module.HasRequirements()) + + options, _ = options.With(&Options{ + FooterFromFile: "doc.tf", + ShowFooter: true, + }) + // options.With and .WithOverwrite will not overwrite true with false + options.ShowHeader = false + module, err = LoadWithOptions(options) + assert.Nil(err) + assert.Equal(true, module.HasFooter()) + assert.Equal(false, module.HasHeader()) } func TestLoadModule(t *testing.T) { @@ -117,6 +130,7 @@ func TestIsFileFormatSupported(t *testing.T) { expected bool wantErr bool errText string + section string }{ { name: "is file format supported", @@ -124,6 +138,7 @@ func TestIsFileFormatSupported(t *testing.T) { expected: true, wantErr: false, errText: "", + section: "header", }, { name: "is file format supported", @@ -131,6 +146,7 @@ func TestIsFileFormatSupported(t *testing.T) { expected: true, wantErr: false, errText: "", + section: "header", }, { name: "is file format supported", @@ -138,6 +154,7 @@ func TestIsFileFormatSupported(t *testing.T) { expected: true, wantErr: false, errText: "", + section: "header", }, { name: "is file format supported", @@ -145,6 +162,7 @@ func TestIsFileFormatSupported(t *testing.T) { expected: true, wantErr: false, errText: "", + section: "header", }, { name: "is file format supported", @@ -152,6 +170,7 @@ func TestIsFileFormatSupported(t *testing.T) { expected: false, wantErr: true, errText: "only .adoc, .md, .tf and .txt formats are supported to read header from", + section: "header", }, { name: "is file format supported", @@ -159,12 +178,28 @@ func TestIsFileFormatSupported(t *testing.T) { expected: false, wantErr: true, errText: "--header-from value is missing", + section: "header", + }, { + name: "err message changes for footer", + filename: "main.doc", + expected: false, + wantErr: true, + errText: "only .adoc, .md, .tf and .txt formats are supported to read footer from", + section: "footer", + }, + { + name: "err message changes for footer", + filename: "", + expected: false, + wantErr: true, + errText: "--footer-from value is missing", + section: "footer", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert := assert.New(t) - actual, err := isFileFormatSupported(tt.filename) + actual, err := isFileFormatSupported(tt.filename, tt.section) if tt.wantErr { assert.NotNil(err) assert.Equal(tt.errText, err.Error()) @@ -178,107 +213,227 @@ func TestIsFileFormatSupported(t *testing.T) { func TestLoadHeader(t *testing.T) { tests := []struct { - name string - path string - header string - expected string - wantErr bool - errText string + name string + testData string + showHeader bool + expectedData func() (string, error) }{ { - name: "load module header from path", - path: "full-example", - header: "main.tf", - expected: "Example of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)", - wantErr: false, - errText: "", + name: "loadHeader should return a string from file", + testData: "full-example", + showHeader: true, + expectedData: func() (string, error) { + path := filepath.Join("testdata", "expected", "full-example-mainTf-Header.golden") + data, err := ioutil.ReadFile(path) + return string(data), err + }, }, { - name: "load module header from path", - path: "full-example", - header: "doc.tf", - expected: "Custom Header:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2", - wantErr: false, - errText: "", - }, - { - name: "load module header from path", - path: "full-example", - header: "doc.md", - expected: "# Custom Header\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n", - wantErr: false, - errText: "", - }, - { - name: "load module header from path", - path: "full-example", - header: "doc.adoc", - expected: "= Custom Header\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n", - wantErr: false, - errText: "", - }, - { - name: "load module header from path", - path: "full-example", - header: "doc.txt", - expected: "# Custom Header\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n", - wantErr: false, - errText: "", - }, - { - name: "load module header from path", - path: "no-inputs", - header: "main.tf", - expected: "", - wantErr: false, - errText: "", - }, - { - name: "load module header from path", - path: "full-example", - header: "non-existent.tf", - expected: "", - wantErr: true, - errText: "stat testdata/full-example/non-existent.tf: no such file or directory", - }, - { - name: "load module header from path", - path: "full-example", - header: "wrong-formate.docx", - expected: "", - wantErr: true, - errText: "only .adoc, .md, .tf and .txt formats are supported to read header from", - }, - { - name: "load module header from path", - path: "full-example", - header: "", - expected: "", - wantErr: true, - errText: "--header-from value is missing", - }, - { - name: "load module header from path", - path: "empty-header", - header: "", - expected: "", - wantErr: true, - errText: "--header-from value is missing", - }, - { - name: "load module header from path", - path: "non-exist", - header: "", - expected: "", - wantErr: true, - errText: "--header-from value is missing", + name: "loadHeader should return an empty string if not shown", + testData: "", + showHeader: false, + expectedData: func() (string, error) { + return "", nil + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert := assert.New(t) - options := &Options{Path: filepath.Join("testdata", tt.path), HeaderFromFile: tt.header, ShowHeader: true} - actual, err := loadHeader(options) + options, err := NewOptions().With(&Options{ + Path: filepath.Join("testdata", tt.testData), + ShowHeader: tt.showHeader, + }) + assert.Nil(err) + expected, err := tt.expectedData() + assert.Nil(err) + header, err := loadHeader(options) + assert.Nil(err) + assert.Equal(expected, header) + }) + } +} + +func TestLoadFooter(t *testing.T) { + tests := []struct { + name string + testData string + footerFile string + showFooter bool + expectedData func() (string, error) + }{ + { + name: "loadFooter should return a string from file", + testData: "full-example", + footerFile: "main.tf", + showFooter: true, + expectedData: func() (string, error) { + path := filepath.Join("testdata", "expected", "full-example-mainTf-Header.golden") + data, err := ioutil.ReadFile(path) + return string(data), err + }, + }, + { + name: "loadHeader should return an empty string if not shown", + testData: "", + footerFile: "", + showFooter: false, + expectedData: func() (string, error) { + return "", nil + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + options, err := NewOptions().With(&Options{ + Path: filepath.Join("testdata", tt.testData), + FooterFromFile: tt.footerFile, + ShowFooter: tt.showFooter, + }) + assert.Nil(err) + expected, err := tt.expectedData() + assert.Nil(err) + header, err := loadFooter(options) + assert.Nil(err) + assert.Equal(expected, header) + }) + } +} + +func TestLoadSections(t *testing.T) { + tests := []struct { + name string + path string + file string + expected string + wantErr bool + errText string + section string + }{ + { + name: "load module header from path", + path: "full-example", + file: "main.tf", + expected: "Example of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n\nEven inline **formatting** in _here_ is possible.\nand some [link](https://domain.com/)", + wantErr: false, + errText: "", + section: "header", + }, + { + name: "load module header from path", + path: "full-example", + file: "doc.tf", + expected: "Custom Header:\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2", + wantErr: false, + errText: "", + section: "header", + }, + { + name: "load module header from path", + path: "full-example", + file: "doc.md", + expected: "# Custom Header\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n", + wantErr: false, + errText: "", + section: "header", + }, + { + name: "load module header from path", + path: "full-example", + file: "doc.adoc", + expected: "= Custom Header\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n", + wantErr: false, + errText: "", + section: "header", + }, + { + name: "load module header from path", + path: "full-example", + file: "doc.txt", + expected: "# Custom Header\n\nExample of 'foo_bar' module in `foo_bar.tf`.\n\n- list item 1\n- list item 2\n", + wantErr: false, + errText: "", + section: "header", + }, + { + name: "load module header from path", + path: "no-inputs", + file: "main.tf", + expected: "", + wantErr: false, + errText: "", + section: "header", + }, + { + name: "load module header from path", + path: "full-example", + file: "non-existent.tf", + expected: "", + wantErr: true, + errText: "stat testdata/full-example/non-existent.tf: no such file or directory", + section: "header", + }, + { + name: "no error if header file is missing and is default 'main.tf'", + path: "inputs-lf", + file: "main.tf", + expected: "", + wantErr: false, + errText: "", + section: "header", + }, + { + name: "error if footer file is missing even if 'main.tf'", + path: "inputs-lf", + file: "main.tf", + expected: "", + wantErr: true, + errText: "stat testdata/inputs-lf/main.tf: no such file or directory", + section: "footer", + }, + { + name: "load module header from path", + path: "full-example", + file: "wrong-formate.docx", + expected: "", + wantErr: true, + errText: "only .adoc, .md, .tf and .txt formats are supported to read footer from", + section: "footer", + }, + { + name: "load module header from path", + path: "full-example", + file: "", + expected: "", + wantErr: true, + errText: "--header-from value is missing", + section: "header", + }, + { + name: "load module header from path", + path: "empty-header", + file: "", + expected: "", + wantErr: true, + errText: "--header-from value is missing", + section: "header", + }, + { + name: "load module footer from path", + path: "non-exist", + file: "", + expected: "", + wantErr: true, + errText: "--footer-from value is missing", + section: "footer", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + options := &Options{Path: filepath.Join("testdata", tt.path)} + actual, err := loadSection(options, tt.file, tt.section) if tt.wantErr { assert.NotNil(err) assert.Equal(tt.errText, err.Error()) diff --git a/internal/terraform/options.go b/internal/terraform/options.go index da8b109..40f60b1 100644 --- a/internal/terraform/options.go +++ b/internal/terraform/options.go @@ -29,6 +29,8 @@ type Options struct { Path string ShowHeader bool HeaderFromFile string + ShowFooter bool + FooterFromFile string SortBy *SortBy OutputValues bool OutputValuesPath string @@ -40,6 +42,8 @@ func NewOptions() *Options { Path: "", ShowHeader: true, HeaderFromFile: "main.tf", + ShowFooter: false, + FooterFromFile: "", SortBy: &SortBy{Name: false, Required: false, Type: false}, OutputValues: false, OutputValuesPath: "", diff --git a/internal/terraform/testdata/expected/full-example-mainTf-Header.golden b/internal/terraform/testdata/expected/full-example-mainTf-Header.golden new file mode 100644 index 0000000..b1170ac --- /dev/null +++ b/internal/terraform/testdata/expected/full-example-mainTf-Header.golden @@ -0,0 +1,7 @@ +Example of 'foo_bar' module in `foo_bar.tf`. + +- list item 1 +- list item 2 + +Even inline **formatting** in _here_ is possible. +and some [link](https://domain.com/) \ No newline at end of file diff --git a/internal/testutil/settings.go b/internal/testutil/settings.go index 800a22b..fe30f77 100644 --- a/internal/testutil/settings.go +++ b/internal/testutil/settings.go @@ -19,6 +19,7 @@ import ( // WithSections appends show all sections to provided Settings. func WithSections(override ...print.Settings) print.Settings { base := print.Settings{ + ShowFooter: true, ShowHeader: true, ShowInputs: true, ShowModuleCalls: true, diff --git a/scripts/docs/generate.go b/scripts/docs/generate.go index 41cf70d..a78b601 100644 --- a/scripts/docs/generate.go +++ b/scripts/docs/generate.go @@ -164,20 +164,23 @@ func generateMarkdown(cmd *cobra.Command, weight int, w io.Writer) error { } func example(ref *reference) error { - flag := "" + flag := " --footer-from footer.md" switch ref.Name { case "pretty": - flag = " --no-color" + flag += " --no-color" } ref.Usage = fmt.Sprintf("%s%s ./examples/", ref.Command, flag) settings := print.DefaultSettings() settings.ShowColor = false + settings.ShowFooter = true options := &terraform.Options{ Path: "./examples", ShowHeader: true, HeaderFromFile: "main.tf", + ShowFooter: true, + FooterFromFile: "footer.md", SortBy: &terraform.SortBy{ Name: true, },