feat: syntax to not override severity from linters (#4472)

This commit is contained in:
Ludovic Fernandez 2024-03-11 18:31:00 +01:00 committed by GitHub
parent bb30bbe658
commit ec52d3c881
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 212 additions and 28 deletions

View File

@ -2881,6 +2881,8 @@ severity:
# - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
# - TeamCity: https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance
#
# `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...)
#
# Default: ""
default-severity: error
@ -2888,13 +2890,12 @@ severity:
# Default: false
case-sensitive: true
# Don't override severity defined by linters.
# Default: false
keep-linter-severity: true
# When a list of severity rules are provided, severity information will be added to lint issues.
# Severity rules have the same filtering capability as exclude rules
# except you are allowed to specify one matcher per severity rule.
#
# `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...)
#
# Only affects out formats that support setting severity information.
#
# Default: []

View File

@ -8,10 +8,9 @@ import (
const severityRuleMinConditionsCount = 1
type Severity struct {
Default string `mapstructure:"default-severity"`
CaseSensitive bool `mapstructure:"case-sensitive"`
Rules []SeverityRule `mapstructure:"rules"`
KeepLinterSeverity bool `mapstructure:"keep-linter-severity"` // TODO(ldez): in v2 should be changed to `Override`.
Default string `mapstructure:"default-severity"`
CaseSensitive bool `mapstructure:"case-sensitive"`
Rules []SeverityRule `mapstructure:"rules"`
}
func (s *Severity) Validate() error {

View File

@ -302,7 +302,6 @@ func getSeverityRulesProcessor(cfg *config.Severity, log logutils.Log, files *fs
Default: cfg.Default,
Rules: severityRules,
CaseSensitive: cfg.CaseSensitive,
Override: !cfg.KeepLinterSeverity,
}
return processors.NewSeverity(log.Child(logutils.DebugKeySeverityRules), files, severityOpts)

View File

@ -22,6 +22,7 @@ func newIssueFromIssueTestCase(c issueTestCase) result.Issue {
return result.Issue{
Text: c.Text,
FromLinter: c.Linter,
Severity: c.Severity,
Pos: token.Position{
Filename: c.Path,
Line: c.Line,

View File

@ -8,6 +8,8 @@ import (
"github.com/golangci/golangci-lint/pkg/result"
)
const severityFromLinter = "@linter"
var _ Processor = &Severity{}
type severityRule struct {
@ -24,7 +26,6 @@ type SeverityOptions struct {
Default string
Rules []SeverityRule
CaseSensitive bool
Override bool
}
type Severity struct {
@ -36,7 +37,6 @@ type Severity struct {
defaultSeverity string
rules []severityRule
override bool
}
func NewSeverity(log logutils.Log, files *fsutils.Files, opts SeverityOptions) *Severity {
@ -45,7 +45,6 @@ func NewSeverity(log logutils.Log, files *fsutils.Files, opts SeverityOptions) *
files: files,
log: log,
defaultSeverity: opts.Default,
override: opts.Override,
}
prefix := caseInsensitivePrefix
@ -64,29 +63,30 @@ func (p *Severity) Process(issues []result.Issue) ([]result.Issue, error) {
return issues, nil
}
return transformIssues(issues, func(issue *result.Issue) *result.Issue {
if issue.Severity != "" && !p.override {
return issue
}
return transformIssues(issues, p.transform), nil
}
for _, rule := range p.rules {
rule := rule
ruleSeverity := p.defaultSeverity
if rule.severity != "" {
ruleSeverity = rule.severity
}
if rule.match(issue, p.files, p.log) {
issue.Severity = ruleSeverity
func (p *Severity) transform(issue *result.Issue) *result.Issue {
for _, rule := range p.rules {
if rule.match(issue, p.files, p.log) {
if rule.severity == severityFromLinter || rule.severity == "" && p.defaultSeverity == severityFromLinter {
return issue
}
issue.Severity = rule.severity
if issue.Severity == "" {
issue.Severity = p.defaultSeverity
}
return issue
}
}
if p.defaultSeverity != severityFromLinter {
issue.Severity = p.defaultSeverity
}
return issue
}), nil
return issue
}
func (p *Severity) Name() string { return p.name }

View File

@ -310,3 +310,187 @@ func TestSeverity_caseSensitive(t *testing.T) {
assert.Equal(t, expectedCases, resultingCases)
}
func TestSeverity_transform(t *testing.T) {
lineCache := fsutils.NewLineCache(fsutils.NewFileCache())
files := fsutils.NewFiles(lineCache, "")
testCases := []struct {
desc string
opts SeverityOptions
issue *result.Issue
expected *result.Issue
}{
{
desc: "apply severity from rule",
opts: SeverityOptions{
Default: "error",
Rules: []SeverityRule{
{
Severity: "info",
BaseRule: BaseRule{
Linters: []string{"linter1"},
},
},
},
},
issue: &result.Issue{
Text: "This is a report",
FromLinter: "linter1",
},
expected: &result.Issue{
Text: "This is a report",
FromLinter: "linter1",
Severity: "info",
},
},
{
desc: "apply severity from default",
opts: SeverityOptions{
Default: "error",
Rules: []SeverityRule{
{
Severity: "info",
BaseRule: BaseRule{
Linters: []string{"linter1"},
},
},
},
},
issue: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
},
expected: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
Severity: "error",
},
},
{
desc: "severity from rule override severity from linter",
opts: SeverityOptions{
Default: "error",
Rules: []SeverityRule{
{
Severity: "info",
BaseRule: BaseRule{
Linters: []string{"linter1"},
},
},
},
},
issue: &result.Issue{
Text: "This is a report",
FromLinter: "linter1",
Severity: "huge",
},
expected: &result.Issue{
Text: "This is a report",
FromLinter: "linter1",
Severity: "info",
},
},
{
desc: "severity from default override severity from linter",
opts: SeverityOptions{
Default: "error",
Rules: []SeverityRule{
{
Severity: "info",
BaseRule: BaseRule{
Linters: []string{"linter1"},
},
},
},
},
issue: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
Severity: "huge",
},
expected: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
Severity: "error",
},
},
{
desc: "keep severity from linter as rule",
opts: SeverityOptions{
Default: "error",
Rules: []SeverityRule{
{
Severity: severityFromLinter,
BaseRule: BaseRule{
Linters: []string{"linter1"},
},
},
},
},
issue: &result.Issue{
Text: "This is a report",
FromLinter: "linter1",
Severity: "huge",
},
expected: &result.Issue{
Text: "This is a report",
FromLinter: "linter1",
Severity: "huge",
},
},
{
desc: "keep severity from linter as default",
opts: SeverityOptions{
Default: severityFromLinter,
Rules: []SeverityRule{
{
Severity: "info",
BaseRule: BaseRule{
Linters: []string{"linter1"},
},
},
},
},
issue: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
Severity: "huge",
},
expected: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
Severity: "huge",
},
},
{
desc: "keep severity from linter as default (without rule)",
opts: SeverityOptions{
Default: severityFromLinter,
},
issue: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
Severity: "huge",
},
expected: &result.Issue{
Text: "This is a report",
FromLinter: "linter2",
Severity: "huge",
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := NewSeverity(nil, files, test.opts)
newIssue := p.transform(test.issue)
assert.Equal(t, test.expected, newIssue)
})
}
}