Skip to content

Commit

Permalink
feat: new linter exclusions system (#5339)
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez authored Jan 28, 2025
1 parent e84aa52 commit 98c110b
Show file tree
Hide file tree
Showing 75 changed files with 1,556 additions and 697 deletions.
12 changes: 11 additions & 1 deletion .golangci.next.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ linters-settings:
failOn: dsl,import
# Comma-separated list of file paths containing ruleguard rules.
# If a path is relative, it is relative to the directory where the golangci-lint command is executed.
# The special '${configDir}' variable is substituted with the absolute directory containing the golangci config file.
# The special '${configDir}' variable is substituted with the absolute directory containing the golangci-lint config file.
# Glob patterns such as 'rules-*.go' may be specified.
# Default: ""
rules: '${configDir}/ruleguard/rules-*.go,${configDir}/myrule1.go'
Expand Down Expand Up @@ -4141,6 +4141,16 @@ run:
# Default: 1m
timeout: 5m

# The mode used to evaluate relative paths.
# It's used by exclusions, Go plugins, and some linters.
# The value can be:
# - `gomod`: the paths will be relative to the directory of the `go.mod` file.
# - `gitroot`: the paths will be relative to the git root (the parent directory of `.git`).
# - `cfg`: the paths will be relative to the configuration file.
# - `wd` (NOT recommended): the paths will be relative to the place where golangci-lint is run.
# Default: wd
relative-path-mode: gomod

# Exit code when at least one issue was found.
# Default: 1
issues-exit-code: 2
Expand Down
2 changes: 1 addition & 1 deletion .golangci.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,7 @@ linters-settings:
failOn: dsl,import
# Comma-separated list of file paths containing ruleguard rules.
# If a path is relative, it is relative to the directory where the golangci-lint command is executed.
# The special '${configDir}' variable is substituted with the absolute directory containing the golangci config file.
# The special '${configDir}' variable is substituted with the absolute directory containing the golangci-lint config file.
# Glob patterns such as 'rules-*.go' may be specified.
# Default: ""
rules: '${configDir}/ruleguard/rules-*.go,${configDir}/myrule1.go'
Expand Down
32 changes: 0 additions & 32 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,6 @@ issues:
- mnd
- lll

# The logic of creating a linter is similar between linters, it's not duplication.
- path: pkg/golinters
linters:
- dupl

# Deprecated configuration options.
- path: pkg/commands/run.go
linters: [staticcheck]
text: "SA1019: c.cfg.Run.ShowStats is deprecated: use Output.ShowStats instead."

# Deprecated linter options.
- path: pkg/golinters/errcheck/errcheck.go
linters: [staticcheck]
Expand All @@ -180,39 +170,17 @@ issues:
- path: pkg/goformatters/gci/gci.go
linters: [staticcheck]
text: "SA1019: settings.LocalPrefixes is deprecated: use Sections instead."
- path: pkg/golinters/mnd/mnd.go
linters: [staticcheck]
text: "SA1019: settings.Settings is deprecated: use root level settings instead."
- path: pkg/golinters/mnd/mnd.go
linters: [staticcheck]
text: "SA1019: config.GoMndSettings is deprecated: use MndSettings."

# Related to `run.go`, it cannot be removed.
- path: pkg/golinters/gofumpt/gofumpt.go
linters: [staticcheck]
text: "SA1019: settings.LangVersion is deprecated: use the global `run.go` instead."
- path: pkg/golinters/internal/staticcheck_common.go
linters: [staticcheck]
text: "SA1019: settings.GoVersion is deprecated: use the global `run.go` instead."
- path: pkg/lint/lintersdb/manager.go
linters: [staticcheck]
text: "SA1019: (.+).(GoVersion|LangVersion) is deprecated: use the global `run.go` instead."

# Based on existing code, the modifications should be limited to make maintenance easier.
- path: pkg/golinters/unused/unused.go
linters: [gocritic]
text: "rangeValCopy: each iteration copies 160 bytes \\(consider pointers or indexing\\)"

# Related to file sizes.
- path: pkg/goanalysis/runner_loadingpackage.go
linters: [gosec]
text: "G115: integer overflow conversion uintptr -> int"

# Related to PID.
- path: test/bench/bench_test.go
linters: [gosec]
text: "G115: integer overflow conversion int -> int32"

# Related to the result of computation but divided multiple times by 1024.
- path: test/bench/bench_test.go
linters: [gosec]
Expand Down
84 changes: 84 additions & 0 deletions jsonschema/golangci.next.jsonschema.json
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,14 @@
"type": "string"
}
]
},
"relative-path-modes": {
"enum": [
"gomod",
"gitroot",
"cfg",
"wd"
]
}
},
"type": "object",
Expand Down Expand Up @@ -506,6 +514,12 @@
"description": "Targeted Go version.",
"type": "string",
"default": "1.17"
},
"relative-path-mode": {
"description": "The mode used to evaluate relative paths.",
"type": "string",
"$ref": "#/definitions/relative-path-modes",
"default": "wd"
}
}
},
Expand Down Expand Up @@ -3872,6 +3886,76 @@
"description": "Enable run of fast linters.",
"type": "boolean",
"default": false
},
"exclusions":{
"type": "object",
"additionalProperties": false,
"properties": {
"generated": {
"enum": ["strict", "lax", "disable"],
"default": "lax"
},
"warn-unused": {
"type": "boolean",
"default": false
},
"default": {
"type": "array",
"items": {
"enum": [
"comments",
"stdErrorHandling",
"commonFalsePositives",
"legacy"
]
}
},
"rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
"path-except": {
"type": "string"
},
"linters": {
"type": "array",
"items": {
"$ref": "#/definitions/linters"
}
},
"text": {
"type": "string"
},
"source": {
"type": "string"
}
},
"anyOf": [
{ "required": ["path"] },
{ "required": ["path-except"] },
{ "required": ["linters"] },
{ "required": ["text"] },
{ "required": ["source"] }
]
}
},
"paths": {
"type": "array",
"items": {
"type": "string"
}
},
"paths-except": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
Expand Down
75 changes: 75 additions & 0 deletions pkg/config/base_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package config

import (
"errors"
"fmt"
"regexp"
)

type BaseRule struct {
Linters []string
Path string
PathExcept string `mapstructure:"path-except"`
Text string
Source string

// For compatibility with exclude-use-default/include.
InternalReference string `mapstructure:"-"`
}

func (b *BaseRule) Validate(minConditionsCount int) error {
if err := validateOptionalRegex(b.Path); err != nil {
return fmt.Errorf("invalid path regex: %w", err)
}

if err := validateOptionalRegex(b.PathExcept); err != nil {
return fmt.Errorf("invalid path-except regex: %w", err)
}

if err := validateOptionalRegex(b.Text); err != nil {
return fmt.Errorf("invalid text regex: %w", err)
}

if err := validateOptionalRegex(b.Source); err != nil {
return fmt.Errorf("invalid source regex: %w", err)
}

if b.Path != "" && b.PathExcept != "" {
return errors.New("path and path-except should not be set at the same time")
}

nonBlank := 0
if len(b.Linters) > 0 {
nonBlank++
}

// Filtering by path counts as one condition, regardless how it is done (one or both).
// Otherwise, a rule with Path and PathExcept set would pass validation
// whereas before the introduction of path-except that wouldn't have been precise enough.
if b.Path != "" || b.PathExcept != "" {
nonBlank++
}

if b.Text != "" {
nonBlank++
}

if b.Source != "" {
nonBlank++
}

if nonBlank < minConditionsCount {
return fmt.Errorf("at least %d of (text, source, path[-except], linters) should be set", minConditionsCount)
}

return nil
}

func validateOptionalRegex(value string) error {
if value == "" {
return nil
}

_, err := regexp.Compile(value)
return err
}
9 changes: 7 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import (

// Config encapsulates the config data specified in the golangci-lint YAML config file.
type Config struct {
cfgDir string // The directory containing the golangci-lint config file.
cfgDir string // Path to the directory containing golangci-lint config file.
basePath string // Path the root directory related to [Run.RelativePathMode].

Run Run `mapstructure:"run"`

Expand All @@ -32,11 +33,15 @@ type Config struct {
InternalTest bool // Option is used only for testing golangci-lint code, don't use it
}

// GetConfigDir returns the directory that contains golangci config file.
// GetConfigDir returns the directory that contains golangci-lint config file.
func (c *Config) GetConfigDir() string {
return c.cfgDir
}

func (c *Config) GetBasePath() string {
return c.basePath
}

func (c *Config) Validate() error {
validators := []func() error{
c.Run.Validate,
Expand Down
Loading

0 comments on commit 98c110b

Please sign in to comment.