diff --git a/.golangci.example.yml b/.golangci.example.yml index 8c55ddb27301..f81c646f8e63 100644 --- a/.golangci.example.yml +++ b/.golangci.example.yml @@ -449,6 +449,16 @@ linters-settings: servingv1: knative.dev/serving/pkg/apis/serving/v1 # using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package autoscalingv1alpha1: knative.dev/serving/pkg/apis/autoscaling/v1alpha1 + gomoddirectives: + # Allow local `replace` directives. Default is false. + replace-local: false + # List of allowed `replace` directives. Default is empty. + replace-allow-list: + - launchpad.net/gocheck + # Allow to not explain why the version has been retracted in the `retract` directives. Default is false. + retract-allow-no-explanation: false + # Forbid the use of the `exclude` directives. Default is false. + exclude-forbidden: false # The custom section can be used to define linter plugins to be loaded at runtime. See README doc # for more info. diff --git a/go.mod b/go.mod index 1e76ab4e7472..5ad5edfafb18 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/kulti/thelper v0.4.0 github.com/kunwardeep/paralleltest v1.0.2 github.com/kyoh86/exportloopref v0.1.8 + github.com/ldez/gomoddirectives v0.2.1 github.com/maratori/testpackage v1.0.1 github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // v1.0 github.com/mattn/go-colorable v0.1.8 diff --git a/go.sum b/go.sum index 9571cb8a4ef3..c703d6f5024a 100644 --- a/go.sum +++ b/go.sum @@ -246,6 +246,8 @@ github.com/kunwardeep/paralleltest v1.0.2 h1:/jJRv0TiqPoEy/Y8dQxCFJhD56uS/pnvtat github.com/kunwardeep/paralleltest v1.0.2/go.mod h1:ZPqNm1fVHPllh5LPVujzbVz1JN2GhLxSfY+oqUsvG30= github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/ldez/gomoddirectives v0.2.1 h1:9pAcW9KRZW7HQjFwbozNvFMcNVwdCBufU7os5QUwLIY= +github.com/ldez/gomoddirectives v0.2.1/go.mod h1:sGicqkRgBOg//JfpXwkB9Hj0X5RyJ7mlACM5B9f6Me4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= @@ -477,8 +479,9 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/pkg/config/config.go b/pkg/config/config.go index 202ae6bc44cb..8cd9fe85a8a9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -276,6 +276,7 @@ type LintersSettings struct { Predeclared PredeclaredSettings Cyclop Cyclop ImportAs ImportAsSettings + GoModDirectives GoModDirectivesSettings Custom map[string]CustomLinterSettings } @@ -464,6 +465,13 @@ type Cyclop struct { type ImportAsSettings map[string]string +type GoModDirectivesSettings struct { + ReplaceAllowList []string `mapstructure:"replace-allow-list"` + ReplaceLocal bool `mapstructure:"replace-local"` + ExcludeForbidden bool `mapstructure:"exclude-forbidden"` + RetractAllowNoExplanation bool `mapstructure:"retract-allow-no-explanation"` +} + var defaultLintersSettings = LintersSettings{ Lll: LllSettings{ LineLength: 120, diff --git a/pkg/golinters/gomoddirectives.go b/pkg/golinters/gomoddirectives.go new file mode 100644 index 000000000000..40d3bf786e09 --- /dev/null +++ b/pkg/golinters/gomoddirectives.go @@ -0,0 +1,64 @@ +package golinters + +import ( + "sync" + + "github.com/ldez/gomoddirectives" + "golang.org/x/tools/go/analysis" + + "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/result" +) + +const goModDirectivesName = "gomoddirectives" + +// NewGoModDirectives returns a new gomoddirectives linter. +func NewGoModDirectives(settings *config.GoModDirectivesSettings) *goanalysis.Linter { + var issues []goanalysis.Issue + var once sync.Once + + var opts gomoddirectives.Options + if settings != nil { + opts.ReplaceAllowLocal = settings.ReplaceLocal + opts.ReplaceAllowList = settings.ReplaceAllowList + opts.RetractAllowNoExplanation = settings.RetractAllowNoExplanation + opts.ExcludeForbidden = settings.ExcludeForbidden + } + + analyzer := &analysis.Analyzer{ + Name: goanalysis.TheOnlyAnalyzerName, + Doc: goanalysis.TheOnlyanalyzerDoc, + } + + return goanalysis.NewLinter( + goModDirectivesName, + "Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.", + []*analysis.Analyzer{analyzer}, + nil, + ).WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { + once.Do(func() { + results, err := gomoddirectives.Analyze(opts) + if err != nil { + lintCtx.Log.Warnf("running %s failed: %s: "+ + "if you are not using go modules it is suggested to disable this linter", goModDirectivesName, err) + return + } + + for _, p := range results { + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + FromLinter: goModDirectivesName, + Pos: p.Start, + Text: p.Reason, + }, pass)) + } + }) + + return nil, nil + } + }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return issues + }).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 086309567b25..5f1b1f0f5a45 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -100,6 +100,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { var reviveCfg *config.ReviveSettings var cyclopCfg *config.Cyclop var importAsCfg *config.ImportAsSettings + var goModDirectivesCfg *config.GoModDirectivesSettings if m.cfg != nil { govetCfg = &m.cfg.LintersSettings.Govet testpackageCfg = &m.cfg.LintersSettings.Testpackage @@ -112,6 +113,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { reviveCfg = &m.cfg.LintersSettings.Revive cyclopCfg = &m.cfg.LintersSettings.Cyclop importAsCfg = &m.cfg.LintersSettings.ImportAs + goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives } const megacheckName = "megacheck" lcs := []*linter.Config{ @@ -394,6 +396,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetStyle). WithLoadForGoAnalysis(). WithURL("https://github.com/gostaticanalysis/forcetypeassert"), + linter.NewConfig(golinters.NewGoModDirectives(goModDirectivesCfg)). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ldez/gomoddirectives"), // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives linter.NewConfig(golinters.NewNoLintLint()). diff --git a/pkg/result/processors/autogenerated_exclude.go b/pkg/result/processors/autogenerated_exclude.go index 7894bbbcf613..57388f64fa48 100644 --- a/pkg/result/processors/autogenerated_exclude.go +++ b/pkg/result/processors/autogenerated_exclude.go @@ -53,6 +53,10 @@ func (p *AutogeneratedExclude) shouldPassIssue(i *result.Issue) (bool, error) { return true, nil } + if filepath.Base(i.FilePath()) == "go.mod" { + return true, nil + } + if isSpecialAutogeneratedFile(i.FilePath()) { return false, nil }