mirror of
https://github.com/scratchfoundation/golangci-lint.git
synced 2025-07-29 07:30:34 -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>
|
</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
|
## Load Packages
|
||||||
|
|
||||||
Loading packages is listing all packages and their recursive dependencies for analysis.
|
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
|
Also, depending on the enabled linters set some parsing of the source code can be performed at this step.
|
||||||
at this step.
|
|
||||||
|
|
||||||
Packages loading starts here:
|
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:
|
First, we need to find all enabled linters. All linters are registered here:
|
||||||
|
|
||||||
```go title=pkg/lint/lintersdb/manager.go
|
```go title=pkg/lint/lintersdb/builder_linter.go
|
||||||
func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
func (b LinterBuilder) Build(cfg *config.Config) []*linter.Config {
|
||||||
// ...
|
// ...
|
||||||
linters = append(linters,
|
return []*linter.Config{
|
||||||
// ...
|
// ...
|
||||||
linter.NewConfig(golinters.NewBodyclose()).
|
linter.NewConfig(golinters.NewBodyclose()).
|
||||||
WithSince("v1.18.0").
|
WithSince("v1.18.0").
|
||||||
|
@ -97,26 +104,25 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||||
WithPresets(linter.PresetBugs, linter.PresetMetaLinter).
|
WithPresets(linter.PresetBugs, linter.PresetMetaLinter).
|
||||||
WithAlternativeNames("vet", "vetshadow").
|
WithAlternativeNames("vet", "vetshadow").
|
||||||
WithURL("https://pkg.go.dev/cmd/vet"),
|
WithURL("https://pkg.go.dev/cmd/vet"),
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
// ...
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We filter requested in config and command-line linters in `EnabledSet`:
|
We filter requested in config and command-line linters in `EnabledSet`:
|
||||||
|
|
||||||
```go title=pkg/lint/lintersdb/enabled_set.go
|
```go title=pkg/lint/lintersdb/manager.go
|
||||||
func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error)
|
func (m *Manager) GetEnabledLintersMap() (map[string]*linter.Config, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
We merge enabled linters into one `MetaLinter` to improve execution time if we can:
|
We merge enabled linters into one `MetaLinter` to improve execution time if we can:
|
||||||
|
|
||||||
```go title=pkg/lint/lintersdb/enabled_set.go
|
```go titlepkg/lint/lintersdb/manager.go
|
||||||
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters
|
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters into a fewer number of linters.
|
||||||
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
|
// E.g. some go/analysis linters can be optimized into one metalinter for data reuse and speed up.
|
||||||
// one metalinter for data reuse and speed up.
|
func (m *Manager) GetOptimizedLinters() ([]*linter.Config, error) {
|
||||||
func (es EnabledSet) 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.
|
Currently, all linters except `unused` can be merged into this meta linter.
|
||||||
The `unused` isn't merged because it has high memory usage.
|
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`.
|
Linters execution starts in `runAnalyzers`.
|
||||||
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
|
It's the most complex part of the `golangci-lint`.
|
||||||
to reduce memory usage. Also, it sets all heavyweight data to `nil` as becomes unneeded to save memory.
|
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
|
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.
|
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.
|
Look at other linters in this directory.
|
||||||
Implement linter integration and check that test passes.
|
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
|
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)
|
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 function `GetAllSupportedLinterConfigs`.
|
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)
|
- 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.
|
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).
|
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,
|
Args: cobra.NoArgs,
|
||||||
ValidArgsFunction: cobra.NoFileCompletions,
|
ValidArgsFunction: cobra.NoFileCompletions,
|
||||||
Run: c.execute,
|
Run: c.execute,
|
||||||
PreRun: c.preRun,
|
PreRunE: c.preRunE,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,10 +50,18 @@ func newHelpCommand(logger logutils.Log) *helpCommand {
|
||||||
return c
|
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.
|
// The command doesn't depend on the real configuration.
|
||||||
// It just needs the list of all plugins and all presets.
|
// 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) {
|
func (c *helpCommand) execute(_ *cobra.Command, _ []string) {
|
||||||
|
|
|
@ -27,8 +27,7 @@ type lintersCommand struct {
|
||||||
|
|
||||||
log logutils.Log
|
log logutils.Log
|
||||||
|
|
||||||
dbManager *lintersdb.Manager
|
dbManager *lintersdb.Manager
|
||||||
enabledLintersSet *lintersdb.EnabledSet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLintersCommand(logger logutils.Log, cfg *config.Config) *lintersCommand {
|
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)
|
return fmt.Errorf("can't load config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.dbManager = lintersdb.NewManager(c.cfg, c.log)
|
dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), c.cfg,
|
||||||
c.enabledLintersSet = lintersdb.NewEnabledSet(c.dbManager,
|
lintersdb.NewPluginBuilder(c.log), lintersdb.NewLinterBuilder())
|
||||||
lintersdb.NewValidator(c.dbManager), c.log.Child(logutils.DebugKeyLintersDB), c.cfg)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.dbManager = dbManager
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *lintersCommand) execute(_ *cobra.Command, _ []string) error {
|
func (c *lintersCommand) execute(_ *cobra.Command, _ []string) error {
|
||||||
enabledLintersMap, err := c.enabledLintersSet.GetEnabledLintersMap()
|
enabledLintersMap, err := c.dbManager.GetEnabledLintersMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't get enabled linters: %w", err)
|
return fmt.Errorf("can't get enabled linters: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,7 @@ type runCommand struct {
|
||||||
|
|
||||||
buildInfo BuildInfo
|
buildInfo BuildInfo
|
||||||
|
|
||||||
dbManager *lintersdb.Manager
|
dbManager *lintersdb.Manager
|
||||||
enabledLintersSet *lintersdb.EnabledSet
|
|
||||||
|
|
||||||
log logutils.Log
|
log logutils.Log
|
||||||
debugf logutils.DebugFunc
|
debugf logutils.DebugFunc
|
||||||
|
@ -171,9 +170,13 @@ func (c *runCommand) persistentPostRunE(_ *cobra.Command, _ []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *runCommand) preRunE(_ *cobra.Command, _ []string) error {
|
func (c *runCommand) preRunE(_ *cobra.Command, _ []string) error {
|
||||||
c.dbManager = lintersdb.NewManager(c.cfg, c.log)
|
dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), c.cfg,
|
||||||
c.enabledLintersSet = lintersdb.NewEnabledSet(c.dbManager,
|
lintersdb.NewPluginBuilder(c.log), lintersdb.NewLinterBuilder())
|
||||||
lintersdb.NewValidator(c.dbManager), c.log.Child(logutils.DebugKeyLintersDB), c.cfg)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.dbManager = dbManager
|
||||||
|
|
||||||
c.goenv = goutil.NewEnv(c.log.Child(logutils.DebugKeyGoEnv))
|
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) {
|
func (c *runCommand) runAnalysis(ctx context.Context, args []string) ([]result.Issue, error) {
|
||||||
c.cfg.Run.Args = args
|
c.cfg.Run.Args = args
|
||||||
|
|
||||||
lintersToRun, err := c.enabledLintersSet.GetOptimizedLinters()
|
lintersToRun, err := c.dbManager.GetOptimizedLinters()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
enabledLintersMap, err := c.enabledLintersSet.GetEnabledLintersMap()
|
enabledLintersMap, err := c.dbManager.GetEnabledLintersMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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)
|
lintCtx.Log = c.log.Child(logutils.DebugKeyLintersContext)
|
||||||
|
|
||||||
runner, err := lint.NewRunner(c.cfg, c.log.Child(logutils.DebugKeyRunner),
|
runner, err := lint.NewRunner(c.log.Child(logutils.DebugKeyRunner),
|
||||||
c.goenv, c.enabledLintersSet, c.lineCache, c.fileCache, c.dbManager, lintCtx.Packages)
|
c.cfg, c.goenv, c.lineCache, c.fileCache, c.dbManager, lintCtx.Packages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ type versionInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionOptions struct {
|
type versionOptions struct {
|
||||||
Format string `mapstructure:"format"`
|
Format string
|
||||||
Debug bool `mapstructure:"debug"`
|
Debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionCommand struct {
|
type versionCommand struct {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
hcversion "github.com/hashicorp/go-version"
|
hcversion "github.com/hashicorp/go-version"
|
||||||
|
@ -33,18 +32,16 @@ func (c *Config) GetConfigDir() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Validate() error {
|
func (c *Config) Validate() error {
|
||||||
for i, rule := range c.Issues.ExcludeRules {
|
validators := []func() error{
|
||||||
if err := rule.Validate(); err != nil {
|
c.Issues.Validate,
|
||||||
return fmt.Errorf("error in exclude rule #%d: %w", i, err)
|
c.Severity.Validate,
|
||||||
}
|
c.LintersSettings.Validate,
|
||||||
|
c.Linters.Validate,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.Severity.Rules) > 0 && c.Severity.Default == "" {
|
for _, v := range validators {
|
||||||
return errors.New("can't set severity rule option: no default severity defined")
|
if err := v(); err != nil {
|
||||||
}
|
return err
|
||||||
for i, rule := range c.Severity.Rules {
|
|
||||||
if err := rule.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("error in severity rule #%d: %w", i, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,3 +87,22 @@ func detectGoVersion() string {
|
||||||
|
|
||||||
return "1.17"
|
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"`
|
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 {
|
type ExcludeRule struct {
|
||||||
BaseRule `mapstructure:",squash"`
|
BaseRule `mapstructure:",squash"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type Linters struct {
|
type Linters struct {
|
||||||
Enable []string
|
Enable []string
|
||||||
Disable []string
|
Disable []string
|
||||||
|
@ -9,3 +14,52 @@ type Linters struct {
|
||||||
|
|
||||||
Presets []string
|
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
|
Custom map[string]CustomLinterSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *LintersSettings) Validate() error {
|
||||||
|
return s.Govet.Validate()
|
||||||
|
}
|
||||||
|
|
||||||
type AsasalintSettings struct {
|
type AsasalintSettings struct {
|
||||||
Exclude []string `mapstructure:"exclude"`
|
Exclude []string `mapstructure:"exclude"`
|
||||||
UseBuiltinExclusions bool `mapstructure:"use-builtin-exclusions"`
|
UseBuiltinExclusions bool `mapstructure:"use-builtin-exclusions"`
|
||||||
|
@ -606,15 +610,14 @@ type GovetSettings struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *GovetSettings) Validate() error {
|
func (cfg *GovetSettings) Validate() error {
|
||||||
// TODO(ldez) need to be move into the linter file.
|
|
||||||
if cfg.EnableAll && cfg.DisableAll {
|
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 {
|
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 {
|
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
|
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.applyStringSliceHack()
|
||||||
|
|
||||||
|
l.handleGoVersion()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Loader) handleGoVersion() {
|
||||||
if l.cfg.Run.Go == "" {
|
if l.cfg.Run.Go == "" {
|
||||||
l.cfg.Run.Go = detectGoVersion()
|
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 {
|
func (l *Loader) setConfigFile() error {
|
||||||
|
@ -161,11 +187,7 @@ func (l *Loader) parseConfig() error {
|
||||||
// Load configuration from flags only.
|
// Load configuration from flags only.
|
||||||
err = l.viper.Unmarshal(l.cfg)
|
err = l.viper.Unmarshal(l.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("can't unmarshal config by viper (flags): %w", err)
|
||||||
}
|
|
||||||
|
|
||||||
if err = l.cfg.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("can't validate config: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -181,11 +203,7 @@ func (l *Loader) parseConfig() error {
|
||||||
|
|
||||||
// Load configuration from all sources (flags, file).
|
// Load configuration from all sources (flags, file).
|
||||||
if err := l.viper.Unmarshal(l.cfg, fileDecoderHook()); err != nil {
|
if err := l.viper.Unmarshal(l.cfg, fileDecoderHook()); err != nil {
|
||||||
return fmt.Errorf("can't unmarshal config by viper: %w", err)
|
return fmt.Errorf("can't unmarshal config by viper (flags, file): %w", err)
|
||||||
}
|
|
||||||
|
|
||||||
if err := l.cfg.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("can't validate config: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.cfg.InternalTest { // just for testing purposes: to detect config file usage
|
if l.cfg.InternalTest { // just for testing purposes: to detect config file usage
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
const severityRuleMinConditionsCount = 1
|
const severityRuleMinConditionsCount = 1
|
||||||
|
|
||||||
type Severity struct {
|
type Severity struct {
|
||||||
|
@ -8,6 +13,20 @@ type Severity struct {
|
||||||
Rules []SeverityRule `mapstructure:"rules"`
|
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 {
|
type SeverityRule struct {
|
||||||
BaseRule `mapstructure:",squash"`
|
BaseRule `mapstructure:",squash"`
|
||||||
Severity string
|
Severity string
|
||||||
|
|
|
@ -139,11 +139,6 @@ var (
|
||||||
func NewGovet(settings *config.GovetSettings) *goanalysis.Linter {
|
func NewGovet(settings *config.GovetSettings) *goanalysis.Linter {
|
||||||
var conf map[string]map[string]any
|
var conf map[string]map[string]any
|
||||||
if settings != nil {
|
if settings != nil {
|
||||||
err := settings.Validate()
|
|
||||||
if err != nil {
|
|
||||||
linterLogger.Fatalf("govet configuration: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf = settings.Settings
|
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/config"
|
||||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AnalyzerPlugin interface {
|
type AnalyzerPlugin interface {
|
||||||
GetAnalyzers() []*analysis.Analyzer
|
GetAnalyzers() []*analysis.Analyzer
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCustomLinterConfigs loads private linters that are specified in the golangci config file.
|
// PluginBuilder builds the custom linters (plugins) based on the configuration.
|
||||||
func (m *Manager) getCustomLinterConfigs() []*linter.Config {
|
type PluginBuilder struct {
|
||||||
if m.cfg == nil || m.log == nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var linters []*linter.Config
|
var linters []*linter.Config
|
||||||
|
|
||||||
for name, settings := range m.cfg.LintersSettings.Custom {
|
for name, settings := range cfg.LintersSettings.Custom {
|
||||||
lc, err := m.loadCustomLinterConfig(name, settings)
|
lc, err := b.loadConfig(cfg, name, settings)
|
||||||
if err != nil {
|
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 {
|
} else {
|
||||||
linters = append(linters, lc)
|
linters = append(linters, lc)
|
||||||
}
|
}
|
||||||
|
@ -37,15 +48,15 @@ func (m *Manager) getCustomLinterConfigs() []*linter.Config {
|
||||||
return linters
|
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.
|
// Private linters are dynamically loaded from .so plugin files.
|
||||||
func (m *Manager) loadCustomLinterConfig(name string, settings config.CustomLinterSettings) (*linter.Config, error) {
|
func (b *PluginBuilder) loadConfig(cfg *config.Config, name string, settings config.CustomLinterSettings) (*linter.Config, error) {
|
||||||
analyzers, err := m.getAnalyzerPlugin(settings.Path, settings.Settings)
|
analyzers, err := b.getAnalyzerPlugin(cfg, settings.Path, settings.Settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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).
|
customLinter := goanalysis.NewLinter(name, settings.Description, analyzers, nil).
|
||||||
WithLoadMode(goanalysis.LoadModeTypesInfo)
|
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.
|
// and returns the 'AnalyzerPlugin' interface implemented by the private plugin.
|
||||||
// An error is returned if the private linter cannot be loaded
|
// An error is returned if the private linter cannot be loaded
|
||||||
// or the linter does not implement the AnalyzerPlugin interface.
|
// 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) {
|
if !filepath.IsAbs(path) {
|
||||||
// resolve non-absolute paths relative to config file's directory
|
// 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)
|
plug, err := plugin.Open(path)
|
||||||
|
@ -74,7 +85,7 @@ func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Anal
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
analyzers, err := m.lookupPlugin(plug, settings)
|
analyzers, err := b.lookupPlugin(plug, settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("lookup plugin %s: %w", path, err)
|
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
|
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")
|
symbol, err := plug.Lookup("New")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
analyzers, errP := m.lookupAnalyzerPlugin(plug)
|
analyzers, errP := b.lookupAnalyzerPlugin(plug)
|
||||||
if errP != nil {
|
if errP != nil {
|
||||||
return nil, errors.Join(err, errP)
|
return nil, errors.Join(err, errP)
|
||||||
}
|
}
|
||||||
|
@ -102,13 +113,13 @@ func (m *Manager) lookupPlugin(plug *plugin.Plugin, settings any) ([]*analysis.A
|
||||||
return constructor(settings)
|
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")
|
symbol, err := plug.Lookup("AnalyzerPlugin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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")
|
"https://golangci-lint.run/contributing/new-linters/#create-a-plugin")
|
||||||
|
|
||||||
analyzerPlugin, ok := symbol.(AnalyzerPlugin)
|
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"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"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 {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
version string
|
linters map[string]*linter.Config
|
||||||
expected string
|
expected map[string]*linter.Config
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "patched version",
|
desc: "no combined, one linter",
|
||||||
version: "1.22.0",
|
linters: map[string]*linter.Config{
|
||||||
expected: "1.22",
|
"foo": {
|
||||||
|
Linter: foo,
|
||||||
|
InPresets: []string{"A"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: map[string]*linter.Config{
|
||||||
|
"foo": {
|
||||||
|
Linter: foo,
|
||||||
|
InPresets: []string{"A"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "minor version",
|
desc: "combined, several linters",
|
||||||
version: "1.22",
|
linters: map[string]*linter.Config{
|
||||||
expected: "1.22",
|
"foo": {
|
||||||
},
|
Linter: foo,
|
||||||
{
|
InPresets: []string{"A"},
|
||||||
desc: "RC version",
|
},
|
||||||
version: "1.22rc1",
|
"bar": {
|
||||||
expected: "1.22",
|
Linter: bar,
|
||||||
},
|
InPresets: []string{"B"},
|
||||||
{
|
},
|
||||||
desc: "alpha version",
|
},
|
||||||
version: "1.22alpha1",
|
expected: func() map[string]*linter.Config {
|
||||||
expected: "1.22",
|
mlConfig := &linter.Config{
|
||||||
},
|
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{bar, foo}),
|
||||||
{
|
InPresets: []string{"A", "B"},
|
||||||
desc: "beta version",
|
}
|
||||||
version: "1.22beta1",
|
|
||||||
expected: "1.22",
|
return map[string]*linter.Config{
|
||||||
},
|
"goanalysis_metalinter": mlConfig.WithLoadForGoAnalysis(),
|
||||||
{
|
}
|
||||||
desc: "semver RC version",
|
}(),
|
||||||
version: "1.22.0-rc1",
|
|
||||||
expected: "1.22",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,8 +229,9 @@ func Test_trimGoVersion(t *testing.T) {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
version := trimGoVersion(test.version)
|
m.combineGoAnalysisLinters(test.linters)
|
||||||
assert.Equal(t, test.expected, version)
|
|
||||||
|
assert.Equal(t, test.expected, test.linters)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,29 @@ type Validator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewValidator(m *Manager) *Validator {
|
func NewValidator(m *Manager) *Validator {
|
||||||
return &Validator{
|
return &Validator{m: m}
|
||||||
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 {
|
func (v Validator) validateLintersNames(cfg *config.Linters) error {
|
||||||
|
@ -55,56 +75,3 @@ func (v Validator) validatePresets(cfg *config.Linters) error {
|
||||||
|
|
||||||
return nil
|
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 {
|
type validatorTestCase struct {
|
||||||
desc string
|
desc string
|
||||||
cfg *config.Linters
|
cfg *config.Linters
|
||||||
|
@ -172,116 +106,43 @@ var validatePresetsTestCases = []validatorTestCase{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var validateDisabledAndEnabledAtOneMomentTestCases = []validatorTestCase{
|
func TestValidator_Validate(t *testing.T) {
|
||||||
{
|
m, err := NewManager(nil, nil, NewLinterBuilder())
|
||||||
desc: "2 different sets",
|
require.NoError(t, err)
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var validateAllDisableEnableOptionsTestCases = []validatorTestCase{
|
v := NewValidator(m)
|
||||||
{
|
|
||||||
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))
|
|
||||||
|
|
||||||
var testCases []validatorTestCase
|
var testCases []validatorTestCase
|
||||||
testCases = append(testCases, validateLintersNamesTestCases...)
|
testCases = append(testCases, validateLintersNamesTestCases...)
|
||||||
testCases = append(testCases, validatePresetsTestCases...)
|
testCases = append(testCases, validatePresetsTestCases...)
|
||||||
testCases = append(testCases, validateDisabledAndEnabledAtOneMomentTestCases...)
|
|
||||||
testCases = append(testCases, validateAllDisableEnableOptionsTestCases...)
|
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
test := test
|
test := test
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
err := v.validateEnabledDisabledLintersConfig(test.cfg)
|
err := v.Validate(&config.Config{Linters: *test.cfg})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidator_validateEnabledDisabledLintersConfig_error(t *testing.T) {
|
func TestValidator_Validate_error(t *testing.T) {
|
||||||
v := NewValidator(NewManager(nil, nil))
|
m, err := NewManager(nil, nil, NewLinterBuilder())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
v := NewValidator(m)
|
||||||
|
|
||||||
var testCases []validateErrorTestCase
|
var testCases []validateErrorTestCase
|
||||||
testCases = append(testCases, validateLintersNamesErrorTestCases...)
|
testCases = append(testCases, validateLintersNamesErrorTestCases...)
|
||||||
testCases = append(testCases, validatePresetsErrorTestCases...)
|
testCases = append(testCases, validatePresetsErrorTestCases...)
|
||||||
testCases = append(testCases, validateDisabledAndEnabledAtOneMomentErrorTestCases...)
|
|
||||||
testCases = append(testCases, validateAllDisableEnableOptionsErrorTestCases...)
|
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
test := test
|
test := test
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
err := v.validateEnabledDisabledLintersConfig(test.cfg)
|
err := v.Validate(&config.Config{Linters: *test.cfg})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
require.EqualError(t, err, test.expected)
|
require.EqualError(t, err, test.expected)
|
||||||
|
@ -290,7 +151,10 @@ func TestValidator_validateEnabledDisabledLintersConfig_error(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidator_validateLintersNames(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 {
|
for _, test := range validateLintersNamesTestCases {
|
||||||
test := test
|
test := test
|
||||||
|
@ -304,7 +168,10 @@ func TestValidator_validateLintersNames(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidator_validateLintersNames_error(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 {
|
for _, test := range validateLintersNamesErrorTestCases {
|
||||||
test := test
|
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
|
Log logutils.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
|
func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env,
|
||||||
es *lintersdb.EnabledSet,
|
|
||||||
lineCache *fsutils.LineCache, fileCache *fsutils.FileCache,
|
lineCache *fsutils.LineCache, fileCache *fsutils.FileCache,
|
||||||
dbManager *lintersdb.Manager, pkgs []*gopackages.Package) (*Runner, error) {
|
dbManager *lintersdb.Manager, pkgs []*gopackages.Package) (*Runner, error) {
|
||||||
// Beware that some processors need to add the path prefix when working with paths
|
// 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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
enabledLinters, err := es.GetEnabledLintersMap()
|
enabledLinters, err := dbManager.GetEnabledLintersMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get enabled linters: %w", err)
|
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 {
|
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 {
|
func getMockLog() *logutils.MockLog {
|
||||||
|
@ -283,11 +286,11 @@ func TestNolintUnused(t *testing.T) {
|
||||||
enabledSetLog.On("Infof", "Active %d linters: %s", len(enabledLinters), enabledLinters)
|
enabledSetLog.On("Infof", "Active %d linters: %s", len(enabledLinters), enabledLinters)
|
||||||
|
|
||||||
cfg := &config.Config{Linters: config.Linters{DisableAll: true, Enable: 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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return NewNolint(log, dbManager, enabledLintersMap)
|
return NewNolint(log, dbManager, enabledLintersMap)
|
||||||
|
@ -347,11 +350,13 @@ func TestNolintUnused(t *testing.T) {
|
||||||
enabledSetLog.On("Infof", "Active %d linters: %s", 1, []string{"nolintlint"})
|
enabledSetLog.On("Infof", "Active %d linters: %s", 1, []string{"nolintlint"})
|
||||||
|
|
||||||
cfg := &config.Config{Linters: config.Linters{DisableAll: true, Enable: []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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
enabledLintersMap, err := dbManager.GetEnabledLintersMap()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
p := NewNolint(log, dbManager, enabledLintersMap)
|
p := NewNolint(log, dbManager, enabledLintersMap)
|
||||||
defer p.Finish()
|
defer p.Finish()
|
||||||
|
|
||||||
|
|
|
@ -204,8 +204,11 @@ func getDefaultExclusions() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLintersListMarkdown(enabled bool) string {
|
func getLintersListMarkdown(enabled bool) string {
|
||||||
|
dbManager, _ := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||||
|
|
||||||
|
lcs := dbManager.GetAllSupportedLinterConfigs()
|
||||||
|
|
||||||
var neededLcs []*linter.Config
|
var neededLcs []*linter.Config
|
||||||
lcs := lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs()
|
|
||||||
for _, lc := range lcs {
|
for _, lc := range lcs {
|
||||||
if lc.Internal {
|
if lc.Internal {
|
||||||
continue
|
continue
|
||||||
|
@ -322,8 +325,9 @@ type authorDetails struct {
|
||||||
|
|
||||||
func getThanksList() string {
|
func getThanksList() string {
|
||||||
addedAuthors := map[string]*authorDetails{}
|
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 {
|
if lc.Internal {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -491,7 +495,8 @@ func extractExampleSnippets(example []byte) (*SettingSnippets, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLintersSettingSections(node, nextNode *yaml.Node) (string, 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)
|
var lintersDesc = make(map[string]string)
|
||||||
for _, lc := range lcs {
|
for _, lc := range lcs {
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||||
"github.com/golangci/golangci-lint/test/testshared"
|
"github.com/golangci/golangci-lint/test/testshared"
|
||||||
)
|
)
|
||||||
|
@ -29,7 +31,7 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
disable:
|
disable:
|
||||||
- govet
|
- govet
|
||||||
`,
|
`,
|
||||||
enabledLinters: getEnabledByDefaultFastLintersExcept("govet"),
|
enabledLinters: getEnabledByDefaultFastLintersExcept(t, "govet"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "enable revive in config",
|
name: "enable revive in config",
|
||||||
|
@ -38,12 +40,12 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
enable:
|
enable:
|
||||||
- revive
|
- revive
|
||||||
`,
|
`,
|
||||||
enabledLinters: getEnabledByDefaultFastLintersWith("revive"),
|
enabledLinters: getEnabledByDefaultFastLintersWith(t, "revive"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disable govet in cmd",
|
name: "disable govet in cmd",
|
||||||
args: []string{"-Dgovet"},
|
args: []string{"-Dgovet"},
|
||||||
enabledLinters: getEnabledByDefaultFastLintersExcept("govet"),
|
enabledLinters: getEnabledByDefaultFastLintersExcept(t, "govet"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "enable gofmt in cmd and enable revive in config",
|
name: "enable gofmt in cmd and enable revive in config",
|
||||||
|
@ -53,7 +55,7 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
enable:
|
enable:
|
||||||
- revive
|
- revive
|
||||||
`,
|
`,
|
||||||
enabledLinters: getEnabledByDefaultFastLintersWith("revive", "gofmt"),
|
enabledLinters: getEnabledByDefaultFastLintersWith(t, "revive", "gofmt"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "fast option in config",
|
name: "fast option in config",
|
||||||
|
@ -61,7 +63,7 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
linters:
|
linters:
|
||||||
fast: true
|
fast: true
|
||||||
`,
|
`,
|
||||||
enabledLinters: getEnabledByDefaultFastLintersWith(),
|
enabledLinters: getEnabledByDefaultFastLintersWith(t),
|
||||||
noImplicitFast: true,
|
noImplicitFast: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -70,13 +72,13 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
linters:
|
linters:
|
||||||
fast: false
|
fast: false
|
||||||
`,
|
`,
|
||||||
enabledLinters: getEnabledByDefaultLinters(),
|
enabledLinters: getEnabledByDefaultLinters(t),
|
||||||
noImplicitFast: true,
|
noImplicitFast: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "set fast option in command-line",
|
name: "set fast option in command-line",
|
||||||
args: []string{"--fast"},
|
args: []string{"--fast"},
|
||||||
enabledLinters: getEnabledByDefaultFastLintersWith(),
|
enabledLinters: getEnabledByDefaultFastLintersWith(t),
|
||||||
noImplicitFast: true,
|
noImplicitFast: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -86,7 +88,7 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
fast: false
|
fast: false
|
||||||
`,
|
`,
|
||||||
args: []string{"--fast"},
|
args: []string{"--fast"},
|
||||||
enabledLinters: getEnabledByDefaultFastLintersWith(),
|
enabledLinters: getEnabledByDefaultFastLintersWith(t),
|
||||||
noImplicitFast: true,
|
noImplicitFast: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -96,13 +98,13 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
fast: true
|
fast: true
|
||||||
`,
|
`,
|
||||||
args: []string{"--fast=false"},
|
args: []string{"--fast=false"},
|
||||||
enabledLinters: getEnabledByDefaultLinters(),
|
enabledLinters: getEnabledByDefaultLinters(t),
|
||||||
noImplicitFast: true,
|
noImplicitFast: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "fast option combined with enable and enable-all",
|
name: "fast option combined with enable and enable-all",
|
||||||
args: []string{"--enable-all", "--fast", "--enable=unused"},
|
args: []string{"--enable-all", "--fast", "--enable=unused"},
|
||||||
enabledLinters: getAllFastLintersWith("unused"),
|
enabledLinters: getAllFastLintersWith(t, "unused"),
|
||||||
noImplicitFast: true,
|
noImplicitFast: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -127,7 +129,7 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
Runner().
|
Runner().
|
||||||
Run()
|
Run()
|
||||||
|
|
||||||
sort.StringSlice(c.enabledLinters).Sort()
|
sort.Strings(c.enabledLinters)
|
||||||
|
|
||||||
r.ExpectOutputContains(fmt.Sprintf("Active %d linters: [%s]",
|
r.ExpectOutputContains(fmt.Sprintf("Active %d linters: [%s]",
|
||||||
len(c.enabledLinters), strings.Join(c.enabledLinters, " ")))
|
len(c.enabledLinters), strings.Join(c.enabledLinters, " ")))
|
||||||
|
@ -135,8 +137,12 @@ func TestEnabledLinters(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEnabledByDefaultFastLintersExcept(except ...string) []string {
|
func getEnabledByDefaultFastLintersExcept(t *testing.T, except ...string) []string {
|
||||||
m := lintersdb.NewManager(nil, nil)
|
t.Helper()
|
||||||
|
|
||||||
|
m, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
ebdl := m.GetAllEnabledByDefaultLinters()
|
ebdl := m.GetAllEnabledByDefaultLinters()
|
||||||
var ret []string
|
var ret []string
|
||||||
for _, lc := range ebdl {
|
for _, lc := range ebdl {
|
||||||
|
@ -152,8 +158,13 @@ func getEnabledByDefaultFastLintersExcept(except ...string) []string {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllFastLintersWith(with ...string) []string {
|
func getAllFastLintersWith(t *testing.T, with ...string) []string {
|
||||||
linters := lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs()
|
t.Helper()
|
||||||
|
|
||||||
|
dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
linters := dbManager.GetAllSupportedLinterConfigs()
|
||||||
ret := append([]string{}, with...)
|
ret := append([]string{}, with...)
|
||||||
for _, lc := range linters {
|
for _, lc := range linters {
|
||||||
if lc.IsSlowLinter() {
|
if lc.IsSlowLinter() {
|
||||||
|
@ -165,8 +176,13 @@ func getAllFastLintersWith(with ...string) []string {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEnabledByDefaultLinters() []string {
|
func getEnabledByDefaultLinters(t *testing.T) []string {
|
||||||
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
|
t.Helper()
|
||||||
|
|
||||||
|
dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ebdl := dbManager.GetAllEnabledByDefaultLinters()
|
||||||
var ret []string
|
var ret []string
|
||||||
for _, lc := range ebdl {
|
for _, lc := range ebdl {
|
||||||
if lc.Internal {
|
if lc.Internal {
|
||||||
|
@ -179,8 +195,13 @@ func getEnabledByDefaultLinters() []string {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEnabledByDefaultFastLintersWith(with ...string) []string {
|
func getEnabledByDefaultFastLintersWith(t *testing.T, with ...string) []string {
|
||||||
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
|
t.Helper()
|
||||||
|
|
||||||
|
dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ebdl := dbManager.GetAllEnabledByDefaultLinters()
|
||||||
ret := append([]string{}, with...)
|
ret := append([]string{}, with...)
|
||||||
for _, lc := range ebdl {
|
for _, lc := range ebdl {
|
||||||
if lc.IsSlowLinter() {
|
if lc.IsSlowLinter() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue