Skip to content

Commit 24e8791

Browse files
committed
Introduce gci as new linter
Signed-off-by: Xiang Dai <long0dai@foxmail.com>
1 parent ba48f30 commit 24e8791

File tree

11 files changed

+144
-1
lines changed

11 files changed

+144
-1
lines changed

.golangci.example.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ linters-settings:
109109
funlen:
110110
lines: 60
111111
statements: 40
112+
gci:
113+
# put imports beginning with prefix after 3rd-party packages;
114+
# only support one prefix
115+
local-prefixes: github.com/org/project
112116
gocognit:
113117
# minimal code complexity to report, 30 by default (but we recommend 10-20)
114118
min-complexity: 10

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ linters-settings:
1414
funlen:
1515
lines: 100
1616
statements: 50
17+
gci:
18+
local-prefixes: github.com/golangci/golangci-lint
1719
goconst:
1820
min-len: 2
1921
min-occurrences: 2

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5
77
github.com/OpenPeeDeeP/depguard v1.0.1
88
github.com/bombsimon/wsl/v3 v3.1.0
9+
github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2
910
github.com/denis-tingajkin/go-header v0.3.1
1011
github.com/fatih/color v1.9.0
1112
github.com/go-critic/go-critic v0.5.0
@@ -56,7 +57,7 @@ require (
5657
github.com/ultraware/whitespace v0.0.4
5758
github.com/uudashr/gocognit v1.0.1
5859
github.com/valyala/quicktemplate v1.5.1
59-
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1
60+
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305
6061
gopkg.in/yaml.v2 v2.3.0
6162
honnef.co/go/tools v0.0.1-2020.1.4
6263
mvdan.cc/gofumpt v0.0.0-20200709182408-4fd085cb6d5f

go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
4646
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
4747
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
4848
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
49+
github.com/daixiang0/gci v0.0.0-20200716011047-39508001b569 h1:kfPaCsRtqTiyT6WyAN2MeLCwqNWp34pkCNNrdh/nzOk=
50+
github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2 h1:3Lhhps85OdA8ezsEKu+IA1hE+DBTjt/fjd7xNCrHbVA=
51+
github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4=
4952
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5053
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5154
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -522,6 +525,8 @@ golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roY
522525
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
523526
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1 h1:rD1FcWVsRaMY+l8biE9jbWP5MS/CJJ/90a9TMkMgNrM=
524527
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
528+
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305 h1:yaM5S0KcY0lIoZo7Fl+oi91b/DdlU2zuWpfHrpWbCS0=
529+
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
525530
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
526531
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
527532
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

pkg/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ type Run struct {
155155
}
156156

157157
type LintersSettings struct {
158+
Gci struct {
159+
LocalPrefixes string `mapstructure:"local-prefixes"`
160+
}
158161
Govet GovetSettings
159162
Golint struct {
160163
MinConfidence float64 `mapstructure:"min-confidence"`

pkg/golinters/gci.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package golinters
2+
3+
import (
4+
"sync"
5+
6+
"github.com/daixiang0/gci/pkg/gci"
7+
"github.com/pkg/errors"
8+
"golang.org/x/tools/go/analysis"
9+
10+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
11+
"github.com/golangci/golangci-lint/pkg/lint/linter"
12+
)
13+
14+
const gciName = "gci"
15+
16+
func NewGci() *goanalysis.Linter {
17+
var mu sync.Mutex
18+
var resIssues []goanalysis.Issue
19+
20+
analyzer := &analysis.Analyzer{
21+
Name: gciName,
22+
Doc: goanalysis.TheOnlyanalyzerDoc,
23+
}
24+
return goanalysis.NewLinter(
25+
gciName,
26+
"Gci control golang package import order and make it always deterministic.",
27+
[]*analysis.Analyzer{analyzer},
28+
nil,
29+
).WithContextSetter(func(lintCtx *linter.Context) {
30+
localFlag := lintCtx.Settings().Gci.LocalPrefixes
31+
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
32+
var fileNames []string
33+
for _, f := range pass.Files {
34+
pos := pass.Fset.PositionFor(f.Pos(), false)
35+
fileNames = append(fileNames, pos.Filename)
36+
}
37+
38+
var issues []goanalysis.Issue
39+
40+
for _, f := range fileNames {
41+
diff, err := gci.Run(f, &gci.FlagSet{LocalFlag: localFlag})
42+
if err != nil {
43+
return nil, err
44+
}
45+
if diff == nil {
46+
continue
47+
}
48+
49+
is, err := extractIssuesFromPatch(string(diff), lintCtx.Log, lintCtx, gciName)
50+
if err != nil {
51+
return nil, errors.Wrapf(err, "can't extract issues from gci diff output %q", string(diff))
52+
}
53+
54+
for i := range is {
55+
issues = append(issues, goanalysis.NewIssue(&is[i], pass))
56+
}
57+
}
58+
59+
if len(issues) == 0 {
60+
return nil, nil
61+
}
62+
63+
mu.Lock()
64+
resIssues = append(resIssues, issues...)
65+
mu.Unlock()
66+
67+
return nil, nil
68+
}
69+
}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
70+
return resIssues
71+
}).WithLoadMode(goanalysis.LoadModeSyntax)
72+
}

pkg/golinters/gofmt_common.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ func getErrorTextForLinter(lintCtx *linter.Context, linterName string) string {
225225
if lintCtx.Settings().Goimports.LocalPrefixes != "" {
226226
text += " with -local " + lintCtx.Settings().Goimports.LocalPrefixes
227227
}
228+
case gciName:
229+
text = "File is not `gci`-ed"
230+
if lintCtx.Settings().Gci.LocalPrefixes != "" {
231+
text += " with -local " + lintCtx.Settings().Gci.LocalPrefixes
232+
}
228233
}
229234
return text
230235
}

