Skip to content

Commit 94d2d80

Browse files
authored
Add gomoddirectives linter. (#1817)
1 parent c11228b commit 94d2d80

File tree

7 files changed

+97
-1
lines changed

7 files changed

+97
-1
lines changed

.golangci.example.yml

+10
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,16 @@ linters-settings:
449449
servingv1: knative.dev/serving/pkg/apis/serving/v1
450450
# using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package
451451
autoscalingv1alpha1: knative.dev/serving/pkg/apis/autoscaling/v1alpha1
452+
gomoddirectives:
453+
# Allow local `replace` directives. Default is false.
454+
replace-local: false
455+
# List of allowed `replace` directives. Default is empty.
456+
replace-allow-list:
457+
- launchpad.net/gocheck
458+
# Allow to not explain why the version has been retracted in the `retract` directives. Default is false.
459+
retract-allow-no-explanation: false
460+
# Forbid the use of the `exclude` directives. Default is false.
461+
exclude-forbidden: false
452462

453463
# The custom section can be used to define linter plugins to be loaded at runtime. See README doc
454464
# for more info.

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ require (
4141
github.com/kulti/thelper v0.4.0
4242
github.com/kunwardeep/paralleltest v1.0.2
4343
github.com/kyoh86/exportloopref v0.1.8
44+
github.com/ldez/gomoddirectives v0.2.1
4445
github.com/maratori/testpackage v1.0.1
4546
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // v1.0
4647
github.com/mattn/go-colorable v0.1.8

go.sum

+4-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/config.go

+8
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ type LintersSettings struct {
276276
Predeclared PredeclaredSettings
277277
Cyclop Cyclop
278278
ImportAs ImportAsSettings
279+
GoModDirectives GoModDirectivesSettings
279280

280281
Custom map[string]CustomLinterSettings
281282
}
@@ -464,6 +465,13 @@ type Cyclop struct {
464465

465466
type ImportAsSettings map[string]string
466467

468+
type GoModDirectivesSettings struct {
469+
ReplaceAllowList []string `mapstructure:"replace-allow-list"`
470+
ReplaceLocal bool `mapstructure:"replace-local"`
471+
ExcludeForbidden bool `mapstructure:"exclude-forbidden"`
472+
RetractAllowNoExplanation bool `mapstructure:"retract-allow-no-explanation"`
473+
}
474+
467475
var defaultLintersSettings = LintersSettings{
468476
Lll: LllSettings{
469477
LineLength: 120,

pkg/golinters/gomoddirectives.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package golinters
2+
3+
import (
4+
"sync"
5+
6+
"github.com/ldez/gomoddirectives"
7+
"golang.org/x/tools/go/analysis"
8+
9+
"github.com/golangci/golangci-lint/pkg/config"
10+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
11+
"github.com/golangci/golangci-lint/pkg/lint/linter"
12+
"github.com/golangci/golangci-lint/pkg/result"
13+
)
14+
15+
const goModDirectivesName = "gomoddirectives"
16+
17+
// NewGoModDirectives returns a new gomoddirectives linter.
18+
func NewGoModDirectives(settings *config.GoModDirectivesSettings) *goanalysis.Linter {
19+
var issues []goanalysis.Issue
20+
var once sync.Once
21+
22+
var opts gomoddirectives.Options
23+
if settings != nil {
24+
opts.ReplaceAllowLocal = settings.ReplaceLocal
25+
opts.ReplaceAllowList = settings.ReplaceAllowList
26+
opts.RetractAllowNoExplanation = settings.RetractAllowNoExplanation
27+
opts.ExcludeForbidden = settings.ExcludeForbidden
28+
}
29+
30+
analyzer := &analysis.Analyzer{
31+
Name: goanalysis.TheOnlyAnalyzerName,
32+
Doc: goanalysis.TheOnlyanalyzerDoc,
33+
}
34+
35+
return goanalysis.NewLinter(
36+
goModDirectivesName,
37+
"Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.",
38+
[]*analysis.Analyzer{analyzer},
39+
nil,
40+
).WithContextSetter(func(lintCtx *linter.Context) {
41+
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
42+
once.Do(func() {
43+
results, err := gomoddirectives.Analyze(opts)
44+
if err != nil {
45+
lintCtx.Log.Warnf("running %s failed: %s: "+
46+
"if you are not using go modules it is suggested to disable this linter", goModDirectivesName, err)
47+
return
48+
}
49+
50+
for _, p := range results {
51+
issues = append(issues, goanalysis.NewIssue(&result.Issue{
52+
FromLinter: goModDirectivesName,
53+
Pos: p.Start,
54+
Text: p.Reason,
55+
}, pass))
56+
}
57+
})
58+
59+
return nil, nil
60+
}
61+
}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
62+
return issues
63+
}).WithLoadMode(goanalysis.LoadModeSyntax)
64+
}

pkg/lint/lintersdb/manager.go

+6
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
100100
var reviveCfg *config.ReviveSettings
101101
var cyclopCfg *config.Cyclop
102102
var importAsCfg *config.ImportAsSettings
103+
var goModDirectivesCfg *config.GoModDirectivesSettings
103104
if m.cfg != nil {
104105
govetCfg = &m.cfg.LintersSettings.Govet
105106
testpackageCfg = &m.cfg.LintersSettings.Testpackage
@@ -112,6 +113,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
112113
reviveCfg = &m.cfg.LintersSettings.Revive
113114
cyclopCfg = &m.cfg.LintersSettings.Cyclop
114115
importAsCfg = &m.cfg.LintersSettings.ImportAs
116+
goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives
115117
}
116118
const megacheckName = "megacheck"
117119
lcs := []*linter.Config{
@@ -394,6 +396,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
394396
WithPresets(linter.PresetStyle).
395397
WithLoadForGoAnalysis().
396398
WithURL("https://github.com/gostaticanalysis/forcetypeassert"),
399+
linter.NewConfig(golinters.NewGoModDirectives(goModDirectivesCfg)).
400+
WithPresets(linter.PresetStyle).
401+
WithLoadForGoAnalysis().
402+
WithURL("https://github.com/ldez/gomoddirectives"),
397403

398404
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
399405
linter.NewConfig(golinters.NewNoLintLint()).

pkg/result/processors/autogenerated_exclude.go

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ func (p *AutogeneratedExclude) shouldPassIssue(i *result.Issue) (bool, error) {
5353
return true, nil
5454
}
5555

56+
if filepath.Base(i.FilePath()) == "go.mod" {
57+
return true, nil
58+
}
59+
5660
if isSpecialAutogeneratedFile(i.FilePath()) {
5761
return false, nil
5862
}

0 commit comments

Comments
 (0)