mirror of
https://github.com/scratchfoundation/golangci-lint.git
synced 2025-07-22 12:10:48 -04:00
dev: rewrite linters Manager (#4419)
This commit is contained in:
parent
26f8088b38
commit
b14d05cdb4
27 changed files with 1749 additions and 1825 deletions
docs/src/docs/contributing
pkg
commands
config
golinters
lint
lintersdb
builder_linter.gobuilder_plugin.goenabled_set.goenabled_set_test.gomanager.gomanager_test.govalidator.govalidator_test.go
runner.goresult/processors
scripts/expand_website_templates
test
|
@ -22,11 +22,18 @@ graph LR
|
|||
|
||||
</ResponsiveContainer>
|
||||
|
||||
## Init
|
||||
|
||||
The configuration is loaded from file and flags by `config.Loader` inside `PersistentPreRun` (or `PreRun`) of the commands that require configuration.
|
||||
|
||||
The linter database (`linterdb.Manager`) is fill based on the configuration:
|
||||
- The linters ("internals" and plugins) are built by `linterdb.LinterBuilder` and `linterdb.PluginBuilder` builders.
|
||||
- The configuration is validated by `linterdb.Validator`.
|
||||
|
||||
## Load Packages
|
||||
|
||||
Loading packages is listing all packages and their recursive dependencies for analysis.
|
||||
Also, depending on the enabled linters set some parsing of the source code can be performed
|
||||
at this step.
|
||||
Also, depending on the enabled linters set some parsing of the source code can be performed at this step.
|
||||
|
||||
Packages loading starts here:
|
||||
|
||||
|
@ -79,10 +86,10 @@ and outputs list of packages and requested information about them: filenames, ty
|
|||
|
||||
First, we need to find all enabled linters. All linters are registered here:
|
||||
|
||||
```go title=pkg/lint/lintersdb/manager.go
|
||||
func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
```go title=pkg/lint/lintersdb/builder_linter.go
|
||||
func (b LinterBuilder) Build(cfg *config.Config) []*linter.Config {
|
||||
// ...
|
||||
linters = append(linters,
|
||||
return []*linter.Config{
|
||||
// ...
|
||||
linter.NewConfig(golinters.NewBodyclose()).
|
||||
WithSince("v1.18.0").
|
||||
|
@ -97,26 +104,25 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||
WithPresets(linter.PresetBugs, linter.PresetMetaLinter).
|
||||
WithAlternativeNames("vet", "vetshadow").
|
||||
WithURL("https://pkg.go.dev/cmd/vet"),
|
||||
// ...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
We filter requested in config and command-line linters in `EnabledSet`:
|
||||
|
||||
```go title=pkg/lint/lintersdb/enabled_set.go
|
||||
func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error)
|
||||
```go title=pkg/lint/lintersdb/manager.go
|
||||
func (m *Manager) GetEnabledLintersMap() (map[string]*linter.Config, error)
|
||||
```
|
||||
|
||||
We merge enabled linters into one `MetaLinter` to improve execution time if we can:
|
||||
|
||||
```go title=pkg/lint/lintersdb/enabled_set.go
|
||||
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters
|
||||
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
|
||||
// one metalinter for data reuse and speed up.
|
||||
func (es EnabledSet) GetOptimizedLinters() ([]*linter.Config, error) {
|
||||
```go titlepkg/lint/lintersdb/manager.go
|
||||
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters into a fewer number of linters.
|
||||
// E.g. some go/analysis linters can be optimized into one metalinter for data reuse and speed up.
|
||||
func (m *Manager) GetOptimizedLinters() ([]*linter.Config, error) {
|
||||
// ...
|
||||
es.combineGoAnalysisLinters(resultLintersSet)
|
||||
m.combineGoAnalysisLinters(resultLintersSet)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
@ -133,9 +139,11 @@ type MetaLinter struct {
|
|||
Currently, all linters except `unused` can be merged into this meta linter.
|
||||
The `unused` isn't merged because it has high memory usage.
|
||||
|
||||
Linters execution starts in `runAnalyzers`. It's the most complex part of the `golangci-lint`.
|
||||
We use custom [go/analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis) runner there. It runs as much as it can in parallel. It lazy-loads as much as it can
|
||||
to reduce memory usage. Also, it sets all heavyweight data to `nil` as becomes unneeded to save memory.
|
||||
Linters execution starts in `runAnalyzers`.
|
||||
It's the most complex part of the `golangci-lint`.
|
||||
We use custom [go/analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis) runner there.
|
||||
It runs as much as it can in parallel. It lazy-loads as much as it can to reduce memory usage.
|
||||
Also, it sets all heavyweight data to `nil` as becomes unneeded to save memory.
|
||||
|
||||
We don't use existing [multichecker](https://pkg.go.dev/golang.org/x/tools/go/analysis/multichecker) because
|
||||
it doesn't use caching and doesn't have some important performance optimizations.
|
||||
|
|
|
@ -28,8 +28,8 @@ After that:
|
|||
Look at other linters in this directory.
|
||||
Implement linter integration and check that test passes.
|
||||
3. Add the new struct for the linter (which you've implemented in `pkg/golinters/{yourlintername}.go`) to the
|
||||
list of all supported linters in [`pkg/lint/lintersdb/manager.go`](https://github.com/golangci/golangci-lint/blob/master/pkg/lint/lintersdb/manager.go)
|
||||
to the function `GetAllSupportedLinterConfigs`.
|
||||
list of all supported linters in [`pkg/lint/lintersdb/builder_linter.go`](https://github.com/golangci/golangci-lint/blob/master/pkg/lint/lintersdb/builder_linter.go)
|
||||
to the method `LinterBuilder.Build`.
|
||||
- Add `WithSince("next_version")`, where `next_version` must be replaced by the next minor version. (ex: v1.2.0 if the current version is v1.1.0)
|
||||
4. Find out what options do you need to configure for the linter.
|
||||
For example, `nakedret` has only 1 option: [`max-func-lines`](https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml).
|
||||
|
|
|
@ -41,7 +41,7 @@ func newHelpCommand(logger logutils.Log) *helpCommand {
|
|||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: cobra.NoFileCompletions,
|
||||
Run: c.execute,
|
||||
PreRun: c.preRun,
|
||||
PreRunE: c.preRunE,
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -50,10 +50,18 @@ func newHelpCommand(logger logutils.Log) *helpCommand {
|
|||
return c
|
||||
}
|
||||
|
||||
func (c *helpCommand) preRun(_ *cobra.Command, _ []string) {
|
||||
func (c *helpCommand) preRunE(_ *cobra.Command, _ []string) error {
|
||||
// The command doesn't depend on the real configuration.
|
||||
// It just needs the list of all plugins and all presets.
|
||||
c.dbManager = lintersdb.NewManager(config.NewDefault(), c.log)
|
||||
dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), config.NewDefault(),
|
||||
lintersdb.NewPluginBuilder(c.log), lintersdb.NewLinterBuilder())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.dbManager = dbManager
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *helpCommand) execute(_ *cobra.Command, _ []string) {
|
||||
|
|
|
@ -27,8 +27,7 @@ type lintersCommand struct {
|
|||
|
||||
log logutils.Log
|
||||
|
||||
dbManager *lintersdb.Manager
|
||||
enabledLintersSet *lintersdb.EnabledSet
|
||||
dbManager *lintersdb.Manager
|
||||
}
|
||||
|
||||
func newLintersCommand(logger logutils.Log, cfg *config.Config) *lintersCommand {
|
||||
|
@ -65,15 +64,19 @@ func (c *lintersCommand) preRunE(cmd *cobra.Command, _ []string) error {
|
|||
return fmt.Errorf("can't load config: %w", err)
|
||||
}
|
||||
|
||||
c.dbManager = lintersdb.NewManager(c.cfg, c.log)
|
||||
c.enabledLintersSet = lintersdb.NewEnabledSet(c.dbManager,
|
||||
lintersdb.NewValidator(c.dbManager), c.log.Child(logutils.DebugKeyLintersDB), c.cfg)
|
||||
dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), c.cfg,
|
||||
lintersdb.NewPluginBuilder(c.log), lintersdb.NewLinterBuilder())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.dbManager = dbManager
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *lintersCommand) execute(_ *cobra.Command, _ []string) error {
|
||||
enabledLintersMap, err := c.enabledLintersSet.GetEnabledLintersMap()
|
||||
enabledLintersMap, err := c.dbManager.GetEnabledLintersMap()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get enabled linters: %w", err)
|
||||
}
|
||||
|
|
|
@ -80,8 +80,7 @@ type runCommand struct {
|
|||
|
||||
buildInfo BuildInfo
|
||||
|
||||
dbManager *lintersdb.Manager
|
||||
enabledLintersSet *lintersdb.EnabledSet
|
||||
dbManager *lintersdb.Manager
|
||||
|
||||
log logutils.Log
|
||||
debugf logutils.DebugFunc
|
||||
|
@ -171,9 +170,13 @@ func (c *runCommand) persistentPostRunE(_ *cobra.Command, _ []string) error {
|
|||
}
|
||||
|
||||
func (c *runCommand) preRunE(_ *cobra.Command, _ []string) error {
|
||||
c.dbManager = lintersdb.NewManager(c.cfg, c.log)
|
||||
c.enabledLintersSet = lintersdb.NewEnabledSet(c.dbManager,
|
||||
lintersdb.NewValidator(c.dbManager), c.log.Child(logutils.DebugKeyLintersDB), c.cfg)
|
||||
dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), c.cfg,
|
||||
lintersdb.NewPluginBuilder(c.log), lintersdb.NewLinterBuilder())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.dbManager = dbManager
|
||||
|
||||
c.goenv = goutil.NewEnv(c.log.Child(logutils.DebugKeyGoEnv))
|
||||
|
||||
|
@ -340,12 +343,12 @@ func (c *runCommand) runAndPrint(ctx context.Context, args []string) error {
|
|||
func (c *runCommand) runAnalysis(ctx context.Context, args []string) ([]result.Issue, error) {
|
||||
c.cfg.Run.Args = args
|
||||
|
||||
lintersToRun, err := c.enabledLintersSet.GetOptimizedLinters()
|
||||
lintersToRun, err := c.dbManager.GetOptimizedLinters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
enabledLintersMap, err := c.enabledLintersSet.GetEnabledLintersMap()
|
||||
enabledLintersMap, err := c.dbManager.GetEnabledLintersMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -361,8 +364,8 @@ func (c *runCommand) runAnalysis(ctx context.Context, args []string) ([]result.I
|
|||
}
|
||||
lintCtx.Log = c.log.Child(logutils.DebugKeyLintersContext)
|
||||
|
||||
runner, err := lint.NewRunner(c.cfg, c.log.Child(logutils.DebugKeyRunner),
|
||||
c.goenv, c.enabledLintersSet, c.lineCache, c.fileCache, c.dbManager, lintCtx.Packages)
|
||||
runner, err := lint.NewRunner(c.log.Child(logutils.DebugKeyRunner),
|
||||
c.cfg, c.goenv, c.lineCache, c.fileCache, c.dbManager, lintCtx.Packages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ type versionInfo struct {
|
|||
}
|
||||
|
||||
type versionOptions struct {
|
||||
Format string `mapstructure:"format"`
|
||||
Debug bool `mapstructure:"debug"`
|
||||
Format string
|
||||
Debug bool
|
||||
}
|
||||
|
||||
type versionCommand struct {
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
hcversion "github.com/hashicorp/go-version"
|
||||
|
@ -33,18 +32,16 @@ func (c *Config) GetConfigDir() string {
|
|||
}
|
||||
|
||||
func (c *Config) Validate() error {
|
||||
for i, rule := range c.Issues.ExcludeRules {
|
||||
if err := rule.Validate(); err != nil {
|
||||
return fmt.Errorf("error in exclude rule #%d: %w", i, err)
|
||||
}
|
||||
validators := []func() error{
|
||||
c.Issues.Validate,
|
||||
c.Severity.Validate,
|
||||
c.LintersSettings.Validate,
|
||||
c.Linters.Validate,
|
||||
}
|
||||
|
||||
if len(c.Severity.Rules) > 0 && c.Severity.Default == "" {
|
||||
return errors.New("can't set severity rule option: no default severity defined")
|
||||
}
|
||||
for i, rule := range c.Severity.Rules {
|
||||
if err := rule.Validate(); err != nil {
|
||||
return fmt.Errorf("error in severity rule #%d: %w", i, err)
|
||||
for _, v := range validators {
|
||||
if err := v(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,3 +87,22 @@ func detectGoVersion() string {
|
|||
|
||||
return "1.17"
|
||||
}
|
||||
|
||||
// Trims the Go version to keep only M.m.
|
||||
// Since Go 1.21 the version inside the go.mod can be a patched version (ex: 1.21.0).
|
||||
// The version can also include information which we want to remove (ex: 1.21alpha1)
|
||||
// https://go.dev/doc/toolchain#versions
|
||||
// This a problem with staticcheck and gocritic.
|
||||
func trimGoVersion(v string) string {
|
||||
if v == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
exp := regexp.MustCompile(`(\d\.\d+)(?:\.\d+|[a-z]+\d)`)
|
||||
|
||||
if exp.MatchString(v) {
|
||||
return exp.FindStringSubmatch(v)[1]
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
|
|
@ -84,3 +84,52 @@ func TestIsGoGreaterThanOrEqual(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_trimGoVersion(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
version string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "patched version",
|
||||
version: "1.22.0",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "minor version",
|
||||
version: "1.22",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "RC version",
|
||||
version: "1.22rc1",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "alpha version",
|
||||
version: "1.22alpha1",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "beta version",
|
||||
version: "1.22beta1",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "semver RC version",
|
||||
version: "1.22.0-rc1",
|
||||
expected: "1.22",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
version := trimGoVersion(test.version)
|
||||
assert.Equal(t, test.expected, version)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,16 @@ type Issues struct {
|
|||
NeedFix bool `mapstructure:"fix"`
|
||||
}
|
||||
|
||||
func (i *Issues) Validate() error {
|
||||
for i, rule := range i.ExcludeRules {
|
||||
if err := rule.Validate(); err != nil {
|
||||
return fmt.Errorf("error in exclude rule #%d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExcludeRule struct {
|
||||
BaseRule `mapstructure:",squash"`
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Linters struct {
|
||||
Enable []string
|
||||
Disable []string
|
||||
|
@ -9,3 +14,52 @@ type Linters struct {
|
|||
|
||||
Presets []string
|
||||
}
|
||||
|
||||
func (l *Linters) Validate() error {
|
||||
if err := l.validateAllDisableEnableOptions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := l.validateDisabledAndEnabledAtOneMoment(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Linters) validateAllDisableEnableOptions() error {
|
||||
if l.EnableAll && l.DisableAll {
|
||||
return errors.New("--enable-all and --disable-all options must not be combined")
|
||||
}
|
||||
|
||||
if l.DisableAll {
|
||||
if len(l.Enable) == 0 && len(l.Presets) == 0 {
|
||||
return errors.New("all linters were disabled, but no one linter was enabled: must enable at least one")
|
||||
}
|
||||
|
||||
if len(l.Disable) != 0 {
|
||||
return errors.New("can't combine options --disable-all and --disable")
|
||||
}
|
||||
}
|
||||
|
||||
if l.EnableAll && len(l.Enable) != 0 && !l.Fast {
|
||||
return errors.New("can't combine options --enable-all and --enable")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Linters) validateDisabledAndEnabledAtOneMoment() error {
|
||||
enabledLintersSet := map[string]bool{}
|
||||
for _, name := range l.Enable {
|
||||
enabledLintersSet[name] = true
|
||||
}
|
||||
|
||||
for _, name := range l.Disable {
|
||||
if enabledLintersSet[name] {
|
||||
return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -291,6 +291,10 @@ type LintersSettings struct {
|
|||
Custom map[string]CustomLinterSettings
|
||||
}
|
||||
|
||||
func (s *LintersSettings) Validate() error {
|
||||
return s.Govet.Validate()
|
||||
}
|
||||
|
||||
type AsasalintSettings struct {
|
||||
Exclude []string `mapstructure:"exclude"`
|
||||
UseBuiltinExclusions bool `mapstructure:"use-builtin-exclusions"`
|
||||
|
@ -606,15 +610,14 @@ type GovetSettings struct {
|
|||
}
|
||||
|
||||
func (cfg *GovetSettings) Validate() error {
|
||||
// TODO(ldez) need to be move into the linter file.
|
||||
if cfg.EnableAll && cfg.DisableAll {
|
||||
return errors.New("enable-all and disable-all can't be combined")
|
||||
return errors.New("govet: enable-all and disable-all can't be combined")
|
||||
}
|
||||
if cfg.EnableAll && len(cfg.Enable) != 0 {
|
||||
return errors.New("enable-all and enable can't be combined")
|
||||
return errors.New("govet: enable-all and enable can't be combined")
|
||||
}
|
||||
if cfg.DisableAll && len(cfg.Disable) != 0 {
|
||||
return errors.New("disable-all and disable can't be combined")
|
||||
return errors.New("govet: disable-all and disable can't be combined")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
214
pkg/config/linters_test.go
Normal file
214
pkg/config/linters_test.go
Normal file
|
@ -0,0 +1,214 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLinters_validateDisabledAndEnabledAtOneMoment(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
cfg *Linters
|
||||
}{
|
||||
{
|
||||
desc: "2 different sets",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
Disable: []string{"goimports", "gosec", "nolintlint"},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "only enable",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"goimports", "gosec", "nolintlint"},
|
||||
Disable: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "only disable",
|
||||
cfg: &Linters{
|
||||
Enable: nil,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no sets",
|
||||
cfg: &Linters{
|
||||
Enable: nil,
|
||||
Disable: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := test.cfg.validateDisabledAndEnabledAtOneMoment()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinters_validateDisabledAndEnabledAtOneMoment_error(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
cfg *Linters
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "disable one linter of the enabled linters",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
Disable: []string{"dupl", "gosec", "nolintlint"},
|
||||
},
|
||||
expected: `linter "dupl" can't be disabled and enabled at one moment`,
|
||||
},
|
||||
{
|
||||
desc: "disable multiple enabled linters",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
},
|
||||
expected: `linter "dupl" can't be disabled and enabled at one moment`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := test.cfg.validateDisabledAndEnabledAtOneMoment()
|
||||
require.Error(t, err)
|
||||
|
||||
require.EqualError(t, err, test.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinters_validateAllDisableEnableOptions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
cfg *Linters
|
||||
}{
|
||||
{
|
||||
desc: "nothing",
|
||||
cfg: &Linters{},
|
||||
},
|
||||
{
|
||||
desc: "enable and disable",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"goimports", "gosec", "nolintlint"},
|
||||
EnableAll: false,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
DisableAll: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "disable-all and enable",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"goimports", "gosec", "nolintlint"},
|
||||
EnableAll: false,
|
||||
Disable: nil,
|
||||
DisableAll: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "enable-all and disable",
|
||||
cfg: &Linters{
|
||||
Enable: nil,
|
||||
EnableAll: true,
|
||||
Disable: []string{"goimports", "gosec", "nolintlint"},
|
||||
DisableAll: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "enable-all and enable and fast",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
EnableAll: true,
|
||||
Disable: nil,
|
||||
DisableAll: false,
|
||||
Fast: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := test.cfg.validateAllDisableEnableOptions()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinters_validateAllDisableEnableOptions_error(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
cfg *Linters
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "enable-all and disable-all",
|
||||
cfg: &Linters{
|
||||
Enable: nil,
|
||||
EnableAll: true,
|
||||
Disable: nil,
|
||||
DisableAll: true,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "--enable-all and --disable-all options must not be combined",
|
||||
},
|
||||
{
|
||||
desc: "disable-all and disable no enable no preset",
|
||||
cfg: &Linters{
|
||||
Enable: nil,
|
||||
EnableAll: false,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
DisableAll: true,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "all linters were disabled, but no one linter was enabled: must enable at least one",
|
||||
},
|
||||
{
|
||||
desc: "disable-all and disable with enable",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"nolintlint"},
|
||||
EnableAll: false,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
DisableAll: true,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "can't combine options --disable-all and --disable",
|
||||
},
|
||||
{
|
||||
desc: "enable-all and enable",
|
||||
cfg: &Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
EnableAll: true,
|
||||
Disable: nil,
|
||||
DisableAll: false,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "can't combine options --enable-all and --enable",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := test.cfg.validateAllDisableEnableOptions()
|
||||
require.Error(t, err)
|
||||
|
||||
require.EqualError(t, err, test.expected)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -59,11 +59,37 @@ func (l *Loader) Load() error {
|
|||
|
||||
l.applyStringSliceHack()
|
||||
|
||||
l.handleGoVersion()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Loader) handleGoVersion() {
|
||||
if l.cfg.Run.Go == "" {
|
||||
l.cfg.Run.Go = detectGoVersion()
|
||||
}
|
||||
|
||||
return nil
|
||||
l.cfg.LintersSettings.Govet.Go = l.cfg.Run.Go
|
||||
|
||||
l.cfg.LintersSettings.ParallelTest.Go = l.cfg.Run.Go
|
||||
|
||||
trimmedGoVersion := trimGoVersion(l.cfg.Run.Go)
|
||||
|
||||
l.cfg.LintersSettings.Gocritic.Go = trimmedGoVersion
|
||||
if l.cfg.LintersSettings.Gofumpt.LangVersion == "" {
|
||||
l.cfg.LintersSettings.Gofumpt.LangVersion = l.cfg.Run.Go
|
||||
}
|
||||
|
||||
// staticcheck related linters.
|
||||
if l.cfg.LintersSettings.Staticcheck.GoVersion == "" {
|
||||
l.cfg.LintersSettings.Staticcheck.GoVersion = trimmedGoVersion
|
||||
}
|
||||
if l.cfg.LintersSettings.Gosimple.GoVersion == "" {
|
||||
l.cfg.LintersSettings.Gosimple.GoVersion = trimmedGoVersion
|
||||
}
|
||||
if l.cfg.LintersSettings.Stylecheck.GoVersion != "" {
|
||||
l.cfg.LintersSettings.Stylecheck.GoVersion = trimmedGoVersion
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Loader) setConfigFile() error {
|
||||
|
@ -161,11 +187,7 @@ func (l *Loader) parseConfig() error {
|
|||
// Load configuration from flags only.
|
||||
err = l.viper.Unmarshal(l.cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = l.cfg.Validate(); err != nil {
|
||||
return fmt.Errorf("can't validate config: %w", err)
|
||||
return fmt.Errorf("can't unmarshal config by viper (flags): %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -181,11 +203,7 @@ func (l *Loader) parseConfig() error {
|
|||
|
||||
// Load configuration from all sources (flags, file).
|
||||
if err := l.viper.Unmarshal(l.cfg, fileDecoderHook()); err != nil {
|
||||
return fmt.Errorf("can't unmarshal config by viper: %w", err)
|
||||
}
|
||||
|
||||
if err := l.cfg.Validate(); err != nil {
|
||||
return fmt.Errorf("can't validate config: %w", err)
|
||||
return fmt.Errorf("can't unmarshal config by viper (flags, file): %w", err)
|
||||
}
|
||||
|
||||
if l.cfg.InternalTest { // just for testing purposes: to detect config file usage
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const severityRuleMinConditionsCount = 1
|
||||
|
||||
type Severity struct {
|
||||
|
@ -8,6 +13,20 @@ type Severity struct {
|
|||
Rules []SeverityRule `mapstructure:"rules"`
|
||||
}
|
||||
|
||||
func (s *Severity) Validate() error {
|
||||
if len(s.Rules) > 0 && s.Default == "" {
|
||||
return errors.New("can't set severity rule option: no default severity defined")
|
||||
}
|
||||
|
||||
for i, rule := range s.Rules {
|
||||
if err := rule.Validate(); err != nil {
|
||||
return fmt.Errorf("error in severity rule #%d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type SeverityRule struct {
|
||||
BaseRule `mapstructure:",squash"`
|
||||
Severity string
|
||||
|
|
|
@ -139,11 +139,6 @@ var (
|
|||
func NewGovet(settings *config.GovetSettings) *goanalysis.Linter {
|
||||
var conf map[string]map[string]any
|
||||
if settings != nil {
|
||||
err := settings.Validate()
|
||||
if err != nil {
|
||||
linterLogger.Fatalf("govet configuration: %v", err)
|
||||
}
|
||||
|
||||
conf = settings.Settings
|
||||
}
|
||||
|
||||
|
|
712
pkg/lint/lintersdb/builder_linter.go
Normal file
712
pkg/lint/lintersdb/builder_linter.go
Normal file
|
@ -0,0 +1,712 @@
|
|||
package lintersdb
|
||||
|
||||
import (
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
)
|
||||
|
||||
// LinterBuilder builds the "internal" linters based on the configuration.
|
||||
type LinterBuilder struct{}
|
||||
|
||||
// NewLinterBuilder creates a new LinterBuilder.
|
||||
func NewLinterBuilder() *LinterBuilder {
|
||||
return &LinterBuilder{}
|
||||
}
|
||||
|
||||
// Build loads all the "internal" linters.
|
||||
// The configuration is use for the linter settings.
|
||||
func (b LinterBuilder) Build(cfg *config.Config) []*linter.Config {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
const megacheckName = "megacheck"
|
||||
|
||||
// The linters are sorted in the alphabetical order (case-insensitive).
|
||||
// When a new linter is added the version in `WithSince(...)` must be the next minor version of golangci-lint.
|
||||
return []*linter.Config{
|
||||
linter.NewConfig(golinters.NewAsasalint(&cfg.LintersSettings.Asasalint)).
|
||||
WithSince("1.47.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/alingse/asasalint"),
|
||||
|
||||
linter.NewConfig(golinters.NewAsciicheck()).
|
||||
WithSince("v1.26.0").
|
||||
WithPresets(linter.PresetBugs, linter.PresetStyle).
|
||||
WithURL("https://github.com/tdakkota/asciicheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewBiDiChkFuncName(&cfg.LintersSettings.BiDiChk)).
|
||||
WithSince("1.43.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/breml/bidichk"),
|
||||
|
||||
linter.NewConfig(golinters.NewBodyclose()).
|
||||
WithSince("v1.18.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetPerformance, linter.PresetBugs).
|
||||
WithURL("https://github.com/timakin/bodyclose"),
|
||||
|
||||
linter.NewConfig(golinters.NewContainedCtx()).
|
||||
WithSince("1.44.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/sivchari/containedctx"),
|
||||
|
||||
linter.NewConfig(golinters.NewContextCheck()).
|
||||
WithSince("v1.43.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/kkHAIKE/contextcheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewCopyLoopVar()).
|
||||
WithSince("v1.57.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/karamaru-alpha/copyloopvar").
|
||||
WithNoopFallback(cfg, linter.IsGoLowerThanGo122()),
|
||||
|
||||
linter.NewConfig(golinters.NewCyclop(&cfg.LintersSettings.Cyclop)).
|
||||
WithSince("v1.37.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetComplexity).
|
||||
WithURL("https://github.com/bkielbasa/cyclop"),
|
||||
|
||||
linter.NewConfig(golinters.NewDecorder(&cfg.LintersSettings.Decorder)).
|
||||
WithSince("v1.44.0").
|
||||
WithPresets(linter.PresetFormatting, linter.PresetStyle).
|
||||
WithURL("https://gitlab.com/bosi/decorder"),
|
||||
|
||||
linter.NewConfig(golinters.NewDeadcode()).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode").
|
||||
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
|
||||
|
||||
linter.NewConfig(golinters.NewDepguard(&cfg.LintersSettings.Depguard)).
|
||||
WithSince("v1.4.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetImport, linter.PresetModule).
|
||||
WithURL("https://github.com/OpenPeeDeeP/depguard"),
|
||||
|
||||
linter.NewConfig(golinters.NewDogsled(&cfg.LintersSettings.Dogsled)).
|
||||
WithSince("v1.19.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/alexkohler/dogsled"),
|
||||
|
||||
linter.NewConfig(golinters.NewDupl(&cfg.LintersSettings.Dupl)).
|
||||
WithSince("v1.0.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/mibk/dupl"),
|
||||
|
||||
linter.NewConfig(golinters.NewDupWord(&cfg.LintersSettings.DupWord)).
|
||||
WithSince("1.50.0").
|
||||
WithPresets(linter.PresetComment).
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/Abirdcfly/dupword"),
|
||||
|
||||
linter.NewConfig(golinters.NewDurationCheck()).
|
||||
WithSince("v1.37.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/charithe/durationcheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewErrcheck(&cfg.LintersSettings.Errcheck)).
|
||||
WithEnabledByDefault().
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs, linter.PresetError).
|
||||
WithURL("https://github.com/kisielk/errcheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewErrChkJSONFuncName(&cfg.LintersSettings.ErrChkJSON)).
|
||||
WithSince("1.44.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/breml/errchkjson"),
|
||||
|
||||
linter.NewConfig(golinters.NewErrName()).
|
||||
WithSince("v1.42.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/Antonboom/errname"),
|
||||
|
||||
linter.NewConfig(golinters.NewErrorLint(&cfg.LintersSettings.ErrorLint)).
|
||||
WithSince("v1.32.0").
|
||||
WithPresets(linter.PresetBugs, linter.PresetError).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/polyfloyd/go-errorlint"),
|
||||
|
||||
linter.NewConfig(golinters.NewExecInQuery()).
|
||||
WithSince("v1.46.0").
|
||||
WithPresets(linter.PresetSQL).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/lufeee/execinquery"),
|
||||
|
||||
linter.NewConfig(golinters.NewExhaustive(&cfg.LintersSettings.Exhaustive)).
|
||||
WithSince(" v1.28.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/nishanths/exhaustive"),
|
||||
|
||||
linter.NewConfig(golinters.NewExhaustiveStruct(&cfg.LintersSettings.ExhaustiveStruct)).
|
||||
WithSince("v1.32.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetTest).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/mbilski/exhaustivestruct").
|
||||
Deprecated("The owner seems to have abandoned the linter.", "v1.46.0", "exhaustruct"),
|
||||
|
||||
linter.NewConfig(golinters.NewExhaustruct(&cfg.LintersSettings.Exhaustruct)).
|
||||
WithSince("v1.46.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetTest).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/GaijinEntertainment/go-exhaustruct"),
|
||||
|
||||
linter.NewConfig(golinters.NewExportLoopRef()).
|
||||
WithSince("v1.28.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/kyoh86/exportloopref"),
|
||||
|
||||
linter.NewConfig(golinters.NewForbidigo(&cfg.LintersSettings.Forbidigo)).
|
||||
WithSince("v1.34.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
// Strictly speaking,
|
||||
// the additional information is only needed when forbidigoCfg.AnalyzeTypes is chosen by the user.
|
||||
// But we don't know that here in all cases (sometimes config is not loaded),
|
||||
// so we have to assume that it is needed to be on the safe side.
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/ashanbrown/forbidigo"),
|
||||
|
||||
linter.NewConfig(golinters.NewForceTypeAssert()).
|
||||
WithSince("v1.38.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/gostaticanalysis/forcetypeassert"),
|
||||
|
||||
linter.NewConfig(golinters.NewFunlen(&cfg.LintersSettings.Funlen)).
|
||||
WithSince("v1.18.0").
|
||||
WithPresets(linter.PresetComplexity).
|
||||
WithURL("https://github.com/ultraware/funlen"),
|
||||
|
||||
linter.NewConfig(golinters.NewGci(&cfg.LintersSettings.Gci)).
|
||||
WithSince("v1.30.0").
|
||||
WithPresets(linter.PresetFormatting, linter.PresetImport).
|
||||
WithURL("https://github.com/daixiang0/gci"),
|
||||
|
||||
linter.NewConfig(golinters.NewGinkgoLinter(&cfg.LintersSettings.GinkgoLinter)).
|
||||
WithSince("v1.51.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/nunnatsa/ginkgolinter"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoCheckCompilerDirectives()).
|
||||
WithSince("v1.51.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/leighmcculloch/gocheckcompilerdirectives"),
|
||||
|
||||
linter.NewConfig(golinters.NewGochecknoglobals()).
|
||||
WithSince("v1.12.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/leighmcculloch/gochecknoglobals"),
|
||||
|
||||
linter.NewConfig(golinters.NewGochecknoinits()).
|
||||
WithSince("v1.12.0").
|
||||
WithPresets(linter.PresetStyle),
|
||||
|
||||
linter.NewConfig(golinters.NewGoCheckSumType()).
|
||||
WithSince("v1.55.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/alecthomas/go-check-sumtype"),
|
||||
|
||||
linter.NewConfig(golinters.NewGocognit(&cfg.LintersSettings.Gocognit)).
|
||||
WithSince("v1.20.0").
|
||||
WithPresets(linter.PresetComplexity).
|
||||
WithURL("https://github.com/uudashr/gocognit"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoconst(&cfg.LintersSettings.Goconst)).
|
||||
WithSince("v1.0.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/jgautheron/goconst"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoCritic(&cfg.LintersSettings.Gocritic, cfg)).
|
||||
WithSince("v1.12.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetMetaLinter).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/go-critic/go-critic"),
|
||||
|
||||
linter.NewConfig(golinters.NewGocyclo(&cfg.LintersSettings.Gocyclo)).
|
||||
WithSince("v1.0.0").
|
||||
WithPresets(linter.PresetComplexity).
|
||||
WithURL("https://github.com/fzipp/gocyclo"),
|
||||
|
||||
linter.NewConfig(golinters.NewGodot(&cfg.LintersSettings.Godot)).
|
||||
WithSince("v1.25.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetComment).
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/tetafro/godot"),
|
||||
|
||||
linter.NewConfig(golinters.NewGodox(&cfg.LintersSettings.Godox)).
|
||||
WithSince("v1.19.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetComment).
|
||||
WithURL("https://github.com/matoous/godox"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoerr113()).
|
||||
WithSince("v1.26.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetError).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/Djarvur/go-err113"),
|
||||
|
||||
linter.NewConfig(golinters.NewGofmt(&cfg.LintersSettings.Gofmt)).
|
||||
WithSince("v1.0.0").
|
||||
WithPresets(linter.PresetFormatting).
|
||||
WithAutoFix().
|
||||
WithURL("https://pkg.go.dev/cmd/gofmt"),
|
||||
|
||||
linter.NewConfig(golinters.NewGofumpt(&cfg.LintersSettings.Gofumpt)).
|
||||
WithSince("v1.28.0").
|
||||
WithPresets(linter.PresetFormatting).
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/mvdan/gofumpt"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoHeader(&cfg.LintersSettings.Goheader)).
|
||||
WithSince("v1.28.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/denis-tingaikin/go-header"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoimports(&cfg.LintersSettings.Goimports)).
|
||||
WithSince("v1.20.0").
|
||||
WithPresets(linter.PresetFormatting, linter.PresetImport).
|
||||
WithAutoFix().
|
||||
WithURL("https://pkg.go.dev/golang.org/x/tools/cmd/goimports"),
|
||||
|
||||
linter.NewConfig(golinters.NewGolint(&cfg.LintersSettings.Golint)).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/golang/lint").
|
||||
Deprecated("The repository of the linter has been archived by the owner.", "v1.41.0", "revive"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoMND(&cfg.LintersSettings.Gomnd)).
|
||||
WithSince("v1.22.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/tommy-muehle/go-mnd"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoModDirectives(&cfg.LintersSettings.GoModDirectives)).
|
||||
WithSince("v1.39.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetModule).
|
||||
WithURL("https://github.com/ldez/gomoddirectives"),
|
||||
|
||||
linter.NewConfig(golinters.NewGomodguard(&cfg.LintersSettings.Gomodguard)).
|
||||
WithSince("v1.25.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetImport, linter.PresetModule).
|
||||
WithURL("https://github.com/ryancurrah/gomodguard"),
|
||||
|
||||
linter.NewConfig(golinters.NewGoPrintfFuncName()).
|
||||
WithSince("v1.23.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/jirfag/go-printf-func-name"),
|
||||
|
||||
linter.NewConfig(golinters.NewGosec(&cfg.LintersSettings.Gosec)).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/securego/gosec").
|
||||
WithAlternativeNames("gas"),
|
||||
|
||||
linter.NewConfig(golinters.NewGosimple(&cfg.LintersSettings.Gosimple)).
|
||||
WithEnabledByDefault().
|
||||
WithSince("v1.20.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithAlternativeNames(megacheckName).
|
||||
WithURL("https://github.com/dominikh/go-tools/tree/master/simple"),
|
||||
|
||||
linter.NewConfig(golinters.NewGosmopolitan(&cfg.LintersSettings.Gosmopolitan)).
|
||||
WithSince("v1.53.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/xen0n/gosmopolitan"),
|
||||
|
||||
linter.NewConfig(golinters.NewGovet(&cfg.LintersSettings.Govet)).
|
||||
WithEnabledByDefault().
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs, linter.PresetMetaLinter).
|
||||
WithAlternativeNames("vet", "vetshadow").
|
||||
WithURL("https://pkg.go.dev/cmd/vet"),
|
||||
|
||||
linter.NewConfig(golinters.NewGrouper(&cfg.LintersSettings.Grouper)).
|
||||
WithSince("v1.44.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/leonklingele/grouper"),
|
||||
|
||||
linter.NewConfig(golinters.NewIfshort(&cfg.LintersSettings.Ifshort)).
|
||||
WithSince("v1.36.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/esimonov/ifshort").
|
||||
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.0", ""),
|
||||
|
||||
linter.NewConfig(golinters.NewImportAs(&cfg.LintersSettings.ImportAs)).
|
||||
WithSince("v1.38.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/julz/importas"),
|
||||
|
||||
linter.NewConfig(golinters.NewINamedParam(&cfg.LintersSettings.Inamedparam)).
|
||||
WithSince("v1.55.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/macabu/inamedparam"),
|
||||
|
||||
linter.NewConfig(golinters.NewIneffassign()).
|
||||
WithEnabledByDefault().
|
||||
WithSince("v1.0.0").
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithURL("https://github.com/gordonklaus/ineffassign"),
|
||||
|
||||
linter.NewConfig(golinters.NewInterfaceBloat(&cfg.LintersSettings.InterfaceBloat)).
|
||||
WithSince("v1.49.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/sashamelentyev/interfacebloat"),
|
||||
|
||||
linter.NewConfig(golinters.NewInterfacer()).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/mvdan/interfacer").
|
||||
Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", ""),
|
||||
|
||||
linter.NewConfig(golinters.NewIntrange()).
|
||||
WithSince("v1.57.0").
|
||||
WithURL("https://github.com/ckaznocha/intrange").
|
||||
WithNoopFallback(cfg, linter.IsGoLowerThanGo122()),
|
||||
|
||||
linter.NewConfig(golinters.NewIreturn(&cfg.LintersSettings.Ireturn)).
|
||||
WithSince("v1.43.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/butuzov/ireturn"),
|
||||
|
||||
linter.NewConfig(golinters.NewLLL(&cfg.LintersSettings.Lll)).
|
||||
WithSince("v1.8.0").
|
||||
WithPresets(linter.PresetStyle),
|
||||
|
||||
linter.NewConfig(golinters.NewLoggerCheck(&cfg.LintersSettings.LoggerCheck)).
|
||||
WithSince("v1.49.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle, linter.PresetBugs).
|
||||
WithAlternativeNames("logrlint").
|
||||
WithURL("https://github.com/timonwong/loggercheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewMaintIdx(&cfg.LintersSettings.MaintIdx)).
|
||||
WithSince("v1.44.0").
|
||||
WithPresets(linter.PresetComplexity).
|
||||
WithURL("https://github.com/yagipy/maintidx"),
|
||||
|
||||
linter.NewConfig(golinters.NewMakezero(&cfg.LintersSettings.Makezero)).
|
||||
WithSince("v1.34.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/ashanbrown/makezero"),
|
||||
|
||||
linter.NewConfig(golinters.NewMaligned(&cfg.LintersSettings.Maligned)).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetPerformance).
|
||||
WithURL("https://github.com/mdempsky/maligned").
|
||||
Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", "govet 'fieldalignment'"),
|
||||
|
||||
linter.NewConfig(golinters.NewMirror()).
|
||||
WithSince("v1.53.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/butuzov/mirror"),
|
||||
|
||||
linter.NewConfig(golinters.NewMisspell(&cfg.LintersSettings.Misspell)).
|
||||
WithSince("v1.8.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetComment).
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/client9/misspell"),
|
||||
|
||||
linter.NewConfig(golinters.NewMustTag(&cfg.LintersSettings.MustTag)).
|
||||
WithSince("v1.51.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle, linter.PresetBugs).
|
||||
WithURL("https://github.com/go-simpler/musttag"),
|
||||
|
||||
linter.NewConfig(golinters.NewNakedret(&cfg.LintersSettings.Nakedret)).
|
||||
WithSince("v1.19.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/alexkohler/nakedret"),
|
||||
|
||||
linter.NewConfig(golinters.NewNestif(&cfg.LintersSettings.Nestif)).
|
||||
WithSince("v1.25.0").
|
||||
WithPresets(linter.PresetComplexity).
|
||||
WithURL("https://github.com/nakabonne/nestif"),
|
||||
|
||||
linter.NewConfig(golinters.NewNilErr()).
|
||||
WithSince("v1.38.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/gostaticanalysis/nilerr"),
|
||||
|
||||
linter.NewConfig(golinters.NewNilNil(&cfg.LintersSettings.NilNil)).
|
||||
WithSince("v1.43.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/Antonboom/nilnil"),
|
||||
|
||||
linter.NewConfig(golinters.NewNLReturn(&cfg.LintersSettings.Nlreturn)).
|
||||
WithSince("v1.30.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/ssgreg/nlreturn"),
|
||||
|
||||
linter.NewConfig(golinters.NewNoctx()).
|
||||
WithSince("v1.28.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetPerformance, linter.PresetBugs).
|
||||
WithURL("https://github.com/sonatard/noctx"),
|
||||
|
||||
linter.NewConfig(golinters.NewNoNamedReturns(&cfg.LintersSettings.NoNamedReturns)).
|
||||
WithSince("v1.46.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/firefart/nonamedreturns"),
|
||||
|
||||
linter.NewConfig(golinters.NewNoSnakeCase()).
|
||||
WithSince("v1.47.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/sivchari/nosnakecase").
|
||||
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.1", "revive(var-naming)"),
|
||||
|
||||
linter.NewConfig(golinters.NewNoSprintfHostPort()).
|
||||
WithSince("v1.46.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/stbenjam/no-sprintf-host-port"),
|
||||
|
||||
linter.NewConfig(golinters.NewParallelTest(&cfg.LintersSettings.ParallelTest)).
|
||||
WithSince("v1.33.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle, linter.PresetTest).
|
||||
WithURL("https://github.com/kunwardeep/paralleltest"),
|
||||
|
||||
linter.NewConfig(golinters.NewPerfSprint(&cfg.LintersSettings.PerfSprint)).
|
||||
WithSince("v1.55.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetPerformance).
|
||||
WithURL("https://github.com/catenacyber/perfsprint"),
|
||||
|
||||
linter.NewConfig(golinters.NewPreAlloc(&cfg.LintersSettings.Prealloc)).
|
||||
WithSince("v1.19.0").
|
||||
WithPresets(linter.PresetPerformance).
|
||||
WithURL("https://github.com/alexkohler/prealloc"),
|
||||
|
||||
linter.NewConfig(golinters.NewPredeclared(&cfg.LintersSettings.Predeclared)).
|
||||
WithSince("v1.35.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/nishanths/predeclared"),
|
||||
|
||||
linter.NewConfig(golinters.NewPromlinter(&cfg.LintersSettings.Promlinter)).
|
||||
WithSince("v1.40.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/yeya24/promlinter"),
|
||||
|
||||
linter.NewConfig(golinters.NewProtoGetter(&cfg.LintersSettings.ProtoGetter)).
|
||||
WithSince("v1.55.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/ghostiam/protogetter"),
|
||||
|
||||
linter.NewConfig(golinters.NewReassign(&cfg.LintersSettings.Reassign)).
|
||||
WithSince("1.49.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/curioswitch/go-reassign"),
|
||||
|
||||
linter.NewConfig(golinters.NewRevive(&cfg.LintersSettings.Revive)).
|
||||
WithSince("v1.37.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetMetaLinter).
|
||||
ConsiderSlow().
|
||||
WithURL("https://github.com/mgechev/revive"),
|
||||
|
||||
linter.NewConfig(golinters.NewRowsErrCheck(&cfg.LintersSettings.RowsErrCheck)).
|
||||
WithSince("v1.23.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs, linter.PresetSQL).
|
||||
WithURL("https://github.com/jingyugao/rowserrcheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewSlogLint(&cfg.LintersSettings.SlogLint)).
|
||||
WithSince("v1.55.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle, linter.PresetFormatting).
|
||||
WithURL("https://github.com/go-simpler/sloglint"),
|
||||
|
||||
linter.NewConfig(golinters.NewScopelint()).
|
||||
WithSince("v1.12.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/kyoh86/scopelint").
|
||||
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.39.0", "exportloopref"),
|
||||
|
||||
linter.NewConfig(golinters.NewSQLCloseCheck()).
|
||||
WithSince("v1.28.0").
|
||||
WithPresets(linter.PresetBugs, linter.PresetSQL).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/ryanrolds/sqlclosecheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewSpancheck(&cfg.LintersSettings.Spancheck)).
|
||||
WithSince("v1.56.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL("https://github.com/jjti/go-spancheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewStaticcheck(&cfg.LintersSettings.Staticcheck)).
|
||||
WithEnabledByDefault().
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs, linter.PresetMetaLinter).
|
||||
WithAlternativeNames(megacheckName).
|
||||
WithURL("https://staticcheck.io/"),
|
||||
|
||||
linter.NewConfig(golinters.NewStructcheck(&cfg.LintersSettings.Structcheck)).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithURL("https://github.com/opennota/check").
|
||||
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
|
||||
|
||||
linter.NewConfig(golinters.NewStylecheck(&cfg.LintersSettings.Stylecheck)).
|
||||
WithSince("v1.20.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/dominikh/go-tools/tree/master/stylecheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewTagAlign(&cfg.LintersSettings.TagAlign)).
|
||||
WithSince("v1.53.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetFormatting).
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/4meepo/tagalign"),
|
||||
|
||||
linter.NewConfig(golinters.NewTagliatelle(&cfg.LintersSettings.Tagliatelle)).
|
||||
WithSince("v1.40.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/ldez/tagliatelle"),
|
||||
|
||||
linter.NewConfig(golinters.NewTenv(&cfg.LintersSettings.Tenv)).
|
||||
WithSince("v1.43.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/sivchari/tenv"),
|
||||
|
||||
linter.NewConfig(golinters.NewTestableexamples()).
|
||||
WithSince("v1.50.0").
|
||||
WithPresets(linter.PresetTest).
|
||||
WithURL("https://github.com/maratori/testableexamples"),
|
||||
|
||||
linter.NewConfig(golinters.NewTestifylint(&cfg.LintersSettings.Testifylint)).
|
||||
WithSince("v1.55.0").
|
||||
WithPresets(linter.PresetTest, linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/Antonboom/testifylint"),
|
||||
|
||||
linter.NewConfig(golinters.NewTestpackage(&cfg.LintersSettings.Testpackage)).
|
||||
WithSince("v1.25.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetTest).
|
||||
WithURL("https://github.com/maratori/testpackage"),
|
||||
|
||||
linter.NewConfig(golinters.NewThelper(&cfg.LintersSettings.Thelper)).
|
||||
WithSince("v1.34.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/kulti/thelper"),
|
||||
|
||||
linter.NewConfig(golinters.NewTparallel()).
|
||||
WithSince("v1.32.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetTest).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/moricho/tparallel"),
|
||||
|
||||
linter.NewConfig(golinters.NewTypecheck()).
|
||||
WithInternal().
|
||||
WithEnabledByDefault().
|
||||
WithSince("v1.3.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithURL(""),
|
||||
|
||||
linter.NewConfig(golinters.NewUnconvert()).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/mdempsky/unconvert"),
|
||||
|
||||
linter.NewConfig(golinters.NewUnparam(&cfg.LintersSettings.Unparam)).
|
||||
WithSince("v1.9.0").
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/mvdan/unparam"),
|
||||
|
||||
linter.NewConfig(golinters.NewUnused(&cfg.LintersSettings.Unused, &cfg.LintersSettings.Staticcheck)).
|
||||
WithEnabledByDefault().
|
||||
WithSince("v1.20.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithAlternativeNames(megacheckName).
|
||||
ConsiderSlow().
|
||||
WithChangeTypes().
|
||||
WithURL("https://github.com/dominikh/go-tools/tree/master/unused"),
|
||||
|
||||
linter.NewConfig(golinters.NewUseStdlibVars(&cfg.LintersSettings.UseStdlibVars)).
|
||||
WithSince("v1.48.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/sashamelentyev/usestdlibvars"),
|
||||
|
||||
linter.NewConfig(golinters.NewVarcheck(&cfg.LintersSettings.Varcheck)).
|
||||
WithSince("v1.0.0").
|
||||
WithLoadForGoAnalysis().
|
||||
WithPresets(linter.PresetUnused).
|
||||
WithURL("https://github.com/opennota/check").
|
||||
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
|
||||
|
||||
linter.NewConfig(golinters.NewVarnamelen(&cfg.LintersSettings.Varnamelen)).
|
||||
WithSince("v1.43.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/blizzy78/varnamelen"),
|
||||
|
||||
linter.NewConfig(golinters.NewWastedAssign()).
|
||||
WithSince("v1.38.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/sanposhiho/wastedassign"),
|
||||
|
||||
linter.NewConfig(golinters.NewWhitespace(&cfg.LintersSettings.Whitespace)).
|
||||
WithSince("v1.19.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/ultraware/whitespace"),
|
||||
|
||||
linter.NewConfig(golinters.NewWrapcheck(&cfg.LintersSettings.Wrapcheck)).
|
||||
WithSince("v1.32.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetError).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/tomarrell/wrapcheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewWSL(&cfg.LintersSettings.WSL)).
|
||||
WithSince("v1.20.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/bombsimon/wsl"),
|
||||
|
||||
linter.NewConfig(golinters.NewZerologLint()).
|
||||
WithSince("v1.53.0").
|
||||
WithPresets(linter.PresetBugs).
|
||||
WithLoadForGoAnalysis().
|
||||
WithURL("https://github.com/ykadowak/zerologlint"),
|
||||
|
||||
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
|
||||
linter.NewConfig(golinters.NewNoLintLint(&cfg.LintersSettings.NoLintLint)).
|
||||
WithSince("v1.26.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint/README.md"),
|
||||
}
|
||||
}
|
|
@ -11,24 +11,35 @@ import (
|
|||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||
)
|
||||
|
||||
type AnalyzerPlugin interface {
|
||||
GetAnalyzers() []*analysis.Analyzer
|
||||
}
|
||||
|
||||
// getCustomLinterConfigs loads private linters that are specified in the golangci config file.
|
||||
func (m *Manager) getCustomLinterConfigs() []*linter.Config {
|
||||
if m.cfg == nil || m.log == nil {
|
||||
// PluginBuilder builds the custom linters (plugins) based on the configuration.
|
||||
type PluginBuilder struct {
|
||||
log logutils.Log
|
||||
}
|
||||
|
||||
// NewPluginBuilder creates new PluginBuilder.
|
||||
func NewPluginBuilder(log logutils.Log) *PluginBuilder {
|
||||
return &PluginBuilder{log: log}
|
||||
}
|
||||
|
||||
// Build loads custom linters that are specified in the golangci-lint config file.
|
||||
func (b *PluginBuilder) Build(cfg *config.Config) []*linter.Config {
|
||||
if cfg == nil || b.log == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var linters []*linter.Config
|
||||
|
||||
for name, settings := range m.cfg.LintersSettings.Custom {
|
||||
lc, err := m.loadCustomLinterConfig(name, settings)
|
||||
for name, settings := range cfg.LintersSettings.Custom {
|
||||
lc, err := b.loadConfig(cfg, name, settings)
|
||||
if err != nil {
|
||||
m.log.Errorf("Unable to load custom analyzer %s:%s, %v", name, settings.Path, err)
|
||||
b.log.Errorf("Unable to load custom analyzer %s:%s, %v", name, settings.Path, err)
|
||||
} else {
|
||||
linters = append(linters, lc)
|
||||
}
|
||||
|
@ -37,15 +48,15 @@ func (m *Manager) getCustomLinterConfigs() []*linter.Config {
|
|||
return linters
|
||||
}
|
||||
|
||||
// loadCustomLinterConfig loads the configuration of private linters.
|
||||
// loadConfig loads the configuration of private linters.
|
||||
// Private linters are dynamically loaded from .so plugin files.
|
||||
func (m *Manager) loadCustomLinterConfig(name string, settings config.CustomLinterSettings) (*linter.Config, error) {
|
||||
analyzers, err := m.getAnalyzerPlugin(settings.Path, settings.Settings)
|
||||
func (b *PluginBuilder) loadConfig(cfg *config.Config, name string, settings config.CustomLinterSettings) (*linter.Config, error) {
|
||||
analyzers, err := b.getAnalyzerPlugin(cfg, settings.Path, settings.Settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.log.Infof("Loaded %s: %s", settings.Path, name)
|
||||
b.log.Infof("Loaded %s: %s", settings.Path, name)
|
||||
|
||||
customLinter := goanalysis.NewLinter(name, settings.Description, analyzers, nil).
|
||||
WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
|
@ -63,10 +74,10 @@ func (m *Manager) loadCustomLinterConfig(name string, settings config.CustomLint
|
|||
// and returns the 'AnalyzerPlugin' interface implemented by the private plugin.
|
||||
// An error is returned if the private linter cannot be loaded
|
||||
// or the linter does not implement the AnalyzerPlugin interface.
|
||||
func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Analyzer, error) {
|
||||
func (b *PluginBuilder) getAnalyzerPlugin(cfg *config.Config, path string, settings any) ([]*analysis.Analyzer, error) {
|
||||
if !filepath.IsAbs(path) {
|
||||
// resolve non-absolute paths relative to config file's directory
|
||||
path = filepath.Join(m.cfg.GetConfigDir(), path)
|
||||
path = filepath.Join(cfg.GetConfigDir(), path)
|
||||
}
|
||||
|
||||
plug, err := plugin.Open(path)
|
||||
|
@ -74,7 +85,7 @@ func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Anal
|
|||
return nil, err
|
||||
}
|
||||
|
||||
analyzers, err := m.lookupPlugin(plug, settings)
|
||||
analyzers, err := b.lookupPlugin(plug, settings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("lookup plugin %s: %w", path, err)
|
||||
}
|
||||
|
@ -82,10 +93,10 @@ func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Anal
|
|||
return analyzers, nil
|
||||
}
|
||||
|
||||
func (m *Manager) lookupPlugin(plug *plugin.Plugin, settings any) ([]*analysis.Analyzer, error) {
|
||||
func (b *PluginBuilder) lookupPlugin(plug *plugin.Plugin, settings any) ([]*analysis.Analyzer, error) {
|
||||
symbol, err := plug.Lookup("New")
|
||||
if err != nil {
|
||||
analyzers, errP := m.lookupAnalyzerPlugin(plug)
|
||||
analyzers, errP := b.lookupAnalyzerPlugin(plug)
|
||||
if errP != nil {
|
||||
return nil, errors.Join(err, errP)
|
||||
}
|
||||
|
@ -102,13 +113,13 @@ func (m *Manager) lookupPlugin(plug *plugin.Plugin, settings any) ([]*analysis.A
|
|||
return constructor(settings)
|
||||
}
|
||||
|
||||
func (m *Manager) lookupAnalyzerPlugin(plug *plugin.Plugin) ([]*analysis.Analyzer, error) {
|
||||
func (b *PluginBuilder) lookupAnalyzerPlugin(plug *plugin.Plugin) ([]*analysis.Analyzer, error) {
|
||||
symbol, err := plug.Lookup("AnalyzerPlugin")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.log.Warnf("plugin: 'AnalyzerPlugin' plugins are deprecated, please use the new plugin signature: " +
|
||||
b.log.Warnf("plugin: 'AnalyzerPlugin' plugins are deprecated, please use the new plugin signature: " +
|
||||
"https://golangci-lint.run/contributing/new-linters/#create-a-plugin")
|
||||
|
||||
analyzerPlugin, ok := symbol.(AnalyzerPlugin)
|
|
@ -1,224 +0,0 @@
|
|||
package lintersdb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||
)
|
||||
|
||||
// EnvTestRun value: "1"
|
||||
const EnvTestRun = "GL_TEST_RUN"
|
||||
|
||||
type EnabledSet struct {
|
||||
m *Manager
|
||||
v *Validator
|
||||
log logutils.Log
|
||||
cfg *config.Config
|
||||
debugf logutils.DebugFunc
|
||||
}
|
||||
|
||||
func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Config) *EnabledSet {
|
||||
return &EnabledSet{
|
||||
m: m,
|
||||
v: v,
|
||||
log: log,
|
||||
cfg: cfg,
|
||||
debugf: logutils.Debug(logutils.DebugKeyEnabledLinters),
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo // the complexity cannot be reduced.
|
||||
func (es EnabledSet) build(lcfg *config.Linters, enabledByDefaultLinters []*linter.Config) map[string]*linter.Config {
|
||||
es.debugf("Linters config: %#v", lcfg)
|
||||
|
||||
resultLintersSet := map[string]*linter.Config{}
|
||||
switch {
|
||||
case len(lcfg.Presets) != 0:
|
||||
break // imply --disable-all
|
||||
case lcfg.EnableAll:
|
||||
resultLintersSet = linterConfigsToMap(es.m.GetAllSupportedLinterConfigs())
|
||||
case lcfg.DisableAll:
|
||||
break
|
||||
default:
|
||||
resultLintersSet = linterConfigsToMap(enabledByDefaultLinters)
|
||||
}
|
||||
|
||||
// --presets can only add linters to default set
|
||||
for _, p := range lcfg.Presets {
|
||||
for _, lc := range es.m.GetAllLinterConfigsForPreset(p) {
|
||||
lc := lc
|
||||
resultLintersSet[lc.Name()] = lc
|
||||
}
|
||||
}
|
||||
|
||||
// --fast removes slow linters from current set.
|
||||
// It should be after --presets to be able to run only fast linters in preset.
|
||||
// It should be before --enable and --disable to be able to enable or disable specific linter.
|
||||
if lcfg.Fast {
|
||||
for name, lc := range resultLintersSet {
|
||||
if lc.IsSlowLinter() {
|
||||
delete(resultLintersSet, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range lcfg.Enable {
|
||||
for _, lc := range es.m.GetLinterConfigs(name) {
|
||||
// it's important to use lc.Name() nor name because name can be alias
|
||||
resultLintersSet[lc.Name()] = lc
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range lcfg.Disable {
|
||||
for _, lc := range es.m.GetLinterConfigs(name) {
|
||||
// it's important to use lc.Name() nor name because name can be alias
|
||||
delete(resultLintersSet, lc.Name())
|
||||
}
|
||||
}
|
||||
|
||||
// typecheck is not a real linter and cannot be disabled.
|
||||
if _, ok := resultLintersSet["typecheck"]; !ok && (es.cfg == nil || !es.cfg.InternalCmdTest) {
|
||||
for _, lc := range es.m.GetLinterConfigs("typecheck") {
|
||||
// it's important to use lc.Name() nor name because name can be alias
|
||||
resultLintersSet[lc.Name()] = lc
|
||||
}
|
||||
}
|
||||
|
||||
return resultLintersSet
|
||||
}
|
||||
|
||||
func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error) {
|
||||
if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
enabledLinters := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
|
||||
if os.Getenv(EnvTestRun) == "1" {
|
||||
es.verbosePrintLintersStatus(enabledLinters)
|
||||
}
|
||||
return enabledLinters, nil
|
||||
}
|
||||
|
||||
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters
|
||||
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
|
||||
// one metalinter for data reuse and speed up.
|
||||
func (es EnabledSet) GetOptimizedLinters() ([]*linter.Config, error) {
|
||||
if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultLintersSet := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
|
||||
es.verbosePrintLintersStatus(resultLintersSet)
|
||||
es.combineGoAnalysisLinters(resultLintersSet)
|
||||
|
||||
resultLinters := maps.Values(resultLintersSet)
|
||||
|
||||
// Make order of execution of linters (go/analysis metalinter and unused) stable.
|
||||
sort.Slice(resultLinters, func(i, j int) bool {
|
||||
a, b := resultLinters[i], resultLinters[j]
|
||||
|
||||
if b.Name() == linter.LastLinter {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Name() == linter.LastLinter {
|
||||
return false
|
||||
}
|
||||
|
||||
if a.DoesChangeTypes != b.DoesChangeTypes {
|
||||
return b.DoesChangeTypes // move type-changing linters to the end to optimize speed
|
||||
}
|
||||
return a.Name() < b.Name()
|
||||
})
|
||||
|
||||
return resultLinters, nil
|
||||
}
|
||||
|
||||
func (es EnabledSet) combineGoAnalysisLinters(linters map[string]*linter.Config) {
|
||||
var goanalysisLinters []*goanalysis.Linter
|
||||
goanalysisPresets := map[string]bool{}
|
||||
for _, lc := range linters {
|
||||
lnt, ok := lc.Linter.(*goanalysis.Linter)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if lnt.LoadMode() == goanalysis.LoadModeWholeProgram {
|
||||
// It's ineffective by CPU and memory to run whole-program and incremental analyzers at once.
|
||||
continue
|
||||
}
|
||||
|
||||
goanalysisLinters = append(goanalysisLinters, lnt)
|
||||
|
||||
for _, p := range lc.InPresets {
|
||||
goanalysisPresets[p] = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(goanalysisLinters) <= 1 {
|
||||
es.debugf("Didn't combine go/analysis linters: got only %d linters", len(goanalysisLinters))
|
||||
return
|
||||
}
|
||||
|
||||
for _, lnt := range goanalysisLinters {
|
||||
delete(linters, lnt.Name())
|
||||
}
|
||||
|
||||
// Make order of execution of go/analysis analyzers stable.
|
||||
sort.Slice(goanalysisLinters, func(i, j int) bool {
|
||||
a, b := goanalysisLinters[i], goanalysisLinters[j]
|
||||
|
||||
if b.Name() == linter.LastLinter {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Name() == linter.LastLinter {
|
||||
return false
|
||||
}
|
||||
|
||||
return a.Name() <= b.Name()
|
||||
})
|
||||
|
||||
ml := goanalysis.NewMetaLinter(goanalysisLinters)
|
||||
|
||||
presets := maps.Keys(goanalysisPresets)
|
||||
sort.Strings(presets)
|
||||
|
||||
mlConfig := &linter.Config{
|
||||
Linter: ml,
|
||||
EnabledByDefault: false,
|
||||
InPresets: presets,
|
||||
AlternativeNames: nil,
|
||||
OriginalURL: "",
|
||||
}
|
||||
|
||||
mlConfig = mlConfig.WithLoadForGoAnalysis()
|
||||
|
||||
linters[ml.Name()] = mlConfig
|
||||
|
||||
es.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters))
|
||||
}
|
||||
|
||||
func (es EnabledSet) verbosePrintLintersStatus(lcs map[string]*linter.Config) {
|
||||
var linterNames []string
|
||||
for _, lc := range lcs {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
||||
linterNames = append(linterNames, lc.Name())
|
||||
}
|
||||
sort.StringSlice(linterNames).Sort()
|
||||
es.log.Infof("Active %d linters: %s", len(linterNames), linterNames)
|
||||
|
||||
if len(es.cfg.Linters.Presets) != 0 {
|
||||
sort.StringSlice(es.cfg.Linters.Presets).Sort()
|
||||
es.log.Infof("Active presets: %s", es.cfg.Linters.Presets)
|
||||
}
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
package lintersdb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||
)
|
||||
|
||||
type dummyLogger struct{}
|
||||
|
||||
func (d dummyLogger) Fatalf(_ string, _ ...any) {}
|
||||
|
||||
func (d dummyLogger) Panicf(_ string, _ ...any) {}
|
||||
|
||||
func (d dummyLogger) Errorf(_ string, _ ...any) {}
|
||||
|
||||
func (d dummyLogger) Warnf(_ string, _ ...any) {}
|
||||
|
||||
func (d dummyLogger) Infof(_ string, _ ...any) {}
|
||||
|
||||
func (d dummyLogger) Child(_ string) logutils.Log {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d dummyLogger) SetLevel(_ logutils.LogLevel) {}
|
||||
|
||||
func TestEnabledSet_GetEnabledLintersMap(t *testing.T) {
|
||||
m := NewManager(nil, nil)
|
||||
|
||||
cfg := config.NewDefault()
|
||||
|
||||
cfg.Linters.DisableAll = true
|
||||
cfg.Linters.Enable = []string{"gofmt"}
|
||||
|
||||
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, cfg)
|
||||
|
||||
lintersMap, err := es.GetEnabledLintersMap()
|
||||
require.NoError(t, err)
|
||||
|
||||
gofmtConfigs := m.GetLinterConfigs("gofmt")
|
||||
typecheckConfigs := m.GetLinterConfigs("typecheck")
|
||||
|
||||
expected := map[string]*linter.Config{
|
||||
"gofmt": gofmtConfigs[0],
|
||||
"typecheck": typecheckConfigs[0],
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, lintersMap)
|
||||
}
|
||||
|
||||
func TestEnabledSet_GetOptimizedLinters(t *testing.T) {
|
||||
m := NewManager(nil, nil)
|
||||
|
||||
cfg := config.NewDefault()
|
||||
|
||||
cfg.Linters.DisableAll = true
|
||||
cfg.Linters.Enable = []string{"gofmt"}
|
||||
|
||||
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, cfg)
|
||||
|
||||
optimizedLinters, err := es.GetOptimizedLinters()
|
||||
require.NoError(t, err)
|
||||
|
||||
gofmtConfigs := m.GetLinterConfigs("gofmt")
|
||||
typecheckConfigs := m.GetLinterConfigs("typecheck")
|
||||
|
||||
var gaLinters []*goanalysis.Linter
|
||||
for _, l := range gofmtConfigs {
|
||||
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
|
||||
}
|
||||
for _, l := range typecheckConfigs {
|
||||
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
|
||||
}
|
||||
|
||||
mlConfig := &linter.Config{
|
||||
Linter: goanalysis.NewMetaLinter(gaLinters),
|
||||
InPresets: []string{"bugs", "format"},
|
||||
}
|
||||
|
||||
expected := []*linter.Config{mlConfig.WithLoadForGoAnalysis()}
|
||||
|
||||
assert.Equal(t, expected, optimizedLinters)
|
||||
}
|
||||
|
||||
func TestEnabledSet_build(t *testing.T) {
|
||||
type cs struct {
|
||||
cfg config.Linters
|
||||
name string // test case name
|
||||
def []string // enabled by default linters
|
||||
exp []string // alphabetically ordered enabled linter names
|
||||
}
|
||||
|
||||
allMegacheckLinterNames := []string{"gosimple", "staticcheck", "unused"}
|
||||
|
||||
cases := []cs{
|
||||
{
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"megacheck"},
|
||||
},
|
||||
name: "disable all linters from megacheck",
|
||||
def: allMegacheckLinterNames,
|
||||
exp: []string{"typecheck"}, // all disabled
|
||||
},
|
||||
{
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"staticcheck"},
|
||||
},
|
||||
name: "disable only staticcheck",
|
||||
def: allMegacheckLinterNames,
|
||||
exp: []string{"gosimple", "typecheck", "unused"},
|
||||
},
|
||||
{
|
||||
name: "don't merge into megacheck",
|
||||
def: allMegacheckLinterNames,
|
||||
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
|
||||
},
|
||||
{
|
||||
name: "expand megacheck",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"megacheck"},
|
||||
},
|
||||
def: nil,
|
||||
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
|
||||
},
|
||||
{
|
||||
name: "don't disable anything",
|
||||
def: []string{"gofmt", "govet", "typecheck"},
|
||||
exp: []string{"gofmt", "govet", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "enable gosec by gas alias",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"gas"},
|
||||
},
|
||||
exp: []string{"gosec", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "enable gosec by primary name",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"gosec"},
|
||||
},
|
||||
exp: []string{"gosec", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "enable gosec by both names",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"gosec", "gas"},
|
||||
},
|
||||
exp: []string{"gosec", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "disable gosec by gas alias",
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"gas"},
|
||||
},
|
||||
def: []string{"gosec"},
|
||||
exp: []string{"typecheck"},
|
||||
},
|
||||
{
|
||||
name: "disable gosec by primary name",
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"gosec"},
|
||||
},
|
||||
def: []string{"gosec"},
|
||||
exp: []string{"typecheck"},
|
||||
},
|
||||
}
|
||||
|
||||
m := NewManager(nil, nil)
|
||||
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, nil)
|
||||
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
var defaultLinters []*linter.Config
|
||||
for _, ln := range c.def {
|
||||
lcs := m.GetLinterConfigs(ln)
|
||||
assert.NotNil(t, lcs, ln)
|
||||
defaultLinters = append(defaultLinters, lcs...)
|
||||
}
|
||||
|
||||
els := es.build(&c.cfg, defaultLinters)
|
||||
var enabledLinters []string
|
||||
for ln, lc := range els {
|
||||
assert.Equal(t, ln, lc.Name())
|
||||
enabledLinters = append(enabledLinters, ln)
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, c.exp, enabledLinters)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnabledSet_combineGoAnalysisLinters(t *testing.T) {
|
||||
m := NewManager(nil, nil)
|
||||
|
||||
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, config.NewDefault())
|
||||
|
||||
foo := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
bar := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
linters map[string]*linter.Config
|
||||
expected map[string]*linter.Config
|
||||
}{
|
||||
{
|
||||
desc: "no combined, one linter",
|
||||
linters: map[string]*linter.Config{
|
||||
"foo": {
|
||||
Linter: foo,
|
||||
InPresets: []string{"A"},
|
||||
},
|
||||
},
|
||||
expected: map[string]*linter.Config{
|
||||
"foo": {
|
||||
Linter: foo,
|
||||
InPresets: []string{"A"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "combined, several linters",
|
||||
linters: map[string]*linter.Config{
|
||||
"foo": {
|
||||
Linter: foo,
|
||||
InPresets: []string{"A"},
|
||||
},
|
||||
"bar": {
|
||||
Linter: bar,
|
||||
InPresets: []string{"B"},
|
||||
},
|
||||
},
|
||||
expected: func() map[string]*linter.Config {
|
||||
mlConfig := &linter.Config{
|
||||
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{bar, foo}),
|
||||
InPresets: []string{"A", "B"},
|
||||
}
|
||||
|
||||
return map[string]*linter.Config{
|
||||
"goanalysis_metalinter": mlConfig.WithLoadForGoAnalysis(),
|
||||
}
|
||||
}(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
es.combineGoAnalysisLinters(test.linters)
|
||||
|
||||
assert.Equal(t, test.expected, test.linters)
|
||||
})
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -4,43 +4,223 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||
)
|
||||
|
||||
func Test_trimGoVersion(t *testing.T) {
|
||||
func TestManager_GetEnabledLintersMap(t *testing.T) {
|
||||
cfg := config.NewDefault()
|
||||
cfg.Linters.DisableAll = true
|
||||
cfg.Linters.Enable = []string{"gofmt"}
|
||||
|
||||
m, err := NewManager(logutils.NewStderrLog("skip"), cfg, NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
lintersMap, err := m.GetEnabledLintersMap()
|
||||
require.NoError(t, err)
|
||||
|
||||
gofmtConfigs := m.GetLinterConfigs("gofmt")
|
||||
typecheckConfigs := m.GetLinterConfigs("typecheck")
|
||||
|
||||
expected := map[string]*linter.Config{
|
||||
"gofmt": gofmtConfigs[0],
|
||||
"typecheck": typecheckConfigs[0],
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, lintersMap)
|
||||
}
|
||||
|
||||
func TestManager_GetOptimizedLinters(t *testing.T) {
|
||||
cfg := config.NewDefault()
|
||||
cfg.Linters.DisableAll = true
|
||||
cfg.Linters.Enable = []string{"gofmt"}
|
||||
|
||||
m, err := NewManager(logutils.NewStderrLog("skip"), cfg, NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
optimizedLinters, err := m.GetOptimizedLinters()
|
||||
require.NoError(t, err)
|
||||
|
||||
var gaLinters []*goanalysis.Linter
|
||||
for _, l := range m.GetLinterConfigs("gofmt") {
|
||||
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
|
||||
}
|
||||
for _, l := range m.GetLinterConfigs("typecheck") {
|
||||
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
|
||||
}
|
||||
|
||||
mlConfig := &linter.Config{
|
||||
Linter: goanalysis.NewMetaLinter(gaLinters),
|
||||
InPresets: []string{"bugs", "format"},
|
||||
}
|
||||
|
||||
expected := []*linter.Config{mlConfig.WithLoadForGoAnalysis()}
|
||||
|
||||
assert.Equal(t, expected, optimizedLinters)
|
||||
}
|
||||
|
||||
func TestManager_build(t *testing.T) {
|
||||
type cs struct {
|
||||
cfg config.Linters
|
||||
name string // test case name
|
||||
def []string // enabled by default linters
|
||||
exp []string // alphabetically ordered enabled linter names
|
||||
}
|
||||
|
||||
allMegacheckLinterNames := []string{"gosimple", "staticcheck", "unused"}
|
||||
|
||||
cases := []cs{
|
||||
{
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"megacheck"},
|
||||
},
|
||||
name: "disable all linters from megacheck",
|
||||
def: allMegacheckLinterNames,
|
||||
exp: []string{"typecheck"}, // all disabled
|
||||
},
|
||||
{
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"staticcheck"},
|
||||
},
|
||||
name: "disable only staticcheck",
|
||||
def: allMegacheckLinterNames,
|
||||
exp: []string{"gosimple", "typecheck", "unused"},
|
||||
},
|
||||
{
|
||||
name: "don't merge into megacheck",
|
||||
def: allMegacheckLinterNames,
|
||||
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
|
||||
},
|
||||
{
|
||||
name: "expand megacheck",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"megacheck"},
|
||||
},
|
||||
def: nil,
|
||||
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
|
||||
},
|
||||
{
|
||||
name: "don't disable anything",
|
||||
def: []string{"gofmt", "govet", "typecheck"},
|
||||
exp: []string{"gofmt", "govet", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "enable gosec by gas alias",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"gas"},
|
||||
},
|
||||
exp: []string{"gosec", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "enable gosec by primary name",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"gosec"},
|
||||
},
|
||||
exp: []string{"gosec", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "enable gosec by both names",
|
||||
cfg: config.Linters{
|
||||
Enable: []string{"gosec", "gas"},
|
||||
},
|
||||
exp: []string{"gosec", "typecheck"},
|
||||
},
|
||||
{
|
||||
name: "disable gosec by gas alias",
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"gas"},
|
||||
},
|
||||
def: []string{"gosec"},
|
||||
exp: []string{"typecheck"},
|
||||
},
|
||||
{
|
||||
name: "disable gosec by primary name",
|
||||
cfg: config.Linters{
|
||||
Disable: []string{"gosec"},
|
||||
},
|
||||
def: []string{"gosec"},
|
||||
exp: []string{"typecheck"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
m, err := NewManager(logutils.NewStderrLog("skip"), &config.Config{Linters: c.cfg}, NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
var defaultLinters []*linter.Config
|
||||
for _, ln := range c.def {
|
||||
lcs := m.GetLinterConfigs(ln)
|
||||
assert.NotNil(t, lcs, ln)
|
||||
defaultLinters = append(defaultLinters, lcs...)
|
||||
}
|
||||
|
||||
els := m.build(defaultLinters)
|
||||
var enabledLinters []string
|
||||
for ln, lc := range els {
|
||||
assert.Equal(t, ln, lc.Name())
|
||||
enabledLinters = append(enabledLinters, ln)
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, c.exp, enabledLinters)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestManager_combineGoAnalysisLinters(t *testing.T) {
|
||||
m, err := NewManager(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
foo := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
bar := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
version string
|
||||
expected string
|
||||
linters map[string]*linter.Config
|
||||
expected map[string]*linter.Config
|
||||
}{
|
||||
{
|
||||
desc: "patched version",
|
||||
version: "1.22.0",
|
||||
expected: "1.22",
|
||||
desc: "no combined, one linter",
|
||||
linters: map[string]*linter.Config{
|
||||
"foo": {
|
||||
Linter: foo,
|
||||
InPresets: []string{"A"},
|
||||
},
|
||||
},
|
||||
expected: map[string]*linter.Config{
|
||||
"foo": {
|
||||
Linter: foo,
|
||||
InPresets: []string{"A"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "minor version",
|
||||
version: "1.22",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "RC version",
|
||||
version: "1.22rc1",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "alpha version",
|
||||
version: "1.22alpha1",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "beta version",
|
||||
version: "1.22beta1",
|
||||
expected: "1.22",
|
||||
},
|
||||
{
|
||||
desc: "semver RC version",
|
||||
version: "1.22.0-rc1",
|
||||
expected: "1.22",
|
||||
desc: "combined, several linters",
|
||||
linters: map[string]*linter.Config{
|
||||
"foo": {
|
||||
Linter: foo,
|
||||
InPresets: []string{"A"},
|
||||
},
|
||||
"bar": {
|
||||
Linter: bar,
|
||||
InPresets: []string{"B"},
|
||||
},
|
||||
},
|
||||
expected: func() map[string]*linter.Config {
|
||||
mlConfig := &linter.Config{
|
||||
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{bar, foo}),
|
||||
InPresets: []string{"A", "B"},
|
||||
}
|
||||
|
||||
return map[string]*linter.Config{
|
||||
"goanalysis_metalinter": mlConfig.WithLoadForGoAnalysis(),
|
||||
}
|
||||
}(),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -49,8 +229,9 @@ func Test_trimGoVersion(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
version := trimGoVersion(test.version)
|
||||
assert.Equal(t, test.expected, version)
|
||||
m.combineGoAnalysisLinters(test.linters)
|
||||
|
||||
assert.Equal(t, test.expected, test.linters)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,29 @@ type Validator struct {
|
|||
}
|
||||
|
||||
func NewValidator(m *Manager) *Validator {
|
||||
return &Validator{
|
||||
m: m,
|
||||
return &Validator{m: m}
|
||||
}
|
||||
|
||||
// Validate validates the configuration by calling all other validators for different
|
||||
// sections in the configuration and then some additional linter validation functions.
|
||||
func (v Validator) Validate(cfg *config.Config) error {
|
||||
err := cfg.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validators := []func(cfg *config.Linters) error{
|
||||
v.validateLintersNames,
|
||||
v.validatePresets,
|
||||
}
|
||||
|
||||
for _, v := range validators {
|
||||
if err := v(&cfg.Linters); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Validator) validateLintersNames(cfg *config.Linters) error {
|
||||
|
@ -55,56 +75,3 @@ func (v Validator) validatePresets(cfg *config.Linters) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Validator) validateAllDisableEnableOptions(cfg *config.Linters) error {
|
||||
if cfg.EnableAll && cfg.DisableAll {
|
||||
return errors.New("--enable-all and --disable-all options must not be combined")
|
||||
}
|
||||
|
||||
if cfg.DisableAll {
|
||||
if len(cfg.Enable) == 0 && len(cfg.Presets) == 0 {
|
||||
return errors.New("all linters were disabled, but no one linter was enabled: must enable at least one")
|
||||
}
|
||||
|
||||
if len(cfg.Disable) != 0 {
|
||||
return fmt.Errorf("can't combine options --disable-all and --disable %s", cfg.Disable[0])
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.EnableAll && len(cfg.Enable) != 0 && !cfg.Fast {
|
||||
return fmt.Errorf("can't combine options --enable-all and --enable %s", cfg.Enable[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Validator) validateDisabledAndEnabledAtOneMoment(cfg *config.Linters) error {
|
||||
enabledLintersSet := map[string]bool{}
|
||||
for _, name := range cfg.Enable {
|
||||
enabledLintersSet[name] = true
|
||||
}
|
||||
|
||||
for _, name := range cfg.Disable {
|
||||
if enabledLintersSet[name] {
|
||||
return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Validator) validateEnabledDisabledLintersConfig(cfg *config.Linters) error {
|
||||
validators := []func(cfg *config.Linters) error{
|
||||
v.validateLintersNames,
|
||||
v.validatePresets,
|
||||
v.validateAllDisableEnableOptions,
|
||||
v.validateDisabledAndEnabledAtOneMoment,
|
||||
}
|
||||
for _, v := range validators {
|
||||
if err := v(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -53,72 +53,6 @@ var validatePresetsErrorTestCases = []validateErrorTestCase{
|
|||
},
|
||||
}
|
||||
|
||||
var validateDisabledAndEnabledAtOneMomentErrorTestCases = []validateErrorTestCase{
|
||||
{
|
||||
desc: "disable one linter of the enabled linters",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
Disable: []string{"dupl", "gosec", "nolintlint"},
|
||||
},
|
||||
expected: `linter "dupl" can't be disabled and enabled at one moment`,
|
||||
},
|
||||
{
|
||||
desc: "disable multiple enabled linters",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
},
|
||||
expected: `linter "dupl" can't be disabled and enabled at one moment`,
|
||||
},
|
||||
}
|
||||
|
||||
var validateAllDisableEnableOptionsErrorTestCases = []validateErrorTestCase{
|
||||
{
|
||||
desc: "enable-all and disable-all",
|
||||
cfg: &config.Linters{
|
||||
Enable: nil,
|
||||
EnableAll: true,
|
||||
Disable: nil,
|
||||
DisableAll: true,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "--enable-all and --disable-all options must not be combined",
|
||||
},
|
||||
{
|
||||
desc: "disable-all and disable no enable no preset",
|
||||
cfg: &config.Linters{
|
||||
Enable: nil,
|
||||
EnableAll: false,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
DisableAll: true,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "all linters were disabled, but no one linter was enabled: must enable at least one",
|
||||
},
|
||||
{
|
||||
desc: "disable-all and disable with enable",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"nolintlint"},
|
||||
EnableAll: false,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
DisableAll: true,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "can't combine options --disable-all and --disable dupl",
|
||||
},
|
||||
{
|
||||
desc: "enable-all and enable",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
EnableAll: true,
|
||||
Disable: nil,
|
||||
DisableAll: false,
|
||||
Fast: false,
|
||||
},
|
||||
expected: "can't combine options --enable-all and --enable dupl",
|
||||
},
|
||||
}
|
||||
|
||||
type validatorTestCase struct {
|
||||
desc string
|
||||
cfg *config.Linters
|
||||
|
@ -172,116 +106,43 @@ var validatePresetsTestCases = []validatorTestCase{
|
|||
},
|
||||
}
|
||||
|
||||
var validateDisabledAndEnabledAtOneMomentTestCases = []validatorTestCase{
|
||||
{
|
||||
desc: "2 different sets",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
Disable: []string{"goimports", "gosec", "nolintlint"},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "only enable",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"goimports", "gosec", "nolintlint"},
|
||||
Disable: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "only disable",
|
||||
cfg: &config.Linters{
|
||||
Enable: nil,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no sets",
|
||||
cfg: &config.Linters{
|
||||
Enable: nil,
|
||||
Disable: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
func TestValidator_Validate(t *testing.T) {
|
||||
m, err := NewManager(nil, nil, NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
var validateAllDisableEnableOptionsTestCases = []validatorTestCase{
|
||||
{
|
||||
desc: "nothing",
|
||||
cfg: &config.Linters{},
|
||||
},
|
||||
{
|
||||
desc: "enable and disable",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"goimports", "gosec", "nolintlint"},
|
||||
EnableAll: false,
|
||||
Disable: []string{"dupl", "gofmt", "misspell"},
|
||||
DisableAll: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "disable-all and enable",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"goimports", "gosec", "nolintlint"},
|
||||
EnableAll: false,
|
||||
Disable: nil,
|
||||
DisableAll: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "enable-all and disable",
|
||||
cfg: &config.Linters{
|
||||
Enable: nil,
|
||||
EnableAll: true,
|
||||
Disable: []string{"goimports", "gosec", "nolintlint"},
|
||||
DisableAll: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "enable-all and enable and fast",
|
||||
cfg: &config.Linters{
|
||||
Enable: []string{"dupl", "gofmt", "misspell"},
|
||||
EnableAll: true,
|
||||
Disable: nil,
|
||||
DisableAll: false,
|
||||
Fast: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestValidator_validateEnabledDisabledLintersConfig(t *testing.T) {
|
||||
v := NewValidator(NewManager(nil, nil))
|
||||
v := NewValidator(m)
|
||||
|
||||
var testCases []validatorTestCase
|
||||
testCases = append(testCases, validateLintersNamesTestCases...)
|
||||
testCases = append(testCases, validatePresetsTestCases...)
|
||||
testCases = append(testCases, validateDisabledAndEnabledAtOneMomentTestCases...)
|
||||
testCases = append(testCases, validateAllDisableEnableOptionsTestCases...)
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := v.validateEnabledDisabledLintersConfig(test.cfg)
|
||||
err := v.Validate(&config.Config{Linters: *test.cfg})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidator_validateEnabledDisabledLintersConfig_error(t *testing.T) {
|
||||
v := NewValidator(NewManager(nil, nil))
|
||||
func TestValidator_Validate_error(t *testing.T) {
|
||||
m, err := NewManager(nil, nil, NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
v := NewValidator(m)
|
||||
|
||||
var testCases []validateErrorTestCase
|
||||
testCases = append(testCases, validateLintersNamesErrorTestCases...)
|
||||
testCases = append(testCases, validatePresetsErrorTestCases...)
|
||||
testCases = append(testCases, validateDisabledAndEnabledAtOneMomentErrorTestCases...)
|
||||
testCases = append(testCases, validateAllDisableEnableOptionsErrorTestCases...)
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := v.validateEnabledDisabledLintersConfig(test.cfg)
|
||||
err := v.Validate(&config.Config{Linters: *test.cfg})
|
||||
require.Error(t, err)
|
||||
|
||||
require.EqualError(t, err, test.expected)
|
||||
|
@ -290,7 +151,10 @@ func TestValidator_validateEnabledDisabledLintersConfig_error(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestValidator_validateLintersNames(t *testing.T) {
|
||||
v := NewValidator(NewManager(nil, nil))
|
||||
m, err := NewManager(nil, nil, NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
v := NewValidator(m)
|
||||
|
||||
for _, test := range validateLintersNamesTestCases {
|
||||
test := test
|
||||
|
@ -304,7 +168,10 @@ func TestValidator_validateLintersNames(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestValidator_validateLintersNames_error(t *testing.T) {
|
||||
v := NewValidator(NewManager(nil, nil))
|
||||
m, err := NewManager(nil, nil, NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
v := NewValidator(m)
|
||||
|
||||
for _, test := range validateLintersNamesErrorTestCases {
|
||||
test := test
|
||||
|
@ -348,63 +215,3 @@ func TestValidator_validatePresets_error(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidator_validateDisabledAndEnabledAtOneMoment(t *testing.T) {
|
||||
v := NewValidator(nil)
|
||||
|
||||
for _, test := range validateDisabledAndEnabledAtOneMomentTestCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := v.validateDisabledAndEnabledAtOneMoment(test.cfg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidator_validateDisabledAndEnabledAtOneMoment_error(t *testing.T) {
|
||||
v := NewValidator(nil)
|
||||
|
||||
for _, test := range validateDisabledAndEnabledAtOneMomentErrorTestCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := v.validateDisabledAndEnabledAtOneMoment(test.cfg)
|
||||
require.Error(t, err)
|
||||
|
||||
require.EqualError(t, err, test.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidator_validateAllDisableEnableOptions(t *testing.T) {
|
||||
v := NewValidator(nil)
|
||||
|
||||
for _, test := range validateAllDisableEnableOptionsTestCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := v.validateAllDisableEnableOptions(test.cfg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidator_validateAllDisableEnableOptions_error(t *testing.T) {
|
||||
v := NewValidator(nil)
|
||||
|
||||
for _, test := range validateAllDisableEnableOptionsErrorTestCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := v.validateAllDisableEnableOptions(test.cfg)
|
||||
require.Error(t, err)
|
||||
|
||||
require.EqualError(t, err, test.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,7 @@ type Runner struct {
|
|||
Log logutils.Log
|
||||
}
|
||||
|
||||
func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
|
||||
es *lintersdb.EnabledSet,
|
||||
func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env,
|
||||
lineCache *fsutils.LineCache, fileCache *fsutils.FileCache,
|
||||
dbManager *lintersdb.Manager, pkgs []*gopackages.Package) (*Runner, error) {
|
||||
// Beware that some processors need to add the path prefix when working with paths
|
||||
|
@ -50,7 +49,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
enabledLinters, err := es.GetEnabledLintersMap()
|
||||
enabledLinters, err := dbManager.GetEnabledLintersMap()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get enabled linters: %w", err)
|
||||
}
|
||||
|
|
|
@ -34,7 +34,10 @@ func newNolint2FileIssue(line int) result.Issue {
|
|||
}
|
||||
|
||||
func newTestNolintProcessor(log logutils.Log) *Nolint {
|
||||
return NewNolint(log, lintersdb.NewManager(nil, nil), nil)
|
||||
dbManager, _ := lintersdb.NewManager(log, config.NewDefault(),
|
||||
lintersdb.NewPluginBuilder(log), lintersdb.NewLinterBuilder())
|
||||
|
||||
return NewNolint(log, dbManager, nil)
|
||||
}
|
||||
|
||||
func getMockLog() *logutils.MockLog {
|
||||
|
@ -283,11 +286,11 @@ func TestNolintUnused(t *testing.T) {
|
|||
enabledSetLog.On("Infof", "Active %d linters: %s", len(enabledLinters), enabledLinters)
|
||||
|
||||
cfg := &config.Config{Linters: config.Linters{DisableAll: true, Enable: enabledLinters}}
|
||||
dbManager := lintersdb.NewManager(cfg, nil)
|
||||
|
||||
enabledLintersSet := lintersdb.NewEnabledSet(dbManager, lintersdb.NewValidator(dbManager), enabledSetLog, cfg)
|
||||
dbManager, err := lintersdb.NewManager(enabledSetLog, cfg, lintersdb.NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
enabledLintersMap, err := enabledLintersSet.GetEnabledLintersMap()
|
||||
enabledLintersMap, err := dbManager.GetEnabledLintersMap()
|
||||
require.NoError(t, err)
|
||||
|
||||
return NewNolint(log, dbManager, enabledLintersMap)
|
||||
|
@ -347,11 +350,13 @@ func TestNolintUnused(t *testing.T) {
|
|||
enabledSetLog.On("Infof", "Active %d linters: %s", 1, []string{"nolintlint"})
|
||||
|
||||
cfg := &config.Config{Linters: config.Linters{DisableAll: true, Enable: []string{"nolintlint"}}}
|
||||
dbManager := lintersdb.NewManager(cfg, nil)
|
||||
enabledLintersSet := lintersdb.NewEnabledSet(dbManager, lintersdb.NewValidator(dbManager), enabledSetLog, cfg)
|
||||
|
||||
enabledLintersMap, err := enabledLintersSet.GetEnabledLintersMap()
|
||||
dbManager, err := lintersdb.NewManager(enabledSetLog, cfg, lintersdb.NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
enabledLintersMap, err := dbManager.GetEnabledLintersMap()
|
||||
require.NoError(t, err)
|
||||
|
||||
p := NewNolint(log, dbManager, enabledLintersMap)
|
||||
defer p.Finish()
|
||||
|
||||
|
|
|
@ -204,8 +204,11 @@ func getDefaultExclusions() string {
|
|||
}
|
||||
|
||||
func getLintersListMarkdown(enabled bool) string {
|
||||
dbManager, _ := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
|
||||
lcs := dbManager.GetAllSupportedLinterConfigs()
|
||||
|
||||
var neededLcs []*linter.Config
|
||||
lcs := lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs()
|
||||
for _, lc := range lcs {
|
||||
if lc.Internal {
|
||||
continue
|
||||
|
@ -322,8 +325,9 @@ type authorDetails struct {
|
|||
|
||||
func getThanksList() string {
|
||||
addedAuthors := map[string]*authorDetails{}
|
||||
dbManager, _ := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
|
||||
for _, lc := range lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs() {
|
||||
for _, lc := range dbManager.GetAllSupportedLinterConfigs() {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
@ -491,7 +495,8 @@ func extractExampleSnippets(example []byte) (*SettingSnippets, error) {
|
|||
}
|
||||
|
||||
func getLintersSettingSections(node, nextNode *yaml.Node) (string, error) {
|
||||
lcs := lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs()
|
||||
dbManager, _ := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
lcs := dbManager.GetAllSupportedLinterConfigs()
|
||||
|
||||
var lintersDesc = make(map[string]string)
|
||||
for _, lc := range lcs {
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
"github.com/golangci/golangci-lint/test/testshared"
|
||||
)
|
||||
|
@ -29,7 +31,7 @@ func TestEnabledLinters(t *testing.T) {
|
|||
disable:
|
||||
- govet
|
||||
`,
|
||||
enabledLinters: getEnabledByDefaultFastLintersExcept("govet"),
|
||||
enabledLinters: getEnabledByDefaultFastLintersExcept(t, "govet"),
|
||||
},
|
||||
{
|
||||
name: "enable revive in config",
|
||||
|
@ -38,12 +40,12 @@ func TestEnabledLinters(t *testing.T) {
|
|||
enable:
|
||||
- revive
|
||||
`,
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith("revive"),
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(t, "revive"),
|
||||
},
|
||||
{
|
||||
name: "disable govet in cmd",
|
||||
args: []string{"-Dgovet"},
|
||||
enabledLinters: getEnabledByDefaultFastLintersExcept("govet"),
|
||||
enabledLinters: getEnabledByDefaultFastLintersExcept(t, "govet"),
|
||||
},
|
||||
{
|
||||
name: "enable gofmt in cmd and enable revive in config",
|
||||
|
@ -53,7 +55,7 @@ func TestEnabledLinters(t *testing.T) {
|
|||
enable:
|
||||
- revive
|
||||
`,
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith("revive", "gofmt"),
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(t, "revive", "gofmt"),
|
||||
},
|
||||
{
|
||||
name: "fast option in config",
|
||||
|
@ -61,7 +63,7 @@ func TestEnabledLinters(t *testing.T) {
|
|||
linters:
|
||||
fast: true
|
||||
`,
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(),
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(t),
|
||||
noImplicitFast: true,
|
||||
},
|
||||
{
|
||||
|
@ -70,13 +72,13 @@ func TestEnabledLinters(t *testing.T) {
|
|||
linters:
|
||||
fast: false
|
||||
`,
|
||||
enabledLinters: getEnabledByDefaultLinters(),
|
||||
enabledLinters: getEnabledByDefaultLinters(t),
|
||||
noImplicitFast: true,
|
||||
},
|
||||
{
|
||||
name: "set fast option in command-line",
|
||||
args: []string{"--fast"},
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(),
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(t),
|
||||
noImplicitFast: true,
|
||||
},
|
||||
{
|
||||
|
@ -86,7 +88,7 @@ func TestEnabledLinters(t *testing.T) {
|
|||
fast: false
|
||||
`,
|
||||
args: []string{"--fast"},
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(),
|
||||
enabledLinters: getEnabledByDefaultFastLintersWith(t),
|
||||
noImplicitFast: true,
|
||||
},
|
||||
{
|
||||
|
@ -96,13 +98,13 @@ func TestEnabledLinters(t *testing.T) {
|
|||
fast: true
|
||||
`,
|
||||
args: []string{"--fast=false"},
|
||||
enabledLinters: getEnabledByDefaultLinters(),
|
||||
enabledLinters: getEnabledByDefaultLinters(t),
|
||||
noImplicitFast: true,
|
||||
},
|
||||
{
|
||||
name: "fast option combined with enable and enable-all",
|
||||
args: []string{"--enable-all", "--fast", "--enable=unused"},
|
||||
enabledLinters: getAllFastLintersWith("unused"),
|
||||
enabledLinters: getAllFastLintersWith(t, "unused"),
|
||||
noImplicitFast: true,
|
||||
},
|
||||
}
|
||||
|
@ -127,7 +129,7 @@ func TestEnabledLinters(t *testing.T) {
|
|||
Runner().
|
||||
Run()
|
||||
|
||||
sort.StringSlice(c.enabledLinters).Sort()
|
||||
sort.Strings(c.enabledLinters)
|
||||
|
||||
r.ExpectOutputContains(fmt.Sprintf("Active %d linters: [%s]",
|
||||
len(c.enabledLinters), strings.Join(c.enabledLinters, " ")))
|
||||
|
@ -135,8 +137,12 @@ func TestEnabledLinters(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func getEnabledByDefaultFastLintersExcept(except ...string) []string {
|
||||
m := lintersdb.NewManager(nil, nil)
|
||||
func getEnabledByDefaultFastLintersExcept(t *testing.T, except ...string) []string {
|
||||
t.Helper()
|
||||
|
||||
m, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
ebdl := m.GetAllEnabledByDefaultLinters()
|
||||
var ret []string
|
||||
for _, lc := range ebdl {
|
||||
|
@ -152,8 +158,13 @@ func getEnabledByDefaultFastLintersExcept(except ...string) []string {
|
|||
return ret
|
||||
}
|
||||
|
||||
func getAllFastLintersWith(with ...string) []string {
|
||||
linters := lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs()
|
||||
func getAllFastLintersWith(t *testing.T, with ...string) []string {
|
||||
t.Helper()
|
||||
|
||||
dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
linters := dbManager.GetAllSupportedLinterConfigs()
|
||||
ret := append([]string{}, with...)
|
||||
for _, lc := range linters {
|
||||
if lc.IsSlowLinter() {
|
||||
|
@ -165,8 +176,13 @@ func getAllFastLintersWith(with ...string) []string {
|
|||
return ret
|
||||
}
|
||||
|
||||
func getEnabledByDefaultLinters() []string {
|
||||
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
|
||||
func getEnabledByDefaultLinters(t *testing.T) []string {
|
||||
t.Helper()
|
||||
|
||||
dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
ebdl := dbManager.GetAllEnabledByDefaultLinters()
|
||||
var ret []string
|
||||
for _, lc := range ebdl {
|
||||
if lc.Internal {
|
||||
|
@ -179,8 +195,13 @@ func getEnabledByDefaultLinters() []string {
|
|||
return ret
|
||||
}
|
||||
|
||||
func getEnabledByDefaultFastLintersWith(with ...string) []string {
|
||||
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
|
||||
func getEnabledByDefaultFastLintersWith(t *testing.T, with ...string) []string {
|
||||
t.Helper()
|
||||
|
||||
dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
require.NoError(t, err)
|
||||
|
||||
ebdl := dbManager.GetAllEnabledByDefaultLinters()
|
||||
ret := append([]string{}, with...)
|
||||
for _, lc := range ebdl {
|
||||
if lc.IsSlowLinter() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue