Skip to content

Commit

Permalink
feat: sanitize severities by output format
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Jan 30, 2025
1 parent 2602996 commit 65d7b38
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 59 deletions.
20 changes: 12 additions & 8 deletions pkg/printers/checkstyle.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ const defaultCheckstyleSeverity = "error"
// Checkstyle prints issues in the Checkstyle format.
// https://checkstyle.org/config.html
type Checkstyle struct {
w io.Writer
w io.Writer
sanitizer severitySanitizer
}

func NewCheckstyle(w io.Writer) *Checkstyle {
return &Checkstyle{w: w}
return &Checkstyle{
w: w,
sanitizer: severitySanitizer{
// https://checkstyle.org/config.html#Severity
// https://checkstyle.org/property_types.html#SeverityLevel
allowedSeverities: []string{"ignore", "info", "warning", defaultCheckstyleSeverity},
defaultSeverity: defaultCheckstyleSeverity,
},
}
}

func (p Checkstyle) Print(issues []result.Issue) error {
Expand All @@ -42,17 +51,12 @@ func (p Checkstyle) Print(issues []result.Issue) error {
files[issue.FilePath()] = file
}

severity := defaultCheckstyleSeverity
if issue.Severity != "" {
severity = issue.Severity
}

newError := &checkstyleError{
Column: issue.Column(),
Line: issue.Line(),
Message: issue.Text,
Source: issue.FromLinter,
Severity: severity,
Severity: p.sanitizer.Clean(issue.Severity),
}

file.Errors = append(file.Errors, newError)
Expand Down
20 changes: 9 additions & 11 deletions pkg/printers/codeclimate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package printers
import (
"encoding/json"
"io"
"slices"

"github.com/golangci/golangci-lint/pkg/result"
)
Expand All @@ -13,15 +12,18 @@ const defaultCodeClimateSeverity = "critical"
// CodeClimate prints issues in the Code Climate format.
// https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md
type CodeClimate struct {
w io.Writer

allowedSeverities []string
w io.Writer
sanitizer severitySanitizer
}

func NewCodeClimate(w io.Writer) *CodeClimate {
return &CodeClimate{
w: w,
allowedSeverities: []string{"info", "minor", "major", defaultCodeClimateSeverity, "blocker"},
w: w,
sanitizer: severitySanitizer{
// https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-types
allowedSeverities: []string{"info", "minor", "major", defaultCodeClimateSeverity, "blocker"},
defaultSeverity: defaultCodeClimateSeverity,
},
}
}

Expand All @@ -37,11 +39,7 @@ func (p CodeClimate) Print(issues []result.Issue) error {
codeClimateIssue.Location.Path = issue.Pos.Filename
codeClimateIssue.Location.Lines.Begin = issue.Pos.Line
codeClimateIssue.Fingerprint = issue.Fingerprint()
codeClimateIssue.Severity = defaultCodeClimateSeverity

if slices.Contains(p.allowedSeverities, issue.Severity) {
codeClimateIssue.Severity = issue.Severity
}
codeClimateIssue.Severity = p.sanitizer.Clean(issue.Severity)

codeClimateIssues = append(codeClimateIssues, codeClimateIssue)
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/printers/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"os"
"path/filepath"
"slices"

"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/logutils"
Expand Down Expand Up @@ -143,3 +144,16 @@ func (c *Printer) createPrinter(format string, w io.Writer) (issuePrinter, error

return p, nil
}

type severitySanitizer struct {
allowedSeverities []string
defaultSeverity string
}

func (s *severitySanitizer) Clean(severity string) string {
if slices.Contains(s.allowedSeverities, severity) {
return severity
}

return s.defaultSeverity
}
26 changes: 13 additions & 13 deletions pkg/printers/sarif.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,25 @@ const (
sarifSchemaURI = "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json"
)

const defaultSarifSeverity = "error"

// Sarif prints issues in the SARIF format.
// https://sarifweb.azurewebsites.net/
// https://docs.oasis-open.org/sarif/sarif/v2.1.0/
type Sarif struct {
w io.Writer
w io.Writer
sanitizer severitySanitizer
}

func NewSarif(w io.Writer) *Sarif {
return &Sarif{w: w}
return &Sarif{
w: w,
sanitizer: severitySanitizer{
// https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790898
allowedSeverities: []string{"none", "note", "warning", defaultSarifSeverity},
defaultSeverity: defaultSarifSeverity,
},
}
}

func (p Sarif) Print(issues []result.Issue) error {
Expand All @@ -31,19 +41,9 @@ func (p Sarif) Print(issues []result.Issue) error {
for i := range issues {
issue := issues[i]

severity := issue.Severity

switch severity {
// https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790898
case "none", "note", "warning", "error":
// Valid levels.
default:
severity = "error"
}

sr := sarifResult{
RuleID: issue.FromLinter,
Level: severity,
Level: p.sanitizer.Clean(issue.Severity),
Message: sarifMessage{Text: issue.Text},
Locations: []sarifLocation{
{
Expand Down
16 changes: 12 additions & 4 deletions pkg/printers/teamcity.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ const (
largeLimit = 4000
)

const defaultTeamCitySeverity = "ERROR"

// TeamCity prints issues in the TeamCity format.
// https://www.jetbrains.com/help/teamcity/service-messages.html
type TeamCity struct {
w io.Writer
escaper *strings.Replacer
w io.Writer
escaper *strings.Replacer
sanitizer severitySanitizer
}

// NewTeamCity output format outputs issues according to TeamCity service message format.
Expand All @@ -34,6 +37,11 @@ func NewTeamCity(w io.Writer) *TeamCity {
"[", "|[",
"]", "|]",
),
sanitizer: severitySanitizer{
// https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance
allowedSeverities: []string{"INFO", defaultTeamCitySeverity, "WARNING", "WEAK WARNING"},
defaultSeverity: defaultTeamCitySeverity,
},
}
}

Expand Down Expand Up @@ -65,7 +73,7 @@ func (p *TeamCity) Print(issues []result.Issue) error {
message: issue.Text,
file: issue.FilePath(),
line: issue.Line(),
severity: issue.Severity,
severity: p.sanitizer.Clean(strings.ToUpper(issue.Severity)),
}

_, err := instance.Print(p.w, p.escaper)
Expand Down Expand Up @@ -108,7 +116,7 @@ func (i InspectionInstance) Print(w io.Writer, replacer *strings.Replacer) (int,
cutVal(i.typeID, smallLimit),
cutVal(replacer.Replace(i.message), largeLimit),
cutVal(i.file, largeLimit),
i.line, strings.ToUpper(i.severity))
i.line, i.severity)
}

func cutVal(s string, limit int) string {
Expand Down
4 changes: 2 additions & 2 deletions pkg/printers/teamcity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ func TestTeamCity_Print(t *testing.T) {
require.NoError(t, err)

expected := `##teamcity[inspectionType id='linter-a' name='linter-a' description='linter-a' category='Golangci-lint reports']
##teamcity[inspection typeId='linter-a' message='warning issue' file='path/to/filea.go' line='10' SEVERITY='']
##teamcity[inspection typeId='linter-a' message='warning issue' file='path/to/filea.go' line='10' SEVERITY='ERROR']
##teamcity[inspection typeId='linter-a' message='error issue' file='path/to/filea.go' line='10' SEVERITY='ERROR']
##teamcity[inspectionType id='linter-b' name='linter-b' description='linter-b' category='Golangci-lint reports']
##teamcity[inspection typeId='linter-b' message='info issue' file='path/to/fileb.go' line='300' SEVERITY='']
##teamcity[inspection typeId='linter-b' message='info issue' file='path/to/fileb.go' line='300' SEVERITY='ERROR']
`

assert.Equal(t, expected, buf.String())
Expand Down
42 changes: 21 additions & 21 deletions pkg/printers/testdata/golden-teamcity.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
##teamcity[inspectionType id='gochecknoinits' name='gochecknoinits' description='gochecknoinits' category='Golangci-lint reports']
##teamcity[inspection typeId='gochecknoinits' message='don|'t use `init` function' file='pkg/experimental/myplugin/myplugin.go' line='13' SEVERITY='']
##teamcity[inspection typeId='gochecknoinits' message='don|'t use `init` function' file='pkg/experimental/myplugin/myplugin.go' line='13' SEVERITY='ERROR']
##teamcity[inspectionType id='gocritic' name='gocritic' description='gocritic' category='Golangci-lint reports']
##teamcity[inspection typeId='gocritic' message='hugeParam: settings is heavy (80 bytes); consider passing it by pointer' file='pkg/lint/lintersdb/builder_plugin.go' line='59' SEVERITY='']
##teamcity[inspection typeId='gocritic' message='hugeParam: settings is heavy (80 bytes); consider passing it by pointer' file='pkg/lint/lintersdb/builder_plugin.go' line='59' SEVERITY='ERROR']
##teamcity[inspectionType id='goimports' name='goimports' description='goimports' category='Golangci-lint reports']
##teamcity[inspection typeId='goimports' message='File is not `goimports`-ed with -local github.com/golangci/golangci-lint' file='pkg/printers/printer_test.go' line='6' SEVERITY='']
##teamcity[inspection typeId='goimports' message='File is not `goimports`-ed with -local github.com/golangci/golangci-lint' file='pkg/printers/printer_test.go' line='6' SEVERITY='ERROR']
##teamcity[inspectionType id='maligned' name='maligned' description='maligned' category='Golangci-lint reports']
##teamcity[inspection typeId='maligned' message='struct of size 144 bytes could be of size 128 bytes' file='pkg/config/issues.go' line='107' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 3144 bytes could be of size 3096 bytes' file='pkg/config/linters_settings.go' line='200' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 72 bytes could be of size 64 bytes' file='pkg/config/linters_settings.go' line='383' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 72 bytes could be of size 56 bytes' file='pkg/config/linters_settings.go' line='470' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 136 bytes could be of size 128 bytes' file='pkg/config/linters_settings.go' line='482' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 64 bytes could be of size 56 bytes' file='pkg/config/linters_settings.go' line='584' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 88 bytes could be of size 80 bytes' file='pkg/config/linters_settings.go' line='591' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 40 bytes could be of size 32 bytes' file='pkg/config/linters_settings.go' line='710' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 112 bytes could be of size 104 bytes' file='pkg/config/linters_settings.go' line='762' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 32 bytes could be of size 24 bytes' file='pkg/config/linters_settings.go' line='787' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 40 bytes could be of size 32 bytes' file='pkg/config/linters_settings.go' line='817' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 80 bytes could be of size 72 bytes' file='pkg/config/linters_settings.go' line='902' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 112 bytes could be of size 96 bytes' file='pkg/config/linters_settings.go' line='928' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 168 bytes could be of size 160 bytes' file='pkg/config/run.go' line='6' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 128 bytes could be of size 120 bytes' file='pkg/lint/linter/config.go' line='36' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 96 bytes could be of size 88 bytes' file='pkg/golinters/govet_test.go' line='70' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 64 bytes could be of size 56 bytes' file='pkg/result/processors/diff.go' line='17' SEVERITY='']
##teamcity[inspection typeId='maligned' message='struct of size 144 bytes could be of size 128 bytes' file='pkg/config/issues.go' line='107' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 3144 bytes could be of size 3096 bytes' file='pkg/config/linters_settings.go' line='200' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 72 bytes could be of size 64 bytes' file='pkg/config/linters_settings.go' line='383' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 72 bytes could be of size 56 bytes' file='pkg/config/linters_settings.go' line='470' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 136 bytes could be of size 128 bytes' file='pkg/config/linters_settings.go' line='482' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 64 bytes could be of size 56 bytes' file='pkg/config/linters_settings.go' line='584' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 88 bytes could be of size 80 bytes' file='pkg/config/linters_settings.go' line='591' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 40 bytes could be of size 32 bytes' file='pkg/config/linters_settings.go' line='710' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 112 bytes could be of size 104 bytes' file='pkg/config/linters_settings.go' line='762' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 32 bytes could be of size 24 bytes' file='pkg/config/linters_settings.go' line='787' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 40 bytes could be of size 32 bytes' file='pkg/config/linters_settings.go' line='817' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 80 bytes could be of size 72 bytes' file='pkg/config/linters_settings.go' line='902' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 112 bytes could be of size 96 bytes' file='pkg/config/linters_settings.go' line='928' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 168 bytes could be of size 160 bytes' file='pkg/config/run.go' line='6' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 128 bytes could be of size 120 bytes' file='pkg/lint/linter/config.go' line='36' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 96 bytes could be of size 88 bytes' file='pkg/golinters/govet_test.go' line='70' SEVERITY='ERROR']
##teamcity[inspection typeId='maligned' message='struct of size 64 bytes could be of size 56 bytes' file='pkg/result/processors/diff.go' line='17' SEVERITY='ERROR']
##teamcity[inspectionType id='revive' name='revive' description='revive' category='Golangci-lint reports']
##teamcity[inspection typeId='revive' message='unused-parameter: parameter |'pass|' seems to be unused, consider removing or renaming it as _' file='pkg/experimental/myplugin/myplugin.go' line='49' SEVERITY='WARNING']
##teamcity[inspectionType id='unused' name='unused' description='unused' category='Golangci-lint reports']
##teamcity[inspection typeId='unused' message='const `defaultFileMode` is unused' file='pkg/commands/run.go' line='47' SEVERITY='']
##teamcity[inspection typeId='unused' message='const `defaultFileMode` is unused' file='pkg/commands/run.go' line='47' SEVERITY='ERROR']

0 comments on commit 65d7b38

Please sign in to comment.