From 4f6992da8da0741022deaafdac3e44b880419a1f Mon Sep 17 00:00:00 2001 From: Joe Wilner Date: Thu, 9 Jul 2020 22:16:28 -0400 Subject: [PATCH 1/5] Configure path prefix via processor abstraction --- .golangci.example.yml | 3 +++ pkg/commands/run.go | 1 + pkg/config/config.go | 9 ++++--- pkg/lint/runner.go | 1 + pkg/result/processors/path_prefixer.go | 37 ++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 pkg/result/processors/path_prefixer.go diff --git a/.golangci.example.yml b/.golangci.example.yml index 28e2715d897f..be5b865cf21e 100644 --- a/.golangci.example.yml +++ b/.golangci.example.yml @@ -72,6 +72,9 @@ output: # make issues output unique by line, default is true uniq-by-line: true + # add a prefix to the output file references; default is no prefix + path-prefix: "" + # all available settings of specific linters linters-settings: diff --git a/pkg/commands/run.go b/pkg/commands/run.go index e4887d587a50..31f52fa78c36 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -81,6 +81,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, is fs.BoolVar(&oc.PrintLinterName, "print-linter-name", true, wh("Print linter name in issue line")) fs.BoolVar(&oc.UniqByLine, "uniq-by-line", true, wh("Make issues output unique by line")) fs.BoolVar(&oc.PrintWelcomeMessage, "print-welcome", false, wh("Print welcome message")) + fs.StringVar(&oc.PathPrefix, "path-prefix", "", wh("Path prefix to add to output")) hideFlag("print-welcome") // no longer used // Run config diff --git a/pkg/config/config.go b/pkg/config/config.go index 3afd40406b08..5717bb669d3f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -516,10 +516,11 @@ type Config struct { Output struct { Format string Color string - PrintIssuedLine bool `mapstructure:"print-issued-lines"` - PrintLinterName bool `mapstructure:"print-linter-name"` - UniqByLine bool `mapstructure:"uniq-by-line"` - PrintWelcomeMessage bool `mapstructure:"print-welcome"` + PrintIssuedLine bool `mapstructure:"print-issued-lines"` + PrintLinterName bool `mapstructure:"print-linter-name"` + UniqByLine bool `mapstructure:"uniq-by-line"` + PrintWelcomeMessage bool `mapstructure:"print-welcome"` + PathPrefix string `mapstructure:"path-prefix"` } LintersSettings LintersSettings `mapstructure:"linters-settings"` diff --git a/pkg/lint/runner.go b/pkg/lint/runner.go index f77778b286f9..14baecc06c01 100644 --- a/pkg/lint/runner.go +++ b/pkg/lint/runner.go @@ -79,6 +79,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint processors.NewSourceCode(lineCache, log.Child("source_code")), processors.NewPathShortener(), getSeverityRulesProcessor(&cfg.Severity, log, lineCache), + processors.NewPathPrefixer(cfg.Output.PathPrefix), }, Log: log, }, nil diff --git a/pkg/result/processors/path_prefixer.go b/pkg/result/processors/path_prefixer.go new file mode 100644 index 000000000000..5ce940b39bf0 --- /dev/null +++ b/pkg/result/processors/path_prefixer.go @@ -0,0 +1,37 @@ +package processors + +import ( + "path" + + "github.com/golangci/golangci-lint/pkg/result" +) + +// PathPrefixer adds a customizable prefix to every output path +type PathPrefixer struct { + prefix string +} + +var _ Processor = new(PathPrefixer) + +// NewPathPrefixer returns a new path prefixer for the provided string +func NewPathPrefixer(prefix string) *PathPrefixer { + return &PathPrefixer{prefix: prefix} +} + +// Name returns the name of this processor +func (*PathPrefixer) Name() string { + return "path_prefixer" +} + +// Process adds the prefix to each path +func (p *PathPrefixer) Process(issues []result.Issue) ([]result.Issue, error) { + if p.prefix != "" { + for i := range issues { + issues[i].Pos.Filename = path.Join(p.prefix, issues[i].Pos.Filename) + } + } + return issues, nil +} + +// Finish is implemented to satisfy the Processor interface +func (*PathPrefixer) Finish() {} From b68ee0d7168c84bb6e25935d9bf06c3ae1541d5b Mon Sep 17 00:00:00 2001 From: Joe Wilner Date: Thu, 9 Jul 2020 23:51:41 -0400 Subject: [PATCH 2/5] Adds a simple unit --- pkg/result/processors/path_prefixer_test.go | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 pkg/result/processors/path_prefixer_test.go diff --git a/pkg/result/processors/path_prefixer_test.go b/pkg/result/processors/path_prefixer_test.go new file mode 100644 index 000000000000..55fdbea9264c --- /dev/null +++ b/pkg/result/processors/path_prefixer_test.go @@ -0,0 +1,37 @@ +package processors + +import ( + "go/token" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/golangci/golangci-lint/pkg/result" +) + +func TestPathPrefixer_Process(t *testing.T) { + paths := func(ps ...string) (issues []result.Issue) { + for _, p := range ps { + issues = append(issues, result.Issue{Pos: token.Position{Filename: p}}) + } + return + } + for _, tt := range []struct { + name, prefix string + issues, want []result.Issue + }{ + {"empty prefix", "", paths("some/path", "cool"), paths("some/path", "cool")}, + {"prefix", "ok", paths("some/path", "cool"), paths("ok/some/path", "ok/cool")}, + {"prefix slashed", "ok/", paths("some/path", "cool"), paths("ok/some/path", "ok/cool")}, + } { + t.Run(tt.name, func(t *testing.T) { + r := require.New(t) + + p := NewPathPrefixer(tt.prefix) + got, err := p.Process(tt.issues) + r.NoError(err, "prefixer should never error") + + r.Equal(got, tt.want) + }) + } +} From 0ed243c5cd9d317587a1585b260c7d06eeb0a053 Mon Sep 17 00:00:00 2001 From: Joe Wilner Date: Fri, 10 Jul 2020 00:12:36 -0400 Subject: [PATCH 3/5] Skip incorrect lint messages --- pkg/result/processors/path_prefixer_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/result/processors/path_prefixer_test.go b/pkg/result/processors/path_prefixer_test.go index 55fdbea9264c..efe558b3afd1 100644 --- a/pkg/result/processors/path_prefixer_test.go +++ b/pkg/result/processors/path_prefixer_test.go @@ -27,11 +27,11 @@ func TestPathPrefixer_Process(t *testing.T) { t.Run(tt.name, func(t *testing.T) { r := require.New(t) - p := NewPathPrefixer(tt.prefix) - got, err := p.Process(tt.issues) + p := NewPathPrefixer(tt.prefix) //nolint:scopelint + got, err := p.Process(tt.issues) //nolint:scopelint r.NoError(err, "prefixer should never error") - r.Equal(got, tt.want) + r.Equal(got, tt.want) //nolint:scopelint }) } } From c0121d51bfcb007eae86fac87fba5ea3b6bf2f26 Mon Sep 17 00:00:00 2001 From: Joe Wilner Date: Fri, 10 Jul 2020 00:16:40 -0400 Subject: [PATCH 4/5] No more editing in github browser --- pkg/result/processors/path_prefixer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/result/processors/path_prefixer_test.go b/pkg/result/processors/path_prefixer_test.go index efe558b3afd1..e4b4c86e30af 100644 --- a/pkg/result/processors/path_prefixer_test.go +++ b/pkg/result/processors/path_prefixer_test.go @@ -27,7 +27,7 @@ func TestPathPrefixer_Process(t *testing.T) { t.Run(tt.name, func(t *testing.T) { r := require.New(t) - p := NewPathPrefixer(tt.prefix) //nolint:scopelint + p := NewPathPrefixer(tt.prefix) //nolint:scopelint got, err := p.Process(tt.issues) //nolint:scopelint r.NoError(err, "prefixer should never error") From 2dca06e1b67b2eb73861794b177f17eb1e415b45 Mon Sep 17 00:00:00 2001 From: Joe Wilner Date: Fri, 10 Jul 2020 09:18:51 -0400 Subject: [PATCH 5/5] run_test additions --- test/run_test.go | 19 +++++++++++++++++++ test/testshared/testshared.go | 6 ++++++ 2 files changed, 25 insertions(+) diff --git a/test/run_test.go b/test/run_test.go index e20b54fa1aca..878a273bca1b 100644 --- a/test/run_test.go +++ b/test/run_test.go @@ -292,3 +292,22 @@ func TestDisallowedOptionsInConfig(t *testing.T) { r.RunWithYamlConfig(c.cfg, withCommonRunArgs(args...)...).ExpectExitCode(exitcodes.Failure) } } + +func TestPathPrefix(t *testing.T) { + for _, tt := range []struct { + Name string + Args []string + Pattern string + }{ + {"empty", nil, "^testdata/withTests/"}, + {"prefixed", []string{"--path-prefix=cool"}, "^cool/testdata/withTests"}, + } { + t.Run(tt.Name, func(t *testing.T) { + testshared.NewLintRunner(t).Run( + append(tt.Args, getTestDataDir("withTests"))..., //nolint:scopelint + ).ExpectOutputRegexp( + tt.Pattern, //nolint:scopelint + ) + }) + } +} diff --git a/test/testshared/testshared.go b/test/testshared/testshared.go index 8fd6185038ab..8effe2bad0bf 100644 --- a/test/testshared/testshared.go +++ b/test/testshared/testshared.go @@ -66,6 +66,12 @@ func (r *RunResult) ExpectExitCode(possibleCodes ...int) *RunResult { return r } +// ExpectOutputRegexp can be called with either a string or compiled regexp +func (r *RunResult) ExpectOutputRegexp(s interface{}) *RunResult { + assert.Regexp(r.t, s, r.output, "exit code is %d", r.exitCode) + return r +} + func (r *RunResult) ExpectOutputContains(s string) *RunResult { assert.Contains(r.t, r.output, s, "exit code is %d", r.exitCode) return r