Skip to content

Commit

Permalink
chore: validate LinterExclusions configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Jan 21, 2025
1 parent 0e0d6ad commit b03312b
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 92 deletions.
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
}
88 changes: 0 additions & 88 deletions pkg/config/issues.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package config

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

const excludeRuleMinConditionsCount = 2

var DefaultExcludePatterns = []ExcludePattern{
{
ID: "EXC0001",
Expand Down Expand Up @@ -141,97 +137,13 @@ func (i *Issues) Validate() error {
return nil
}

type ExcludeRule struct {
BaseRule `mapstructure:",squash"`
}

func (e *ExcludeRule) Validate() error {
return e.BaseRule.Validate(excludeRuleMinConditionsCount)
}

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
}

type ExcludePattern struct {
ID string
Pattern string
Linter string
Why string
}

func GetDefaultExcludePatternsStrings() []string {
ret := make([]string, len(DefaultExcludePatterns))
for i, p := range DefaultExcludePatterns {
ret[i] = p.Pattern
}
return ret
}

// TODO(ldez): this behavior must be changed in v2, because this is confusing.
func GetExcludePatterns(include []string) []ExcludePattern {
includeMap := make(map[string]struct{}, len(include))
Expand Down
12 changes: 8 additions & 4 deletions pkg/config/linters.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@ type Linters struct {
}

func (l *Linters) Validate() error {
if err := l.validateAllDisableEnableOptions(); err != nil {
return err
validators := []func() error{
l.validateAllDisableEnableOptions,
l.validateDisabledAndEnabledAtOneMoment,
l.LinterExclusions.Validate,
}

if err := l.validateDisabledAndEnabledAtOneMoment(); err != nil {
return err
for _, v := range validators {
if err := v(); err != nil {
return err
}
}

return nil
Expand Down
24 changes: 24 additions & 0 deletions pkg/config/linters_exclusions.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,40 @@
package config

import (
"fmt"
)

const (
DefaultExclusionComments = "comments"
DefaultExclusionStdErrorHandling = "stdErrorHandling"
DefaultExclusionCommonFalsePositives = "commonFalsePositives"
DefaultExclusionLegacy = "legacy"
)

const excludeRuleMinConditionsCount = 2

type LinterExclusions struct {
Generated string `mapstructure:"generated"`
WarnUnused bool `mapstructure:"warn-unused"`
Default []string `mapstructure:"default"`
Rules []ExcludeRule `mapstructure:"rules"`
Paths []string `mapstructure:"paths"`
}

func (e *LinterExclusions) Validate() error {
for i, rule := range e.Rules {
if err := rule.Validate(); err != nil {
return fmt.Errorf("error in exclude rule #%d: %w", i, err)
}
}

return nil
}

type ExcludeRule struct {
BaseRule `mapstructure:",squash"`
}

func (e *ExcludeRule) Validate() error {
return e.BaseRule.Validate(excludeRuleMinConditionsCount)
}

0 comments on commit b03312b

Please sign in to comment.