From 9464bf52c695e753eacb32257b99218e8b35378c Mon Sep 17 00:00:00 2001 From: Simon Sawert Date: Mon, 10 Jan 2022 18:14:47 +0100 Subject: [PATCH 1/3] Return error if any linter fails to run If a linter fails to run, store its name and use that to create a list of all linters that failed to run. This will make `golangci-lint` exit with a non-zero exit code if one or more linters fails but still ensure all linters are run before exiting. --- pkg/lint/runner.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/lint/runner.go b/pkg/lint/runner.go index 3a0ed5f4c321..1059d21405ee 100644 --- a/pkg/lint/runner.go +++ b/pkg/lint/runner.go @@ -192,20 +192,34 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint sw := timeutils.NewStopwatch("linters", r.Log) defer sw.Print() - var issues []result.Issue + var ( + linterErr error + failedLinters []string + issues []result.Issue + ) + for _, lc := range linters { lc := lc sw.TrackStage(lc.Name(), func() { linterIssues, err := r.runLinterSafe(ctx, lintCtx, lc) if err != nil { + failedLinters = append(failedLinters, lc.Linter.Name()) r.Log.Warnf("Can't run linter %s: %v", lc.Linter.Name(), err) + return } issues = append(issues, linterIssues...) }) } - return r.processLintResults(issues), nil + if len(failedLinters) > 0 { + linterErr = fmt.Errorf( + "one or more linters failed to run: %s", + strings.Join(failedLinters, ", "), + ) + } + + return r.processLintResults(issues), linterErr } func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, statPerProcessor map[string]processorStat) []result.Issue { From 610f49ecac4aea010ee5bc20d1e6ceb3d478621b Mon Sep 17 00:00:00 2001 From: Simon Sawert Date: Mon, 10 Jan 2022 18:57:37 +0100 Subject: [PATCH 2/3] Use string concatenation to construct error --- pkg/lint/runner.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/lint/runner.go b/pkg/lint/runner.go index 1059d21405ee..6e466411eadd 100644 --- a/pkg/lint/runner.go +++ b/pkg/lint/runner.go @@ -213,10 +213,7 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint } if len(failedLinters) > 0 { - linterErr = fmt.Errorf( - "one or more linters failed to run: %s", - strings.Join(failedLinters, ", "), - ) + linterErr = errors.New("one or more linters failed to run: " + strings.Join(failedLinters, ", ")) } return r.processLintResults(issues), linterErr From 84d3c8fa858a9a26cfc2bab47541c363d3e67fdf Mon Sep 17 00:00:00 2001 From: Simon Sawert Date: Fri, 14 Jan 2022 17:18:25 +0100 Subject: [PATCH 3/3] Use multierror instead of list of strings --- pkg/lint/runner.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pkg/lint/runner.go b/pkg/lint/runner.go index 6e466411eadd..e1a77c7d6885 100644 --- a/pkg/lint/runner.go +++ b/pkg/lint/runner.go @@ -6,6 +6,7 @@ import ( "runtime/debug" "strings" + "github.com/hashicorp/go-multierror" "github.com/pkg/errors" gopackages "golang.org/x/tools/go/packages" @@ -193,9 +194,8 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint defer sw.Print() var ( - linterErr error - failedLinters []string - issues []result.Issue + lintErrors *multierror.Error + issues []result.Issue ) for _, lc := range linters { @@ -203,7 +203,7 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint sw.TrackStage(lc.Name(), func() { linterIssues, err := r.runLinterSafe(ctx, lintCtx, lc) if err != nil { - failedLinters = append(failedLinters, lc.Linter.Name()) + lintErrors = multierror.Append(lintErrors, fmt.Errorf("can't run linter %s: %w", lc.Linter.Name(), err)) r.Log.Warnf("Can't run linter %s: %v", lc.Linter.Name(), err) return @@ -212,11 +212,7 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint }) } - if len(failedLinters) > 0 { - linterErr = errors.New("one or more linters failed to run: " + strings.Join(failedLinters, ", ")) - } - - return r.processLintResults(issues), linterErr + return r.processLintResults(issues), lintErrors.ErrorOrNil() } func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, statPerProcessor map[string]processorStat) []result.Issue {