Skip to content

Commit 55748a8

Browse files
committed
Add support for gci sections
Signed-off-by: Norman Gehrsitz <[email protected]>
1 parent 3d733a2 commit 55748a8

File tree

12 files changed

+67
-110
lines changed

12 files changed

+67
-110
lines changed

.golangci.example.yml

+12-4
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,18 @@ linters-settings:
295295
statements: -1
296296

297297
gci:
298-
# Put imports beginning with prefix after 3rd-party packages.
299-
# Only support one prefix.
300-
# If not set, use `goimports.local-prefixes`.
301-
local-prefixes: github.com/org/project
298+
# Checks that no inline Comments are present
299+
no-inlineComments: false
300+
# Checks that no prefix Comments(comment lines above an import) are present
301+
no-prefixComments: false
302+
# Section configuration to compare against.
303+
# Run gci print -h for a detailed explanation
304+
sections:
305+
- Standard
306+
- Default
307+
# Separators that should be present between sections
308+
sectionSeparators:
309+
- Newline
302310

303311
gocognit:
304312
# Minimal code complexity to report

.golangci.yml

-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ linters-settings:
1212
funlen:
1313
lines: 100
1414
statements: 50
15-
gci:
16-
local-prefixes: github.com/golangci/golangci-lint
1715
goconst:
1816
min-len: 2
1917
min-occurrences: 3

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ require (
1919
github.com/breml/errchkjson v0.2.1
2020
github.com/butuzov/ireturn v0.1.1
2121
github.com/charithe/durationcheck v0.0.9
22-
github.com/daixiang0/gci v0.2.9
22+
github.com/daixiang0/gci v0.3.0
2323
github.com/denis-tingajkin/go-header v0.4.2
2424
github.com/esimonov/ifshort v1.0.4
2525
github.com/fatih/color v1.13.0

go.sum

+5-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/linters_settings.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,10 @@ type FunlenSettings struct {
253253
}
254254

255255
type GciSettings struct {
256-
LocalPrefixes string `mapstructure:"local-prefixes"`
256+
NoInlineComments bool `mapstructure:"no-inlineComments"`
257+
NoPrefixComments bool `mapstructure:"no-prefixComments"`
258+
Sections []string `mapstructure:"sections"`
259+
SectionSeparator []string `mapstructure:"sectionSeparators"`
257260
}
258261

259262
type GocognitSettings struct {

pkg/golinters/gci.go

+19-80
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,35 @@
11
package golinters
22

33
import (
4-
"bytes"
5-
"fmt"
6-
"sync"
4+
"strings"
75

8-
"github.com/daixiang0/gci/pkg/gci"
9-
"github.com/pkg/errors"
10-
"github.com/shazow/go-diff/difflib"
6+
gciAnalyzer "github.com/daixiang0/gci/pkg/analyzer"
117
"golang.org/x/tools/go/analysis"
128

9+
"github.com/golangci/golangci-lint/pkg/config"
1310
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
14-
"github.com/golangci/golangci-lint/pkg/lint/linter"
1511
)
1612

1713
const gciName = "gci"
1814

19-
func NewGci() *goanalysis.Linter {
20-
var mu sync.Mutex
21-
var resIssues []goanalysis.Issue
22-
differ := difflib.New()
23-
24-
analyzer := &analysis.Analyzer{
25-
Name: gciName,
26-
Doc: goanalysis.TheOnlyanalyzerDoc,
15+
func NewGci(settings *config.GciSettings) *goanalysis.Linter {
16+
analyzer := gciAnalyzer.Analyzer
17+
var cfg map[string]map[string]interface{}
18+
if settings != nil {
19+
cfg = map[string]map[string]interface{}{
20+
analyzer.Name: {
21+
gciAnalyzer.NoInlineCommentsFlag: settings.NoInlineComments,
22+
gciAnalyzer.NoPrefixCommentsFlag: settings.NoPrefixComments,
23+
gciAnalyzer.SectionsFlag: strings.Join(settings.Sections, gciAnalyzer.SectionDelimiter),
24+
gciAnalyzer.SectionSeparatorsFlag: strings.Join(settings.SectionSeparator, gciAnalyzer.SectionDelimiter),
25+
},
26+
}
2727
}
28+
2829
return goanalysis.NewLinter(
2930
gciName,
30-
"Gci control golang package import order and make it always deterministic.",
31+
"Gci controls golang package import order and makes it always deterministic.",
3132
[]*analysis.Analyzer{analyzer},
32-
nil,
33-
).WithContextSetter(func(lintCtx *linter.Context) {
34-
localFlag := lintCtx.Settings().Gci.LocalPrefixes
35-
goimportsFlag := lintCtx.Settings().Goimports.LocalPrefixes
36-
if localFlag == "" && goimportsFlag != "" {
37-
localFlag = goimportsFlag
38-
}
39-
40-
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
41-
var fileNames []string
42-
for _, f := range pass.Files {
43-
pos := pass.Fset.PositionFor(f.Pos(), false)
44-
fileNames = append(fileNames, pos.Filename)
45-
}
46-
47-
var issues []goanalysis.Issue
48-
49-
flagSet := gci.FlagSet{
50-
LocalFlag: gci.ParseLocalFlag(localFlag),
51-
}
52-
53-
for _, f := range fileNames {
54-
source, result, err := gci.Run(f, &flagSet)
55-
if err != nil {
56-
return nil, err
57-
}
58-
if result == nil {
59-
continue
60-
}
61-
62-
diff := bytes.Buffer{}
63-
_, err = diff.WriteString(fmt.Sprintf("--- %[1]s\n+++ %[1]s\n", f))
64-
if err != nil {
65-
return nil, fmt.Errorf("can't write diff header: %v", err)
66-
}
67-
68-
err = differ.Diff(&diff, bytes.NewReader(source), bytes.NewReader(result))
69-
if err != nil {
70-
return nil, fmt.Errorf("can't get gci diff output: %v", err)
71-
}
72-
73-
is, err := extractIssuesFromPatch(diff.String(), lintCtx.Log, lintCtx, gciName)
74-
if err != nil {
75-
return nil, errors.Wrapf(err, "can't extract issues from gci diff output %q", diff.String())
76-
}
77-
78-
for i := range is {
79-
issues = append(issues, goanalysis.NewIssue(&is[i], pass))
80-
}
81-
}
82-
83-
if len(issues) == 0 {
84-
return nil, nil
85-
}
86-
87-
mu.Lock()
88-
resIssues = append(resIssues, issues...)
89-
mu.Unlock()
90-
91-
return nil, nil
92-
}
93-
}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
94-
return resIssues
95-
}).WithLoadMode(goanalysis.LoadModeSyntax)
33+
cfg,
34+
).WithLoadMode(goanalysis.LoadModeSyntax)
9635
}

pkg/golinters/gofmt_common.go

+6-8
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,14 @@ func getErrorTextForLinter(lintCtx *linter.Context, linterName string) string {
226226
text += " with -local " + lintCtx.Settings().Goimports.LocalPrefixes
227227
}
228228
case gciName:
229-
text = "File is not `gci`-ed"
230-
localPrefixes := lintCtx.Settings().Gci.LocalPrefixes
231-
goimportsFlag := lintCtx.Settings().Goimports.LocalPrefixes
232-
if localPrefixes == "" && goimportsFlag != "" {
233-
localPrefixes = goimportsFlag
229+
optionsText := []string{}
230+
if lintCtx.Settings().Gci.NoInlineComments {
231+
optionsText = append(optionsText, "NoInlineComments")
234232
}
235-
236-
if localPrefixes != "" {
237-
text += " with -local " + localPrefixes
233+
if lintCtx.Settings().Gci.NoPrefixComments {
234+
optionsText = append(optionsText, "NoPrefixComments")
238235
}
236+
text = fmt.Sprintf("File does not conform to the import format configured for `Gci`(%s)", strings.Join(optionsText, ","))
239237
}
240238
return text
241239
}

pkg/lint/lintersdb/manager.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
107107
var errorlintCfg *config.ErrorLintSettings
108108
var exhaustiveCfg *config.ExhaustiveSettings
109109
var exhaustiveStructCfg *config.ExhaustiveStructSettings
110+
var gciCfg *config.GciSettings
110111
var goModDirectivesCfg *config.GoModDirectivesSettings
111112
var goMndCfg *config.GoMndSettings
112113
var gosecCfg *config.GoSecSettings
@@ -139,6 +140,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
139140
errorlintCfg = &m.cfg.LintersSettings.ErrorLint
140141
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
141142
exhaustiveStructCfg = &m.cfg.LintersSettings.ExhaustiveStruct
143+
gciCfg = &m.cfg.LintersSettings.Gci
142144
goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives
143145
goMndCfg = &m.cfg.LintersSettings.Gomnd
144146
gosecCfg = &m.cfg.LintersSettings.Gosec
@@ -292,7 +294,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
292294
WithPresets(linter.PresetComplexity).
293295
WithURL("https://github.com/ultraware/funlen"),
294296

295-
linter.NewConfig(golinters.NewGci()).
297+
linter.NewConfig(golinters.NewGci(gciCfg)).
296298
WithSince("v1.30.0").
297299
WithPresets(linter.PresetFormatting, linter.PresetImport).
298300
WithAutoFix().

test/linters_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ func TestGciLocal(t *testing.T) {
9292
rc := extractRunContextFromComments(t, sourcePath)
9393
args = append(args, rc.args...)
9494

95-
cfg, err := yaml.Marshal(rc.config)
95+
cfg, err := os.ReadFile(rc.configPath)
9696
require.NoError(t, err)
9797

9898
testshared.NewLintRunner(t).RunWithYamlConfig(string(cfg), args...).
99-
ExpectHasIssue("testdata/gci/gci.go:7: File is not `gci`-ed")
99+
ExpectHasIssue("testdata/gci/gci.go:9:1: Expected '\\n', Found '\\t'")
100100
}
101101

102102
func TestMultipleOutputs(t *testing.T) {
@@ -108,11 +108,11 @@ func TestMultipleOutputs(t *testing.T) {
108108
rc := extractRunContextFromComments(t, sourcePath)
109109
args = append(args, rc.args...)
110110

111-
cfg, err := yaml.Marshal(rc.config)
111+
cfg, err := os.ReadFile(rc.configPath)
112112
require.NoError(t, err)
113113

114114
testshared.NewLintRunner(t).RunWithYamlConfig(string(cfg), args...).
115-
ExpectHasIssue("testdata/gci/gci.go:7: File is not `gci`-ed").
115+
ExpectHasIssue("testdata/gci/gci.go:9:1: Expected '\\n', Found '\\t'").
116116
ExpectOutputContains(`"Issues":[`)
117117
}
118118

@@ -125,11 +125,11 @@ func TestStderrOutput(t *testing.T) {
125125
rc := extractRunContextFromComments(t, sourcePath)
126126
args = append(args, rc.args...)
127127

128-
cfg, err := yaml.Marshal(rc.config)
128+
cfg, err := os.ReadFile(rc.configPath)
129129
require.NoError(t, err)
130130

131131
testshared.NewLintRunner(t).RunWithYamlConfig(string(cfg), args...).
132-
ExpectHasIssue("testdata/gci/gci.go:7: File is not `gci`-ed").
132+
ExpectHasIssue("testdata/gci/gci.go:9:1: Expected '\\n', Found '\\t'").
133133
ExpectOutputContains(`"Issues":[`)
134134
}
135135

@@ -145,11 +145,11 @@ func TestFileOutput(t *testing.T) {
145145
rc := extractRunContextFromComments(t, sourcePath)
146146
args = append(args, rc.args...)
147147

148-
cfg, err := yaml.Marshal(rc.config)
148+
cfg, err := os.ReadFile(rc.configPath)
149149
require.NoError(t, err)
150150

151151
testshared.NewLintRunner(t).RunWithYamlConfig(string(cfg), args...).
152-
ExpectHasIssue("testdata/gci/gci.go:7: File is not `gci`-ed").
152+
ExpectHasIssue("testdata/gci/gci.go:9:1: Expected '\\n', Found '\\t'").
153153
ExpectOutputNotContains(`"Issues":[`)
154154

155155
b, err := os.ReadFile(resultPath)

test/testdata/configs/gci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
linters-settings:
2+
gci:
3+
sections:
4+
- Standard
5+
- Prefix(github.com/golangci/golangci-lint)
6+
- Default

test/testdata/gci.go

+2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
//args: -Egci
2+
//config_path: testdata/configs/gci.yml
23
package testdata
34

45
import (
56
"fmt"
67

78
"github.com/golangci/golangci-lint/pkg/config"
9+
810
"github.com/pkg/errors"
911
)
1012

test/testdata/gci/gci.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
//args: -Egci
2-
//config: linters-settings.gci.local-prefixes=github.com/golangci/golangci-lint
2+
//config_path: testdata/configs/gci.yml
33
package gci
44

55
import (
66
"fmt"
77

88
"github.com/golangci/golangci-lint/pkg/config"
9-
109
"github.com/pkg/errors"
1110
)
1211

0 commit comments

Comments
 (0)