diff --git a/internal/cli/config.go b/internal/cli/config.go index 9e4c10d..4948643 100644 --- a/internal/cli/config.go +++ b/internal/cli/config.go @@ -68,7 +68,11 @@ func defaultSections() sections { } } -func (s *sections) validate() error { +func (s *sections) validate() error { //nolint:gocyclo + // NOTE(khos2ow): this function is over our cyclomatic complexity goal. + // Be wary when adding branches, and look for functionality that could + // be reasonably moved into an injected dependency. + for _, item := range s.Show { switch item { case allSections[0], allSections[1], allSections[2], allSections[3], allSections[4], allSections[5], allSections[6], allSections[7]: @@ -326,7 +330,11 @@ func (c *Config) process() { } // validate config and check for any misuse or misconfiguration -func (c *Config) validate() error { +func (c *Config) validate() error { //nolint:gocyclo + // NOTE(khos2ow): this function is over our cyclomatic complexity goal. + // Be wary when adding branches, and look for functionality that could + // be reasonably moved into an injected dependency. + // formatter if c.Formatter == "" { return fmt.Errorf("value of 'formatter' can't be empty") diff --git a/internal/cli/reader.go b/internal/cli/reader.go index a639a80..eaef086 100644 --- a/internal/cli/reader.go +++ b/internal/cli/reader.go @@ -35,7 +35,11 @@ func (c *cfgreader) exist() (bool, error) { return true, nil } -func (c *cfgreader) parse() error { +func (c *cfgreader) parse() error { //nolint:gocyclo + // NOTE(khos2ow): this function is over our cyclomatic complexity goal. + // Be wary when adding branches, and look for functionality that could + // be reasonably moved into an injected dependency. + if ok, err := c.exist(); !ok { return err } diff --git a/internal/cli/run.go b/internal/cli/run.go index f9d4180..8dee2c3 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -37,7 +37,7 @@ func PreRunEFunc(config *Config) func(*cobra.Command, []string) error { // root command must have an argument, otherwise we're going to show help if formatter == "root" && len(args) == 0 { - cmd.Help() //nolint:errcheck + cmd.Help() //nolint:errcheck,gosec os.Exit(0) } @@ -63,14 +63,12 @@ func PreRunEFunc(config *Config) func(*cobra.Command, []string) error { } // config is not provided and file not found, only show an error for the root command if formatter == "root" { - cmd.Help() //nolint:errcheck + cmd.Help() //nolint:errcheck,gosec os.Exit(0) } - } else { + } else if err := cfgreader.parse(); err != nil { // config file is found, we're now going to parse it - if err := cfgreader.parse(); err != nil { - return err - } + return err } // explicitly setting formatter to Config for non-root commands this diff --git a/internal/cli/writer.go b/internal/cli/writer.go index 0a70197..4a67d1f 100644 --- a/internal/cli/writer.go +++ b/internal/cli/writer.go @@ -100,7 +100,7 @@ func (fw *fileWriter) Write(p []byte) (int, error) { if after < before { return 0, errors.New(errEndCommentBeforeBegin) } - content = content + fc[after+len(fw.end):] + content += fc[after+len(fw.end):] } n := len(content) diff --git a/internal/format/tfvars_hcl.go b/internal/format/tfvars_hcl.go index 4b1f297..f2eb10f 100644 --- a/internal/format/tfvars_hcl.go +++ b/internal/format/tfvars_hcl.go @@ -79,10 +79,8 @@ func alignments(inputs []*terraform.Input) { padding[i] = l maxlen = 0 index = i + 1 - } else { - if l > maxlen { - maxlen = l - } + } else if l > maxlen { + maxlen = l } } for i := index; i < len(inputs); i++ { diff --git a/internal/plugin/discovery.go b/internal/plugin/discovery.go index 641ce9f..60d0701 100644 --- a/internal/plugin/discovery.go +++ b/internal/plugin/discovery.go @@ -52,12 +52,16 @@ func findPlugins(dir string) (*List, error) { } for _, f := range files { - name := strings.Replace(f.Name(), namePrefix, "", -1) + name := strings.ReplaceAll(f.Name(), namePrefix, "") path, err := getPluginPath(dir, name) if err != nil { return nil, err } + // Accepting variables here is intentional; we need to determine the + // path on the fly per directory. + // + // nolint:gosec cmd := exec.Command(path) client := pluginsdk.NewClient(&pluginsdk.ClientOpts{ diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 936f796..1e7ad6c 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -25,7 +25,7 @@ type List struct { // All returns all registered plugins. func (l *List) All() []*pluginsdk.Client { - all := make([]*pluginsdk.Client, len(l.formatters)-1) + all := make([]*pluginsdk.Client, 0) for _, f := range l.formatters { all = append(all, f) } diff --git a/internal/reader/lines.go b/internal/reader/lines.go index b289fbe..c81502a 100644 --- a/internal/reader/lines.go +++ b/internal/reader/lines.go @@ -41,7 +41,11 @@ func (l *Lines) Extract() ([]string, error) { return l.extract(f) } -func (l *Lines) extract(r io.Reader) ([]string, error) { +func (l *Lines) extract(r io.Reader) ([]string, error) { //nolint:gocyclo + // NOTE(khos2ow): this function is over our cyclomatic complexity goal. + // Be wary when adding branches, and look for functionality that could + // be reasonably moved into an injected dependency. + bf := bufio.NewReader(r) var lines = make([]string, 0) for lnum := 0; ; lnum++ { @@ -49,7 +53,7 @@ func (l *Lines) extract(r io.Reader) ([]string, error) { break } line, err := bf.ReadString('\n') - if err == io.EOF && line == "" { + if errors.Is(err, io.EOF) && line == "" { switch lnum { case 0: return nil, errors.New("no lines in file") @@ -62,6 +66,8 @@ func (l *Lines) extract(r io.Reader) ([]string, error) { return nil, fmt.Errorf("only %d lines", lnum) } } + + //nolint:gocritic if l.Condition(line) { if extracted, capture := l.Parser(line); capture { lines = append(lines, extracted) diff --git a/internal/template/sanitizer.go b/internal/template/sanitizer.go index 30ac136..767a51a 100644 --- a/internal/template/sanitizer.go +++ b/internal/template/sanitizer.go @@ -25,7 +25,7 @@ import ( func sanitizeName(name string, settings *print.Settings) string { if settings.EscapeCharacters { // Escape underscore - name = strings.Replace(name, "_", "\\_", -1) + name = strings.ReplaceAll(name, "_", "\\_") } return name } @@ -106,8 +106,8 @@ func sanitizeMarkdownTable(s string, settings *print.Settings) string { }, func(segment string) string { segment = strings.TrimSpace(segment) - segment = strings.Replace(segment, "\n", "
", -1) - segment = strings.Replace(segment, "\r", "", -1) + segment = strings.ReplaceAll(segment, "\n", "
") + segment = strings.ReplaceAll(segment, "\r", "") segment = fmt.Sprintf("
%s
", segment) return segment }, @@ -145,7 +145,7 @@ func convertMultiLineText(s string, isTable bool, isHeader bool) string { } // Convert double newlines to

. - s = strings.Replace(s, "\n\n", "

", -1) + s = strings.ReplaceAll(s, "\n\n", "

") // Convert line-break on a non-empty line followed by another line // starting with "alphanumeric" word into space-space-newline @@ -154,18 +154,18 @@ func convertMultiLineText(s string, isTable bool, isHeader bool) string { // consecutive lines start with hyphen which is a special character. if !isHeader { s = regexp.MustCompile(`(\S*)(\r?\n)(\s*)(\w+)`).ReplaceAllString(s, "$1 $2$3$4") - s = strings.Replace(s, " \n", " \n", -1) - s = strings.Replace(s, "
\n", "\n\n", -1) + s = strings.ReplaceAll(s, " \n", " \n") + s = strings.ReplaceAll(s, "
\n", "\n\n") } if isTable { // Convert space-space-newline to
- s = strings.Replace(s, " \n", "
", -1) + s = strings.ReplaceAll(s, " \n", "
") // Convert single newline to
. - s = strings.Replace(s, "\n", "
", -1) + s = strings.ReplaceAll(s, "\n", "
") } else { - s = strings.Replace(s, "
", "\n", -1) + s = strings.ReplaceAll(s, "
", "\n") } return s @@ -179,7 +179,7 @@ func escapeIllegalCharacters(s string, settings *print.Settings, escapePipe bool s, "`", func(segment string) string { - return strings.Replace(segment, "|", "\\|", -1) + return strings.ReplaceAll(segment, "|", "\\|") }, func(segment string) string { return fmt.Sprintf("`%s`", segment) @@ -194,7 +194,7 @@ func escapeIllegalCharacters(s string, settings *print.Settings, escapePipe bool func(segment string) string { return executePerLine(segment, func(line string) string { escape := func(char string) { - c := strings.Replace(char, "*", "\\*", -1) + c := strings.ReplaceAll(char, "*", "\\*") cases := []struct { pattern string index []int @@ -208,18 +208,19 @@ func escapeIllegalCharacters(s string, settings *print.Settings, escapePipe bool index: []int{6, 2}, }, } - for _, c := range cases { + for i := range cases { + c := cases[i] r := regexp.MustCompile(c.pattern) m := r.FindAllStringSubmatch(line, -1) i := r.FindAllStringSubmatchIndex(line, -1) for j := range m { for _, k := range c.index { - line = line[:i[j][k*2]] + strings.Replace(m[j][k], char, "‡‡‡DONTESCAPE‡‡‡", -1) + line[i[j][(k*2)+1]:] + line = line[:i[j][k*2]] + strings.ReplaceAll(m[j][k], char, "‡‡‡DONTESCAPE‡‡‡") + line[i[j][(k*2)+1]:] } } } - line = strings.Replace(line, char, "\\"+char, -1) - line = strings.Replace(line, "‡‡‡DONTESCAPE‡‡‡", char, -1) + line = strings.ReplaceAll(line, char, "\\"+char) + line = strings.ReplaceAll(line, "‡‡‡DONTESCAPE‡‡‡", char) } escape("_") // Escape underscore return line @@ -242,8 +243,8 @@ func normalizeURLs(s string, settings *print.Settings) string { if settings.EscapeCharacters { if urls := xurls.Strict().FindAllString(s, -1); len(urls) > 0 { for _, url := range urls { - normalized := strings.Replace(url, "\\", "", -1) - s = strings.Replace(s, url, normalized, -1) + normalized := strings.ReplaceAll(url, "\\", "") + s = strings.ReplaceAll(s, url, normalized) } } } diff --git a/internal/terraform/module.go b/internal/terraform/module.go index 9095046..f434732 100644 --- a/internal/terraform/module.go +++ b/internal/terraform/module.go @@ -210,7 +210,11 @@ func loadFooter(options *Options) (string, error) { return loadSection(options, options.FooterFromFile, "footer") } -func loadSection(options *Options, file string, section string) (string, error) { +func loadSection(options *Options, file string, section string) (string, error) { //nolint:gocyclo + // NOTE(khos2ow): this function is over our cyclomatic complexity goal. + // Be wary when adding branches, and look for functionality that could + // be reasonably moved into an injected dependency. + if section == "" { return "", errors.New("section is missing") } @@ -225,7 +229,7 @@ func loadSection(options *Options, file string, section string) (string, error) return "", err // user explicitly asked for a file which doesn't exist } if getFileFormat(file) != ".tf" { - content, err := ioutil.ReadFile(filename) + content, err := ioutil.ReadFile(filepath.Clean(filename)) if err != nil { return "", err } @@ -266,7 +270,7 @@ func loadInputs(tfmodule *tfconfig.Module) ([]*Input, []*Input, []*Input) { for _, input := range tfmodule.Variables { // convert CRLF to LF early on (https://github.com/terraform-docs/terraform-docs/issues/305) - inputDescription := strings.Replace(input.Description, "\r\n", "\n", -1) + inputDescription := strings.ReplaceAll(input.Description, "\r\n", "\n") if inputDescription == "" { inputDescription = loadComments(input.Pos.Filename, input.Pos.Line) } @@ -355,12 +359,10 @@ func loadOutputValues(options *Options) (map[string]*output, error) { cmd := exec.Command("terraform", "output", "-json") cmd.Dir = options.Path if out, err = cmd.Output(); err != nil { - return nil, fmt.Errorf("caught error while reading the terraform outputs: %v", err) - } - } else { - if out, err = ioutil.ReadFile(options.OutputValuesPath); err != nil { - return nil, fmt.Errorf("caught error while reading the terraform outputs file at %s: %v", options.OutputValuesPath, err) + return nil, fmt.Errorf("caught error while reading the terraform outputs: %w", err) } + } else if out, err = ioutil.ReadFile(options.OutputValuesPath); err != nil { + return nil, fmt.Errorf("caught error while reading the terraform outputs file at %s: %w", options.OutputValuesPath, err) } var terraformOutputs map[string]*output err = json.Unmarshal(out, &terraformOutputs) @@ -514,21 +516,26 @@ func loadComments(filename string, lineNum int) string { return strings.Join(comment, " ") } -func sortItems(tfmodule *Module, sortby *SortBy) { +func sortItems(tfmodule *Module, sortby *SortBy) { //nolint:gocyclo + // NOTE(khos2ow): this function is over our cyclomatic complexity goal. + // Be wary when adding branches, and look for functionality that could + // be reasonably moved into an injected dependency. + // inputs - if sortby.Type { + switch { + case sortby.Type: sort.Sort(inputsSortedByType(tfmodule.Inputs)) sort.Sort(inputsSortedByType(tfmodule.RequiredInputs)) sort.Sort(inputsSortedByType(tfmodule.OptionalInputs)) - } else if sortby.Required { + case sortby.Required: sort.Sort(inputsSortedByRequired(tfmodule.Inputs)) sort.Sort(inputsSortedByRequired(tfmodule.RequiredInputs)) sort.Sort(inputsSortedByRequired(tfmodule.OptionalInputs)) - } else if sortby.Name { + case sortby.Name: sort.Sort(inputsSortedByName(tfmodule.Inputs)) sort.Sort(inputsSortedByName(tfmodule.RequiredInputs)) sort.Sort(inputsSortedByName(tfmodule.OptionalInputs)) - } else { + default: sort.Sort(inputsSortedByPosition(tfmodule.Inputs)) sort.Sort(inputsSortedByPosition(tfmodule.RequiredInputs)) sort.Sort(inputsSortedByPosition(tfmodule.OptionalInputs)) @@ -552,11 +559,12 @@ func sortItems(tfmodule *Module, sortby *SortBy) { sort.Sort(resourcesSortedByType(tfmodule.Resources)) // modules - if sortby.Name || sortby.Required { + switch { + case sortby.Name || sortby.Required: sort.Sort(modulecallsSortedByName(tfmodule.ModuleCalls)) - } else if sortby.Type { + case sortby.Type: sort.Sort(modulecallsSortedBySource(tfmodule.ModuleCalls)) - } else { + default: sort.Sort(modulecallsSortedByPosition(tfmodule.ModuleCalls)) } } diff --git a/internal/terraform/output.go b/internal/terraform/output.go index 3b3e2e3..f8c7f9a 100644 --- a/internal/terraform/output.go +++ b/internal/terraform/output.go @@ -99,11 +99,11 @@ func (o *Output) MarshalXML(e *xml.Encoder, start xml.StartElement) error { if err != nil { return err } - fn(o.Name, "name") //nolint: errcheck - fn(o.Description, "description") //nolint: errcheck + fn(o.Name, "name") //nolint:errcheck,gosec + fn(o.Description, "description") //nolint:errcheck,gosec if o.ShowValue { - fn(o.Value, "value") //nolint: errcheck - fn(o.Sensitive, "sensitive") //nolint: errcheck + fn(o.Value, "value") //nolint:errcheck,gosec + fn(o.Sensitive, "sensitive") //nolint:errcheck,gosec } return e.EncodeToken(start.End()) } diff --git a/internal/testutil/testing.go b/internal/testutil/testing.go index 3cb88ce..416dc33 100644 --- a/internal/testutil/testing.go +++ b/internal/testutil/testing.go @@ -39,7 +39,7 @@ func GetModule(options *terraform.Options) (*terraform.Module, error) { // GetExpected returns 'example' Module and expected Golden file content func GetExpected(format, name string) (string, error) { path := filepath.Join(testDataPath(), format, name+".golden") - bytes, err := ioutil.ReadFile(path) + bytes, err := ioutil.ReadFile(filepath.Clean(path)) if err != nil { return "", err } diff --git a/internal/types/types.go b/internal/types/types.go index 11a3583..b583ef4 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -43,6 +43,10 @@ func ValueOf(v interface{}) Value { return new(Nil) } value := reflect.ValueOf(v) + + // We don't really care about all the other kinds. + // + //nolint:exhaustive switch value.Kind() { case reflect.String: if value.IsZero() { @@ -70,6 +74,9 @@ func TypeOf(t string, v interface{}) String { return String(t) } if v != nil { + // We don't really care about all the other kinds. + // + //nolint:exhaustive switch reflect.ValueOf(v).Kind() { case reflect.String: return String("string") @@ -295,7 +302,7 @@ func (l List) MarshalXML(e *xml.Encoder, start xml.StartElement) error { return err } for _, i := range l { - e.Encode(xmllistentry{XMLName: xml.Name{Local: "item"}, Value: i}) //nolint: errcheck + e.Encode(xmllistentry{XMLName: xml.Name{Local: "item"}, Value: i}) //nolint:errcheck,gosec } return e.EncodeToken(start.End()) } @@ -374,15 +381,18 @@ func (m Map) MarshalXML(e *xml.Encoder, start xml.StartElement) error { } sort.Sort(sortmapkeys(keys)) for _, k := range keys { + // We don't really care about all the other kinds. + // + //nolint:exhaustive switch reflect.TypeOf(m[k]).Kind() { case reflect.Map: is := xml.StartElement{Name: xml.Name{Local: k}} - Map(m[k].(map[string]interface{})).MarshalXML(e, is) //nolint: errcheck + Map(m[k].(map[string]interface{})).MarshalXML(e, is) //nolint:errcheck,gosec case reflect.Slice: is := xml.StartElement{Name: xml.Name{Local: k}} - List(m[k].([]interface{})).MarshalXML(e, is) //nolint: errcheck + List(m[k].([]interface{})).MarshalXML(e, is) //nolint:errcheck,gosec default: - e.Encode(xmlmapentry{XMLName: xml.Name{Local: k}, Value: m[k]}) //nolint: errcheck + e.Encode(xmlmapentry{XMLName: xml.Name{Local: k}, Value: m[k]}) //nolint:errcheck,gosec } } return e.EncodeToken(start.End()) diff --git a/internal/types/types_test.go b/internal/types/types_test.go index 9a44870..d94f06d 100644 --- a/internal/types/types_test.go +++ b/internal/types/types_test.go @@ -45,7 +45,8 @@ type testmap struct { } func testPrimitive(t *testing.T, tests []testprimitive) { - for _, tt := range tests { + for i := range tests { + tt := tests[i] for _, tv := range tt.values { t.Run(tt.name, func(t *testing.T) { assert := assert.New(t) diff --git a/scripts/docs/generate.go b/scripts/docs/generate.go index a78b601..4b174c2 100644 --- a/scripts/docs/generate.go +++ b/scripts/docs/generate.go @@ -74,7 +74,7 @@ func generate(cmd *cobra.Command, weight int, basename string) error { if err != nil { return err } - defer f.Close() //nolint:errcheck + defer f.Close() //nolint:errcheck,gosec if _, err := io.WriteString(f, ""); err != nil { return err @@ -113,7 +113,7 @@ func generateMarkdown(cmd *cobra.Command, weight int, w io.Writer) error { cmd.InitDefaultHelpFlag() command := cmd.CommandPath() - name := strings.Replace(command, "terraform-docs ", "", -1) + name := strings.ReplaceAll(command, "terraform-docs ", "") short := cmd.Short long := cmd.Long @@ -152,7 +152,7 @@ func generateMarkdown(cmd *cobra.Command, weight int, w io.Writer) error { if ref.HasChildren { subcommands(ref, cmd.Commands()) } else { - example(ref) //nolint:errcheck + example(ref) //nolint:errcheck,gosec } file := "format.tmpl" @@ -165,8 +165,7 @@ func generateMarkdown(cmd *cobra.Command, weight int, w io.Writer) error { func example(ref *reference) error { flag := " --footer-from footer.md" - switch ref.Name { - case "pretty": + if ref.Name == "pretty" { flag += " --no-color" } @@ -238,7 +237,7 @@ func subcommands(ref *reference, children []*cobra.Command) { } func extractFilename(s string) string { - s = strings.Replace(s, " ", "-", -1) - s = strings.Replace(s, "terraform-docs-", "", -1) + s = strings.ReplaceAll(s, " ", "-") + s = strings.ReplaceAll(s, "terraform-docs-", "") return s }