Skip to content

Commit d06d6e5

Browse files
committed
feat: add inters.exclusions.paths-except
1 parent 499997d commit d06d6e5

File tree

4 files changed

+128
-24
lines changed

4 files changed

+128
-24
lines changed

jsonschema/golangci.next.jsonschema.json

+6
Original file line numberDiff line numberDiff line change
@@ -3946,6 +3946,12 @@
39463946
"items": {
39473947
"type": "string"
39483948
}
3949+
},
3950+
"paths-except": {
3951+
"type": "array",
3952+
"items": {
3953+
"type": "string"
3954+
}
39493955
}
39503956
}
39513957
}

pkg/config/linters_exclusions.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ const (
1414
const excludeRuleMinConditionsCount = 2
1515

1616
type LinterExclusions struct {
17-
Generated string `mapstructure:"generated"`
18-
WarnUnused bool `mapstructure:"warn-unused"`
19-
Default []string `mapstructure:"default"`
20-
Rules []ExcludeRule `mapstructure:"rules"`
21-
Paths []string `mapstructure:"paths"`
17+
Generated string `mapstructure:"generated"`
18+
WarnUnused bool `mapstructure:"warn-unused"`
19+
Default []string `mapstructure:"default"`
20+
Rules []ExcludeRule `mapstructure:"rules"`
21+
Paths []string `mapstructure:"paths"`
22+
PathsExcept []string `mapstructure:"paths-except"`
2223
}
2324

2425
func (e *LinterExclusions) Validate() error {

pkg/result/processors/exclusion_paths.go

+34-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import (
1313
var _ Processor = (*ExclusionPaths)(nil)
1414

1515
type ExclusionPaths struct {
16-
patterns []*regexp.Regexp
16+
pathPatterns []*regexp.Regexp
17+
pathExceptPatterns []*regexp.Regexp
1718

1819
warnUnused bool
1920
skippedPathCounter map[*regexp.Regexp]int
@@ -24,7 +25,7 @@ type ExclusionPaths struct {
2425
func NewExclusionPaths(log logutils.Log, cfg *config.LinterExclusions) (*ExclusionPaths, error) {
2526
var counter = make(map[*regexp.Regexp]int)
2627

27-
var patternsRe []*regexp.Regexp
28+
var pathPatterns []*regexp.Regexp
2829
for _, p := range cfg.Paths {
2930
p = fsutils.NormalizePathInRegex(p)
3031

@@ -33,12 +34,25 @@ func NewExclusionPaths(log logutils.Log, cfg *config.LinterExclusions) (*Exclusi
3334
return nil, fmt.Errorf("can't compile regexp %q: %w", p, err)
3435
}
3536

36-
patternsRe = append(patternsRe, patternRe)
37+
pathPatterns = append(pathPatterns, patternRe)
3738
counter[patternRe] = 0
3839
}
3940

41+
var pathExceptPatterns []*regexp.Regexp
42+
for _, p := range cfg.PathsExcept {
43+
p = fsutils.NormalizePathInRegex(p)
44+
45+
patternRe, err := regexp.Compile(p)
46+
if err != nil {
47+
return nil, fmt.Errorf("can't compile regexp %q: %w", p, err)
48+
}
49+
50+
pathExceptPatterns = append(pathExceptPatterns, patternRe)
51+
}
52+
4053
return &ExclusionPaths{
41-
patterns: patternsRe,
54+
pathPatterns: pathPatterns,
55+
pathExceptPatterns: pathExceptPatterns,
4256
warnUnused: cfg.WarnUnused,
4357
skippedPathCounter: counter,
4458
log: log.Child(logutils.DebugKeyExclusionPaths),
@@ -50,7 +64,7 @@ func (*ExclusionPaths) Name() string {
5064
}
5165

5266
func (p *ExclusionPaths) Process(issues []result.Issue) ([]result.Issue, error) {
53-
if len(p.patterns) == 0 {
67+
if len(p.pathPatterns) == 0 && len(p.pathExceptPatterns) == 0 {
5468
return issues, nil
5569
}
5670

@@ -68,12 +82,25 @@ func (p *ExclusionPaths) Finish() {
6882
}
6983

7084
func (p *ExclusionPaths) shouldPassIssue(issue *result.Issue) bool {
71-
for _, pattern := range p.patterns {
85+
for _, pattern := range p.pathPatterns {
7286
if pattern.MatchString(issue.RelativePath) {
7387
p.skippedPathCounter[pattern] += 1
7488
return false
7589
}
7690
}
7791

78-
return true
92+
if len(p.pathExceptPatterns) == 0 {
93+
return true
94+
}
95+
96+
matched := false
97+
for _, pattern := range p.pathExceptPatterns {
98+
if !pattern.MatchString(issue.RelativePath) {
99+
continue
100+
}
101+
102+
matched = true
103+
}
104+
105+
return !matched
79106
}

pkg/result/processors/exclusion_paths_test.go

+82-12
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ func TestExclusionPaths_Process(t *testing.T) {
1818

1919
testCases := []struct {
2020
desc string
21-
patterns []string
21+
cfg *config.LinterExclusions
2222
issues []result.Issue
2323
expected []result.Issue
2424
}{
2525
{
26-
desc: "word",
27-
patterns: []string{"foo"},
26+
desc: "paths: word",
27+
cfg: &config.LinterExclusions{
28+
Paths: []string{"foo"},
29+
},
2830
issues: []result.Issue{
2931
{RelativePath: "foo.go"},
3032
{RelativePath: "foo/foo.go"},
@@ -37,8 +39,10 @@ func TestExclusionPaths_Process(t *testing.T) {
3739
},
3840
},
3941
{
40-
desc: "begin with word",
41-
patterns: []string{"^foo"},
42+
desc: "paths: begin with word",
43+
cfg: &config.LinterExclusions{
44+
Paths: []string{"^foo"},
45+
},
4246
issues: []result.Issue{
4347
{RelativePath: filepath.FromSlash("foo.go")},
4448
{RelativePath: filepath.FromSlash("foo/foo.go")},
@@ -52,8 +56,10 @@ func TestExclusionPaths_Process(t *testing.T) {
5256
},
5357
},
5458
{
55-
desc: "directory begin with word",
56-
patterns: []string{"^foo/"},
59+
desc: "paths: directory begin with word",
60+
cfg: &config.LinterExclusions{
61+
Paths: []string{"^foo/"},
62+
},
5763
issues: []result.Issue{
5864
{RelativePath: filepath.FromSlash("foo.go")},
5965
{RelativePath: filepath.FromSlash("foo/foo.go")},
@@ -68,17 +74,21 @@ func TestExclusionPaths_Process(t *testing.T) {
6874
},
6975
},
7076
{
71-
desc: "same suffix with unconstrained expression",
72-
patterns: []string{"c/d.go"},
77+
desc: "paths: same suffix with unconstrained expression",
78+
cfg: &config.LinterExclusions{
79+
Paths: []string{"c/d.go"},
80+
},
7381
issues: []result.Issue{
7482
{RelativePath: filepath.FromSlash("a/b/c/d.go")},
7583
{RelativePath: filepath.FromSlash("c/d.go")},
7684
},
7785
expected: []result.Issue{},
7886
},
7987
{
80-
desc: "same suffix with constrained expression",
81-
patterns: []string{"^c/d.go"},
88+
desc: "paths: same suffix with constrained expression",
89+
cfg: &config.LinterExclusions{
90+
Paths: []string{"^c/d.go"},
91+
},
8292
issues: []result.Issue{
8393
{RelativePath: filepath.FromSlash("a/b/c/d.go")},
8494
{RelativePath: filepath.FromSlash("c/d.go")},
@@ -87,13 +97,73 @@ func TestExclusionPaths_Process(t *testing.T) {
8797
{RelativePath: filepath.FromSlash("a/b/c/d.go")},
8898
},
8999
},
100+
{
101+
desc: "pathsExcept",
102+
cfg: &config.LinterExclusions{
103+
PathsExcept: []string{`^base/c/.*$`},
104+
},
105+
issues: []result.Issue{
106+
{RelativePath: filepath.FromSlash("base/a/file.go")},
107+
{RelativePath: filepath.FromSlash("base/b/file.go")},
108+
{RelativePath: filepath.FromSlash("base/c/file.go")},
109+
{RelativePath: filepath.FromSlash("base/c/a/file.go")},
110+
{RelativePath: filepath.FromSlash("base/c/b/file.go")},
111+
{RelativePath: filepath.FromSlash("base/d/file.go")},
112+
},
113+
expected: []result.Issue{
114+
{RelativePath: filepath.FromSlash("base/a/file.go")},
115+
{RelativePath: filepath.FromSlash("base/b/file.go")},
116+
{RelativePath: filepath.FromSlash("base/d/file.go")},
117+
},
118+
},
119+
{
120+
desc: "pathsExcept: multiple patterns",
121+
cfg: &config.LinterExclusions{
122+
PathsExcept: []string{
123+
`^base/z/.*$`,
124+
`^base/c/.*$`,
125+
},
126+
},
127+
issues: []result.Issue{
128+
{RelativePath: filepath.FromSlash("base/a/file.go")},
129+
{RelativePath: filepath.FromSlash("base/b/file.go")},
130+
{RelativePath: filepath.FromSlash("base/c/file.go")},
131+
{RelativePath: filepath.FromSlash("base/c/a/file.go")},
132+
{RelativePath: filepath.FromSlash("base/c/b/file.go")},
133+
{RelativePath: filepath.FromSlash("base/d/file.go")},
134+
},
135+
expected: []result.Issue{
136+
{RelativePath: filepath.FromSlash("base/a/file.go")},
137+
{RelativePath: filepath.FromSlash("base/b/file.go")},
138+
{RelativePath: filepath.FromSlash("base/d/file.go")},
139+
},
140+
},
141+
{
142+
desc: "pathsExcept and paths",
143+
cfg: &config.LinterExclusions{
144+
Paths: []string{"^base/b/"},
145+
PathsExcept: []string{`^base/c/.*$`},
146+
},
147+
issues: []result.Issue{
148+
{RelativePath: filepath.FromSlash("base/a/file.go")},
149+
{RelativePath: filepath.FromSlash("base/b/file.go")},
150+
{RelativePath: filepath.FromSlash("base/c/file.go")},
151+
{RelativePath: filepath.FromSlash("base/c/a/file.go")},
152+
{RelativePath: filepath.FromSlash("base/c/b/file.go")},
153+
{RelativePath: filepath.FromSlash("base/d/file.go")},
154+
},
155+
expected: []result.Issue{
156+
{RelativePath: filepath.FromSlash("base/a/file.go")},
157+
{RelativePath: filepath.FromSlash("base/d/file.go")},
158+
},
159+
},
90160
}
91161

92162
for _, test := range testCases {
93163
t.Run(test.desc, func(t *testing.T) {
94164
t.Parallel()
95165

96-
p, err := NewExclusionPaths(logger, &config.LinterExclusions{Paths: test.patterns})
166+
p, err := NewExclusionPaths(logger, test.cfg)
97167
require.NoError(t, err)
98168

99169
processedIssues := process(t, p, test.issues...)

0 commit comments

Comments
 (0)