Skip to content

feat: Add output option to group results by linter name #4325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .golangci.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ output:
# Default: false
sort-results: true

# Group results by linter name.
# Default: false
group-results-by-linter: false


# All available settings of specific linters.
linters-settings:
Expand Down
1 change: 1 addition & 0 deletions pkg/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, is
fs.BoolVar(&oc.PrintLinterName, "print-linter-name", true, wh("Print linter name in issue line"))
fs.BoolVar(&oc.UniqByLine, "uniq-by-line", true, wh("Make issues output unique by line"))
fs.BoolVar(&oc.SortResults, "sort-results", false, wh("Sort linter results"))
fs.BoolVar(&oc.GroupResultsByLinter, "group-results-by-linter", false, wh("Group results by linter name"))
fs.BoolVar(&oc.PrintWelcomeMessage, "print-welcome", false, wh("Print welcome message"))
fs.StringVar(&oc.PathPrefix, "path-prefix", "", wh("Path prefix to add to output"))
hideFlag("print-welcome") // no longer used
Expand Down
15 changes: 8 additions & 7 deletions pkg/config/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ var OutFormats = []string{
}

type Output struct {
Format string
PrintIssuedLine bool `mapstructure:"print-issued-lines"`
PrintLinterName bool `mapstructure:"print-linter-name"`
UniqByLine bool `mapstructure:"uniq-by-line"`
SortResults bool `mapstructure:"sort-results"`
PrintWelcomeMessage bool `mapstructure:"print-welcome"`
PathPrefix string `mapstructure:"path-prefix"`
Format string
PrintIssuedLine bool `mapstructure:"print-issued-lines"`
PrintLinterName bool `mapstructure:"print-linter-name"`
UniqByLine bool `mapstructure:"uniq-by-line"`
SortResults bool `mapstructure:"sort-results"`
GroupResultsByLinter bool `mapstructure:"group-results-by-linter"`
PrintWelcomeMessage bool `mapstructure:"print-welcome"`
PathPrefix string `mapstructure:"path-prefix"`

// only work with CLI flags because the setup of logs is done before the config file parsing.
Color string
Expand Down
43 changes: 43 additions & 0 deletions pkg/result/processors/sort_results.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package processors

import (
"fmt"
"sort"
"strings"

Expand Down Expand Up @@ -35,6 +36,48 @@ func NewSortResults(cfg *config.Config) *SortResults {

// Process is performing sorting of the result issues.
func (sr SortResults) Process(issues []result.Issue) ([]result.Issue, error) {
if sr.cfg.Output.GroupResultsByLinter {
issuesByLinterName := sr.groupIssuesByLinterName(issues)
return sr.processIssuesByLinterName(issuesByLinterName)
}
return sr.processFlatIssues(issues)
}

func (sr SortResults) groupIssuesByLinterName(issues []result.Issue) map[string][]result.Issue {
issuesByLinterName := map[string][]result.Issue{}
for _, issue := range issues {
if _, ok := issuesByLinterName[issue.FromLinter]; !ok {
issuesByLinterName[issue.FromLinter] = []result.Issue{}
}
issuesByLinterName[issue.FromLinter] = append(issuesByLinterName[issue.FromLinter], issue)
}
return issuesByLinterName
}

func (sr SortResults) processIssuesByLinterName(issuesByLinterName map[string][]result.Issue) ([]result.Issue, error) {
linterNames := sr.getSortedLinterNames(issuesByLinterName)
var processedIssues []result.Issue
for _, linterName := range linterNames {
linterIssues := issuesByLinterName[linterName]
processedLinterIssues, err := sr.processFlatIssues(linterIssues)
if err != nil {
return nil, fmt.Errorf("failed to process issues from %s linter: %w", linterName, err)
}
processedIssues = append(processedIssues, processedLinterIssues...)
}
return processedIssues, nil
}

func (sr SortResults) getSortedLinterNames(issuesByLinterName map[string][]result.Issue) []string {
linterNames := make([]string, 0, len(issuesByLinterName))
for linterName := range issuesByLinterName {
linterNames = append(linterNames, linterName)
}
sort.Strings(linterNames)
return linterNames
}

func (sr SortResults) processFlatIssues(issues []result.Issue) ([]result.Issue, error) {
if !sr.cfg.Output.SortResults {
return issues, nil
}
Expand Down
31 changes: 31 additions & 0 deletions pkg/result/processors/sort_results_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,30 @@ import (

var issues = []result.Issue{
{
FromLinter: "linter-a",
Pos: token.Position{
Filename: "file_windows.go",
Column: 80,
Line: 10,
},
},
{
FromLinter: "linter-b",
Pos: token.Position{
Filename: "file_linux.go",
Column: 70,
Line: 11,
},
},
{
FromLinter: "linter-a",
Pos: token.Position{
Filename: "file_darwin.go",
Line: 12,
},
},
{
FromLinter: "linter-b",
Pos: token.Position{
Filename: "file_darwin.go",
Column: 60,
Expand Down Expand Up @@ -175,3 +179,30 @@ func TestSorting(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, []result.Issue{issues[3], issues[2], issues[1], issues[0]}, results)
}

func TestGroupingByLinterName(t *testing.T) {
var tests = make([]result.Issue, len(issues))
copy(tests, issues)

var cfg = config.Config{}
cfg.Output.GroupResultsByLinter = true
var sr = NewSortResults(&cfg)

results, err := sr.Process(tests)
require.NoError(t, err)
assert.Equal(t, []result.Issue{issues[0], issues[2], issues[1], issues[3]}, results)
}

func TestSortingAndGroupingByLinterName(t *testing.T) {
var tests = make([]result.Issue, len(issues))
copy(tests, issues)

var cfg = config.Config{}
cfg.Output.SortResults = true
cfg.Output.GroupResultsByLinter = true
var sr = NewSortResults(&cfg)

results, err := sr.Process(tests)
require.NoError(t, err)
assert.Equal(t, []result.Issue{issues[2], issues[0], issues[3], issues[1]}, results)
}