diff --git a/.golangci.yml b/.golangci.yml index 688c83ce..b9c90afe 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -60,6 +60,8 @@ linters-settings: - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + errorlint: + asserts: false lll: line-length: 140 misspell: @@ -82,6 +84,7 @@ linters: - dogsled - dupl - errcheck + - errorlint - exportloopref - funlen - gocheckcompilerdirectives diff --git a/pkg/commands/executor.go b/pkg/commands/executor.go index 61e221cb..d241f565 100644 --- a/pkg/commands/executor.go +++ b/pkg/commands/executor.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/sha256" + "errors" "fmt" "io" "os" @@ -78,7 +79,7 @@ func NewExecutor(buildInfo BuildInfo) *Executor { // to setup log level early we need to parse config from command line extra time to // find `-v` option commandLineCfg, err := e.getConfigForCommandLine() - if err != nil && err != pflag.ErrHelp { + if err != nil && !errors.Is(err, pflag.ErrHelp) { e.log.Fatalf("Can't get config for command line: %s", err) } if commandLineCfg != nil { diff --git a/pkg/commands/run.go b/pkg/commands/run.go index c8085714..a082d7ad 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -261,11 +261,11 @@ func (e *Executor) getConfigForCommandLine() (*config.Config, error) { fs.Usage = func() {} // otherwise, help text will be printed twice if err := fs.Parse(os.Args); err != nil { - if err == pflag.ErrHelp { + if errors.Is(err, pflag.ErrHelp) { return nil, err } - return nil, fmt.Errorf("can't parse args: %s", err) + return nil, fmt.Errorf("can't parse args: %w", err) } return &cfg, nil @@ -433,7 +433,7 @@ func (e *Executor) printReports(issues []result.Issue, path, format string) erro if file, ok := w.(io.Closer); shouldClose && ok { _ = file.Close() } - return fmt.Errorf("can't print %d issues: %s", len(issues), err) + return fmt.Errorf("can't print %d issues: %w", len(issues), err) } if file, ok := w.(io.Closer); shouldClose && ok { diff --git a/pkg/config/issues.go b/pkg/config/issues.go index 5968d83d..27dcf810 100644 --- a/pkg/config/issues.go +++ b/pkg/config/issues.go @@ -139,16 +139,16 @@ type BaseRule struct { func (b *BaseRule) Validate(minConditionsCount int) error { if err := validateOptionalRegex(b.Path); err != nil { - return fmt.Errorf("invalid path regex: %v", err) + return fmt.Errorf("invalid path regex: %w", err) } if err := validateOptionalRegex(b.PathExcept); err != nil { - return fmt.Errorf("invalid path-except regex: %v", err) + return fmt.Errorf("invalid path-except regex: %w", err) } if err := validateOptionalRegex(b.Text); err != nil { - return fmt.Errorf("invalid text regex: %v", err) + return fmt.Errorf("invalid text regex: %w", err) } if err := validateOptionalRegex(b.Source); err != nil { - return fmt.Errorf("invalid source regex: %v", err) + return fmt.Errorf("invalid source regex: %w", err) } nonBlank := 0 if len(b.Linters) > 0 { diff --git a/pkg/config/reader.go b/pkg/config/reader.go index de203876..a7a1af39 100644 --- a/pkg/config/reader.go +++ b/pkg/config/reader.go @@ -38,11 +38,11 @@ func (r *FileReader) Read() error { configFile, err := r.parseConfigOption() if err != nil { - if err == errConfigDisabled { + if errors.Is(err, errConfigDisabled) { return nil } - return fmt.Errorf("can't parse --config option: %s", err) + return fmt.Errorf("can't parse --config option: %w", err) } if configFile != "" { @@ -65,7 +65,7 @@ func (r *FileReader) parseConfig() error { return nil } - return fmt.Errorf("can't read viper config: %s", err) + return fmt.Errorf("can't read viper config: %w", err) } usedConfigFile := viper.ConfigFileUsed() @@ -100,11 +100,11 @@ func (r *FileReader) parseConfig() error { // Needed for forbidigo. mapstructure.TextUnmarshallerHookFunc(), ))); err != nil { - return fmt.Errorf("can't unmarshal config by viper: %s", err) + return fmt.Errorf("can't unmarshal config by viper: %w", err) } if err := r.validateConfig(); err != nil { - return fmt.Errorf("can't validate config: %s", err) + return fmt.Errorf("can't validate config: %w", err) } if r.cfg.InternalTest { // just for testing purposes: to detect config file usage @@ -138,7 +138,7 @@ func (r *FileReader) validateConfig() error { } for i, rule := range c.Issues.ExcludeRules { if err := rule.Validate(); err != nil { - return fmt.Errorf("error in exclude rule #%d: %v", i, err) + return fmt.Errorf("error in exclude rule #%d: %w", i, err) } } if len(c.Severity.Rules) > 0 && c.Severity.Default == "" { @@ -146,11 +146,11 @@ func (r *FileReader) validateConfig() error { } for i, rule := range c.Severity.Rules { if err := rule.Validate(); err != nil { - return fmt.Errorf("error in severity rule #%d: %v", i, err) + return fmt.Errorf("error in severity rule #%d: %w", i, err) } } if err := c.LintersSettings.Govet.Validate(); err != nil { - return fmt.Errorf("error in govet config: %v", err) + return fmt.Errorf("error in govet config: %w", err) } return nil } diff --git a/pkg/fsutils/fsutils.go b/pkg/fsutils/fsutils.go index a39c105e..715a3a4a 100644 --- a/pkg/fsutils/fsutils.go +++ b/pkg/fsutils/fsutils.go @@ -34,7 +34,7 @@ func Getwd() (string, error) { evaledWd, err := EvalSymlinks(cachedWd) if err != nil { - cachedWd, cachedWdError = "", fmt.Errorf("can't eval symlinks on wd %s: %s", cachedWd, err) + cachedWd, cachedWdError = "", fmt.Errorf("can't eval symlinks on wd %s: %w", cachedWd, err) return } @@ -70,13 +70,13 @@ func ShortestRelPath(path, wd string) (string, error) { var err error wd, err = Getwd() if err != nil { - return "", fmt.Errorf("can't get working directory: %s", err) + return "", fmt.Errorf("can't get working directory: %w", err) } } evaledPath, err := EvalSymlinks(path) if err != nil { - return "", fmt.Errorf("can't eval symlinks for path %s: %s", path, err) + return "", fmt.Errorf("can't eval symlinks for path %s: %w", path, err) } path = evaledPath @@ -92,7 +92,7 @@ func ShortestRelPath(path, wd string) (string, error) { relPath, err := filepath.Rel(wd, absPath) if err != nil { - return "", fmt.Errorf("can't get relative path for path %s and root %s: %s", + return "", fmt.Errorf("can't get relative path for path %s and root %s: %w", absPath, wd, err) } diff --git a/pkg/golinters/golint.go b/pkg/golinters/golint.go index a6fc73c9..22ca5904 100644 --- a/pkg/golinters/golint.go +++ b/pkg/golinters/golint.go @@ -56,7 +56,7 @@ func runGoLint(pass *analysis.Pass, settings *config.GoLintSettings) ([]goanalys ps, err := l.LintPkg(pass.Files, pass.Fset, pass.Pkg, pass.TypesInfo) if err != nil { - return nil, fmt.Errorf("can't lint %d files: %s", len(pass.Files), err) + return nil, fmt.Errorf("can't lint %d files: %w", len(pass.Files), err) } if len(ps) == 0 { diff --git a/pkg/golinters/lll.go b/pkg/golinters/lll.go index 9ed32012..61498087 100644 --- a/pkg/golinters/lll.go +++ b/pkg/golinters/lll.go @@ -2,6 +2,7 @@ package golinters import ( "bufio" + "errors" "fmt" "go/token" "os" @@ -82,7 +83,7 @@ func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]r f, err := os.Open(filename) if err != nil { - return nil, fmt.Errorf("can't open file %s: %s", filename, err) + return nil, fmt.Errorf("can't open file %s: %w", filename, err) } defer f.Close() @@ -127,7 +128,7 @@ func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]r } if err := scanner.Err(); err != nil { - if err == bufio.ErrTooLong && maxLineLen < bufio.MaxScanTokenSize { + if errors.Is(err, bufio.ErrTooLong) && maxLineLen < bufio.MaxScanTokenSize { // scanner.Scan() might fail if the line is longer than bufio.MaxScanTokenSize // In the case where the specified maxLineLen is smaller than bufio.MaxScanTokenSize // we can return this line as a long line instead of returning an error. @@ -148,7 +149,7 @@ func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]r FromLinter: lllName, }) } else { - return nil, fmt.Errorf("can't scan file %s: %s", filename, err) + return nil, fmt.Errorf("can't scan file %s: %w", filename, err) } } diff --git a/pkg/golinters/misspell.go b/pkg/golinters/misspell.go index 5e408b78..0f69cdb8 100644 --- a/pkg/golinters/misspell.go +++ b/pkg/golinters/misspell.go @@ -108,7 +108,7 @@ func createMisspellReplacer(settings *config.MisspellSettings) (*misspell.Replac func runMisspellOnFile(lintCtx *linter.Context, filename string, replacer *misspell.Replacer, mode string) ([]result.Issue, error) { fileContent, err := lintCtx.FileCache.GetFileBytes(filename) if err != nil { - return nil, fmt.Errorf("can't get file %s contents: %s", filename, err) + return nil, fmt.Errorf("can't get file %s contents: %w", filename, err) } // `r.ReplaceGo` doesn't find issues inside strings: it searches only inside comments. diff --git a/pkg/golinters/nolintlint.go b/pkg/golinters/nolintlint.go index 00ef1f83..ae372ab7 100644 --- a/pkg/golinters/nolintlint.go +++ b/pkg/golinters/nolintlint.go @@ -76,7 +76,7 @@ func runNoLintLint(pass *analysis.Pass, settings *config.NoLintLintSettings) ([] lintIssues, err := lnt.Run(pass.Fset, nodes...) if err != nil { - return nil, fmt.Errorf("linter failed to run: %s", err) + return nil, fmt.Errorf("linter failed to run: %w", err) } var issues []goanalysis.Issue diff --git a/pkg/lint/lintersdb/custom_linters.go b/pkg/lint/lintersdb/custom_linters.go index b6ce32a6..c4378d0a 100644 --- a/pkg/lint/lintersdb/custom_linters.go +++ b/pkg/lint/lintersdb/custom_linters.go @@ -71,7 +71,7 @@ func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Anal configFilePath := viper.ConfigFileUsed() absConfigFilePath, err := filepath.Abs(configFilePath) if err != nil { - return nil, fmt.Errorf("could not get absolute representation of config file path %q: %v", configFilePath, err) + return nil, fmt.Errorf("could not get absolute representation of config file path %q: %w", configFilePath, err) } path = filepath.Join(filepath.Dir(absConfigFilePath), path) } diff --git a/pkg/packages/errors.go b/pkg/packages/errors.go index 48983671..ff37651a 100644 --- a/pkg/packages/errors.go +++ b/pkg/packages/errors.go @@ -18,7 +18,7 @@ func ParseErrorPosition(pos string) (*token.Position, error) { file := parts[0] line, err := strconv.Atoi(parts[1]) if err != nil { - return nil, fmt.Errorf("can't parse line number %q: %s", parts[1], err) + return nil, fmt.Errorf("can't parse line number %q: %w", parts[1], err) } var column int diff --git a/pkg/result/processors/diff.go b/pkg/result/processors/diff.go index 67104bab..496d9c86 100644 --- a/pkg/result/processors/diff.go +++ b/pkg/result/processors/diff.go @@ -47,7 +47,7 @@ func (p Diff) Process(issues []result.Issue) ([]result.Issue, error) { if p.patchFilePath != "" { patch, err := os.ReadFile(p.patchFilePath) if err != nil { - return nil, fmt.Errorf("can't read from patch file %s: %s", p.patchFilePath, err) + return nil, fmt.Errorf("can't read from patch file %s: %w", p.patchFilePath, err) } patchReader = bytes.NewReader(patch) } else if p.patch != "" { @@ -60,7 +60,7 @@ func (p Diff) Process(issues []result.Issue) ([]result.Issue, error) { WholeFiles: p.wholeFiles, } if err := c.Prepare(); err != nil { - return nil, fmt.Errorf("can't prepare diff by revgrep: %s", err) + return nil, fmt.Errorf("can't prepare diff by revgrep: %w", err) } return transformIssues(issues, func(i *result.Issue) *result.Issue { diff --git a/pkg/result/processors/skip_files.go b/pkg/result/processors/skip_files.go index 9579bee8..6c1c5869 100644 --- a/pkg/result/processors/skip_files.go +++ b/pkg/result/processors/skip_files.go @@ -21,7 +21,7 @@ func NewSkipFiles(patterns []string, pathPrefix string) (*SkipFiles, error) { p = fsutils.NormalizePathInRegex(p) patternRe, err := regexp.Compile(p) if err != nil { - return nil, fmt.Errorf("can't compile regexp %q: %s", p, err) + return nil, fmt.Errorf("can't compile regexp %q: %w", p, err) } patternsRe = append(patternsRe, patternRe) }