From 21eaab4fc78b63805924cd678f0af1711148c4fb Mon Sep 17 00:00:00 2001 From: Ricardo Herrera Date: Tue, 30 Mar 2021 15:19:55 -0400 Subject: [PATCH] add output-check option for outputs adding option to compare outputted file with generated terraform-doc and fail if different Signed-off-by: Ricardo Herrera Signed-off-by: Khosrow Moossavi --- cmd/root.go | 1 + docs/reference/asciidoc-document.md | 1 + docs/reference/asciidoc-table.md | 1 + docs/reference/asciidoc.md | 1 + docs/reference/json.md | 1 + docs/reference/markdown-document.md | 1 + docs/reference/markdown-table.md | 1 + docs/reference/markdown.md | 1 + docs/reference/pretty.md | 1 + docs/reference/terraform-docs.md | 1 + docs/reference/tfvars-hcl.md | 1 + docs/reference/tfvars-json.md | 1 + docs/reference/tfvars.md | 1 + docs/reference/toml.md | 1 + docs/reference/xml.md | 1 + docs/reference/yaml.md | 1 + internal/cli/config.go | 2 ++ internal/cli/run.go | 2 ++ internal/cli/writer.go | 21 +++++++++++++++++++++ internal/cli/writer_test.go | 29 +++++++++++++++++++++++++++++ 20 files changed, 70 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index 53b3f84..8c8f03c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -65,6 +65,7 @@ func NewCommand() *cobra.Command { cmd.PersistentFlags().StringVar(&config.Output.File, "output-file", "", "file path to insert output into (default \"\")") cmd.PersistentFlags().StringVar(&config.Output.Mode, "output-mode", "inject", "output to file method ["+cli.OutputModes+"]") cmd.PersistentFlags().StringVar(&config.Output.Template, "output-template", cli.OutputTemplate, "output template") + cmd.PersistentFlags().BoolVar(&config.Output.Check, "output-check", false, "check if content of output file is up to date (default false)") cmd.PersistentFlags().BoolVar(&config.Sort.Enabled, "sort", true, "sort items") cmd.PersistentFlags().StringVar(&config.Sort.By, "sort-by", "name", "sort items by criteria ["+cli.SortTypes+"]") diff --git a/docs/reference/asciidoc-document.md b/docs/reference/asciidoc-document.md index 496fd97..24c2bc0 100644 --- a/docs/reference/asciidoc-document.md +++ b/docs/reference/asciidoc-document.md @@ -32,6 +32,7 @@ terraform-docs asciidoc document [PATH] [flags] --header-from string relative path of a file to read header from (default "main.tf") --hide strings hide section [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] --indent int indention level of AsciiDoc sections [1, 2, 3, 4, 5] (default 2) + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/asciidoc-table.md b/docs/reference/asciidoc-table.md index 2d6bf3c..3565e1e 100644 --- a/docs/reference/asciidoc-table.md +++ b/docs/reference/asciidoc-table.md @@ -32,6 +32,7 @@ terraform-docs asciidoc table [PATH] [flags] --header-from string relative path of a file to read header from (default "main.tf") --hide strings hide section [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] --indent int indention level of AsciiDoc sections [1, 2, 3, 4, 5] (default 2) + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/asciidoc.md b/docs/reference/asciidoc.md index 1a5843b..f8d09ff 100644 --- a/docs/reference/asciidoc.md +++ b/docs/reference/asciidoc.md @@ -35,6 +35,7 @@ terraform-docs asciidoc [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/json.md b/docs/reference/json.md index 46da130..2b36d32 100644 --- a/docs/reference/json.md +++ b/docs/reference/json.md @@ -30,6 +30,7 @@ terraform-docs json [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/markdown-document.md b/docs/reference/markdown-document.md index 6e2448b..61010b1 100644 --- a/docs/reference/markdown-document.md +++ b/docs/reference/markdown-document.md @@ -34,6 +34,7 @@ terraform-docs markdown document [PATH] [flags] --hide strings hide section [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] --html use HTML tags in genereted output (default true) --indent int indention level of Markdown sections [1, 2, 3, 4, 5] (default 2) + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/markdown-table.md b/docs/reference/markdown-table.md index 8b154ec..9cdb613 100644 --- a/docs/reference/markdown-table.md +++ b/docs/reference/markdown-table.md @@ -34,6 +34,7 @@ terraform-docs markdown table [PATH] [flags] --hide strings hide section [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] --html use HTML tags in genereted output (default true) --indent int indention level of Markdown sections [1, 2, 3, 4, 5] (default 2) + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/markdown.md b/docs/reference/markdown.md index ef48ffe..242255f 100644 --- a/docs/reference/markdown.md +++ b/docs/reference/markdown.md @@ -37,6 +37,7 @@ terraform-docs markdown [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/pretty.md b/docs/reference/pretty.md index 922985c..d18a556 100644 --- a/docs/reference/pretty.md +++ b/docs/reference/pretty.md @@ -30,6 +30,7 @@ terraform-docs pretty [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/terraform-docs.md b/docs/reference/terraform-docs.md index f06b228..9aec99b 100644 --- a/docs/reference/terraform-docs.md +++ b/docs/reference/terraform-docs.md @@ -24,6 +24,7 @@ terraform-docs [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/tfvars-hcl.md b/docs/reference/tfvars-hcl.md index e191af0..04ead66 100644 --- a/docs/reference/tfvars-hcl.md +++ b/docs/reference/tfvars-hcl.md @@ -30,6 +30,7 @@ terraform-docs tfvars hcl [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/tfvars-json.md b/docs/reference/tfvars-json.md index f7d2ef5..41477ef 100644 --- a/docs/reference/tfvars-json.md +++ b/docs/reference/tfvars-json.md @@ -29,6 +29,7 @@ terraform-docs tfvars json [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/tfvars.md b/docs/reference/tfvars.md index 6947fca..ba312af 100644 --- a/docs/reference/tfvars.md +++ b/docs/reference/tfvars.md @@ -25,6 +25,7 @@ Generate terraform.tfvars of inputs. --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/toml.md b/docs/reference/toml.md index 2d31326..c4f0edc 100644 --- a/docs/reference/toml.md +++ b/docs/reference/toml.md @@ -29,6 +29,7 @@ terraform-docs toml [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/xml.md b/docs/reference/xml.md index 4580cd4..080a40c 100644 --- a/docs/reference/xml.md +++ b/docs/reference/xml.md @@ -29,6 +29,7 @@ terraform-docs xml [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/docs/reference/yaml.md b/docs/reference/yaml.md index f09e7c7..ea2f395 100644 --- a/docs/reference/yaml.md +++ b/docs/reference/yaml.md @@ -29,6 +29,7 @@ terraform-docs yaml [PATH] [flags] --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 [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources] + --output-check check if content of output file is up to date (default false) --output-file string file path 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") diff --git a/internal/cli/config.go b/internal/cli/config.go index ed3c7e8..1f3cbc7 100644 --- a/internal/cli/config.go +++ b/internal/cli/config.go @@ -203,6 +203,7 @@ type output struct { File string `mapstructure:"file"` Mode string `mapstructure:"mode"` Template string `mapstructure:"template"` + Check bool beginComment string endComment string @@ -213,6 +214,7 @@ func defaultOutput() output { File: "", Mode: outputModeInject, Template: OutputTemplate, + Check: false, beginComment: outputBeginComment, endComment: outputEndComment, diff --git a/internal/cli/run.go b/internal/cli/run.go index bc4e6d7..46d7277 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -229,6 +229,8 @@ func writeContent(config *Config, content string) error { mode: config.Output.Mode, + check: config.Output.Check, + template: config.Output.Template, begin: config.Output.beginComment, end: config.Output.endComment, diff --git a/internal/cli/writer.go b/internal/cli/writer.go index b9c351d..661d710 100644 --- a/internal/cli/writer.go +++ b/internal/cli/writer.go @@ -13,6 +13,7 @@ package cli import ( "bytes" "errors" + "fmt" "io" "os" "path/filepath" @@ -46,6 +47,8 @@ type fileWriter struct { mode string + check bool + template string begin string end string @@ -154,8 +157,26 @@ func (fw *fileWriter) inject(filename string, content string, generated string) // wrtie the content to io.Writer. If no io.Writer is available, // it will be written to 'filename'. func (fw *fileWriter) write(filename string, p []byte) (int, error) { + // if run in check mode return exit 1 + if fw.check { + f, err := os.ReadFile(filename) + if err != nil { + return 0, err + } + + // check for changes and print changed file + if !bytes.Equal(f, p) { + return 0, fmt.Errorf("%s is out of date", filename) + } + + fmt.Printf("%s is up to date\n", filename) + return 0, nil + } + if fw.writer != nil { return fw.writer.Write(p) } + + fmt.Printf("%s updated successfully\n", filename) return len(p), os.WriteFile(filename, p, 0644) } diff --git a/internal/cli/writer_test.go b/internal/cli/writer_test.go index 774e178..6b6aae8 100644 --- a/internal/cli/writer_test.go +++ b/internal/cli/writer_test.go @@ -58,6 +58,7 @@ func TestFileWriter(t *testing.T) { tests := map[string]struct { file string mode string + check bool template string begin string end string @@ -71,6 +72,7 @@ func TestFileWriter(t *testing.T) { "ModeInject": { file: "mode-inject.md", mode: "inject", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -83,6 +85,7 @@ func TestFileWriter(t *testing.T) { "ModeInjectEmptyFile": { file: "empty-file.md", mode: "inject", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -95,6 +98,7 @@ func TestFileWriter(t *testing.T) { "ModeInjectNoCommentAppend": { file: "mode-inject-no-comment.md", mode: "inject", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -107,6 +111,7 @@ func TestFileWriter(t *testing.T) { "ModeInjectFileMissing": { file: "file-missing.md", mode: "inject", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -119,6 +124,7 @@ func TestFileWriter(t *testing.T) { "ModeReplaceWithComment": { file: "mode-replace.md", mode: "replace", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -131,6 +137,7 @@ func TestFileWriter(t *testing.T) { "ModeReplaceWithCommentEmptyFile": { file: "mode-replace.md", mode: "replace", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -143,6 +150,7 @@ func TestFileWriter(t *testing.T) { "ModeReplaceWithCommentFileMissing": { file: "file-missing.md", mode: "replace", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -155,6 +163,7 @@ func TestFileWriter(t *testing.T) { "ModeReplaceWithoutComment": { file: "mode-replace.md", mode: "replace", + check: false, template: outputContent, begin: "", end: "", @@ -167,6 +176,7 @@ func TestFileWriter(t *testing.T) { "ModeReplaceWithoutTemplate": { file: "mode-replace.md", mode: "replace", + check: false, template: "", begin: "", end: "", @@ -181,6 +191,7 @@ func TestFileWriter(t *testing.T) { "EmptyTemplate": { file: "not-applicable.md", mode: "inject", + check: false, template: "", begin: outputBeginComment, end: outputEndComment, @@ -193,6 +204,7 @@ func TestFileWriter(t *testing.T) { "BeginCommentMissing": { file: "begin-comment-missing.md", mode: "inject", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -205,6 +217,7 @@ func TestFileWriter(t *testing.T) { "EndCommentMissing": { file: "end-comment-missing.md", mode: "inject", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -217,6 +230,7 @@ func TestFileWriter(t *testing.T) { "EndCommentBeforeBegin": { file: "end-comment-before-begin.md", mode: "inject", + check: false, template: OutputTemplate, begin: outputBeginComment, end: outputEndComment, @@ -226,6 +240,19 @@ func TestFileWriter(t *testing.T) { wantErr: true, errMsg: "end comment is before begin comment", }, + "ModeReplaceOutOfDate": { + file: "mode-replace.md", + mode: "replace", + check: true, + template: OutputTemplate, + begin: outputBeginComment, + end: outputEndComment, + writer: nil, + + expected: "", + wantErr: true, + errMsg: "testdata/writer/mode-replace.md is out of date", + }, } for name, tt := range tests { t.Run(name, func(t *testing.T) { @@ -237,6 +264,8 @@ func TestFileWriter(t *testing.T) { mode: tt.mode, + check: tt.check, + template: tt.template, begin: tt.begin, end: tt.end,