pkg/lint/lintersdb/manager.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
206206
WithPresets(linter.PresetStyle).
207207
WithLoadForGoAnalysis().
208208
WithURL("https://github.com/denis-tingajkin/go-header"),
209+
linter.NewConfig(golinters.NewGci()).
210+
WithLoadForGoAnalysis().
211+
WithURL("https://github.com/daixiang0/gci"),
209212
linter.NewConfig(golinters.NewMaligned()).
210213
WithLoadForGoAnalysis().
211214
WithPresets(linter.PresetPerformance).

test/linters_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ func TestGoimportsLocal(t *testing.T) {
8383
ExpectHasIssue("testdata/goimports/goimports.go:8: File is not `goimports`-ed")
8484
}
8585

86+
func TestGciLocal(t *testing.T) {
87+
sourcePath := filepath.Join(testdataDir, "gci", "gci.go")
88+
args := []string{
89+
"--disable-all", "--print-issued-lines=false", "--print-linter-name=false", "--out-format=line-number",
90+
sourcePath,
91+
}
92+
rc := extractRunContextFromComments(t, sourcePath)
93+
args = append(args, rc.args...)
94+
95+
cfg, err := yaml.Marshal(rc.config)
96+
assert.NoError(t, err)
97+
98+
testshared.NewLintRunner(t).RunWithYamlConfig(string(cfg), args...).
99+
ExpectHasIssue("testdata/gci/gci.go:8: File is not `gci`-ed")
100+
}
101+
86102
func saveConfig(t *testing.T, cfg map[string]interface{}) (cfgPath string, finishFunc func()) {
87103
f, err := ioutil.TempFile("", "golangci_lint_test")
88104
assert.NoError(t, err)

test/testdata/gci.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//args: -Egci
2+
package testdata
3+
4+
import (
5+
"fmt"
6+
7+
"github.com/golangci/golangci-lint/pkg/config"
8+
"github.com/pkg/errors"
9+
)
10+
11+
func GoimportsLocalTest() {
12+
fmt.Print("x")
13+
_ = config.Config{}
14+
_ = errors.New("")
15+
}

test/testdata/gci/gci.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//args: -Egci
2+
//config: linters-settings.gci.local-prefixes=github.com/golangci/golangci-lint
3+
package gci
4+
5+
import (
6+
"fmt"
7+
8+
"github.com/golangci/golangci-lint/pkg/config"
9+
10+
"github.com/pkg/errors"
11+
)
12+
13+
func GoimportsLocalTest() {
14+
fmt.Print("x")
15+
_ = config.Config{}
16+
_ = errors.New("")
17+
}

0 commit comments

Comments
 (0)