Introduce gci as new linter (#1266)
* Introduce gci as new linter Signed-off-by: Xiang Dai <long0dai@foxmail.com> * use goimports setting if not specified Signed-off-by: Xiang Dai <long0dai@foxmail.com>
This commit is contained in:
parent
ba48f30fdc
commit
60613dc3eb
@ -109,6 +109,11 @@ linters-settings:
|
|||||||
funlen:
|
funlen:
|
||||||
lines: 60
|
lines: 60
|
||||||
statements: 40
|
statements: 40
|
||||||
|
gci:
|
||||||
|
# put imports beginning with prefix after 3rd-party packages;
|
||||||
|
# only support one prefix
|
||||||
|
# if not set, use goimports.local-prefixes
|
||||||
|
local-prefixes: github.com/org/project
|
||||||
gocognit:
|
gocognit:
|
||||||
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||||
min-complexity: 10
|
min-complexity: 10
|
||||||
|
@ -14,6 +14,8 @@ linters-settings:
|
|||||||
funlen:
|
funlen:
|
||||||
lines: 100
|
lines: 100
|
||||||
statements: 50
|
statements: 50
|
||||||
|
gci:
|
||||||
|
local-prefixes: github.com/golangci/golangci-lint
|
||||||
goconst:
|
goconst:
|
||||||
min-len: 2
|
min-len: 2
|
||||||
min-occurrences: 2
|
min-occurrences: 2
|
||||||
|
3
go.mod
3
go.mod
@ -6,6 +6,7 @@ require (
|
|||||||
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5
|
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5
|
||||||
github.com/OpenPeeDeeP/depguard v1.0.1
|
github.com/OpenPeeDeeP/depguard v1.0.1
|
||||||
github.com/bombsimon/wsl/v3 v3.1.0
|
github.com/bombsimon/wsl/v3 v3.1.0
|
||||||
|
github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2
|
||||||
github.com/denis-tingajkin/go-header v0.3.1
|
github.com/denis-tingajkin/go-header v0.3.1
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.9.0
|
||||||
github.com/go-critic/go-critic v0.5.0
|
github.com/go-critic/go-critic v0.5.0
|
||||||
@ -56,7 +57,7 @@ require (
|
|||||||
github.com/ultraware/whitespace v0.0.4
|
github.com/ultraware/whitespace v0.0.4
|
||||||
github.com/uudashr/gocognit v1.0.1
|
github.com/uudashr/gocognit v1.0.1
|
||||||
github.com/valyala/quicktemplate v1.5.1
|
github.com/valyala/quicktemplate v1.5.1
|
||||||
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1
|
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4
|
honnef.co/go/tools v0.0.1-2020.1.4
|
||||||
mvdan.cc/gofumpt v0.0.0-20200709182408-4fd085cb6d5f
|
mvdan.cc/gofumpt v0.0.0-20200709182408-4fd085cb6d5f
|
||||||
|
4
go.sum
4
go.sum
@ -46,6 +46,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
|||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2 h1:3Lhhps85OdA8ezsEKu+IA1hE+DBTjt/fjd7xNCrHbVA=
|
||||||
|
github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -522,6 +524,8 @@ golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roY
|
|||||||
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1 h1:rD1FcWVsRaMY+l8biE9jbWP5MS/CJJ/90a9TMkMgNrM=
|
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1 h1:rD1FcWVsRaMY+l8biE9jbWP5MS/CJJ/90a9TMkMgNrM=
|
||||||
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305 h1:yaM5S0KcY0lIoZo7Fl+oi91b/DdlU2zuWpfHrpWbCS0=
|
||||||
|
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
@ -155,6 +155,9 @@ type Run struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LintersSettings struct {
|
type LintersSettings struct {
|
||||||
|
Gci struct {
|
||||||
|
LocalPrefixes string `mapstructure:"local-prefixes"`
|
||||||
|
}
|
||||||
Govet GovetSettings
|
Govet GovetSettings
|
||||||
Golint struct {
|
Golint struct {
|
||||||
MinConfidence float64 `mapstructure:"min-confidence"`
|
MinConfidence float64 `mapstructure:"min-confidence"`
|
||||||
|
77
pkg/golinters/gci.go
Normal file
77
pkg/golinters/gci.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package golinters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/daixiang0/gci/pkg/gci"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
|
)
|
||||||
|
|
||||||
|
const gciName = "gci"
|
||||||
|
|
||||||
|
func NewGci() *goanalysis.Linter {
|
||||||
|
var mu sync.Mutex
|
||||||
|
var resIssues []goanalysis.Issue
|
||||||
|
|
||||||
|
analyzer := &analysis.Analyzer{
|
||||||
|
Name: gciName,
|
||||||
|
Doc: goanalysis.TheOnlyanalyzerDoc,
|
||||||
|
}
|
||||||
|
return goanalysis.NewLinter(
|
||||||
|
gciName,
|
||||||
|
"Gci control golang package import order and make it always deterministic.",
|
||||||
|
[]*analysis.Analyzer{analyzer},
|
||||||
|
nil,
|
||||||
|
).WithContextSetter(func(lintCtx *linter.Context) {
|
||||||
|
localFlag := lintCtx.Settings().Gci.LocalPrefixes
|
||||||
|
goimportsFlag := lintCtx.Settings().Goimports.LocalPrefixes
|
||||||
|
if localFlag == "" && goimportsFlag != "" {
|
||||||
|
localFlag = goimportsFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
var fileNames []string
|
||||||
|
for _, f := range pass.Files {
|
||||||
|
pos := pass.Fset.PositionFor(f.Pos(), false)
|
||||||
|
fileNames = append(fileNames, pos.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
var issues []goanalysis.Issue
|
||||||
|
|
||||||
|
for _, f := range fileNames {
|
||||||
|
diff, err := gci.Run(f, &gci.FlagSet{LocalFlag: localFlag})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if diff == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
is, err := extractIssuesFromPatch(string(diff), lintCtx.Log, lintCtx, gciName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "can't extract issues from gci diff output %q", string(diff))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range is {
|
||||||
|
issues = append(issues, goanalysis.NewIssue(&is[i], pass))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(issues) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
resIssues = append(resIssues, issues...)
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
||||||
|
return resIssues
|
||||||
|
}).WithLoadMode(goanalysis.LoadModeSyntax)
|
||||||
|
}
|
@ -225,6 +225,17 @@ func getErrorTextForLinter(lintCtx *linter.Context, linterName string) string {
|
|||||||
if lintCtx.Settings().Goimports.LocalPrefixes != "" {
|
if lintCtx.Settings().Goimports.LocalPrefixes != "" {
|
||||||
text += " with -local " + lintCtx.Settings().Goimports.LocalPrefixes
|
text += " with -local " + lintCtx.Settings().Goimports.LocalPrefixes
|
||||||
}
|
}
|
||||||
|
case gciName:
|
||||||
|
text = "File is not `gci`-ed"
|
||||||
|
localPrefixes := lintCtx.Settings().Gci.LocalPrefixes
|
||||||
|
goimportsFlag := lintCtx.Settings().Goimports.LocalPrefixes
|
||||||
|
if localPrefixes == "" && goimportsFlag != "" {
|
||||||
|
localPrefixes = goimportsFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
if localPrefixes != "" {
|
||||||
|
text += " with -local " + localPrefixes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
@ -206,6 +206,9 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
WithPresets(linter.PresetStyle).
|
WithPresets(linter.PresetStyle).
|
||||||
WithLoadForGoAnalysis().
|
WithLoadForGoAnalysis().
|
||||||
WithURL("https://github.com/denis-tingajkin/go-header"),
|
WithURL("https://github.com/denis-tingajkin/go-header"),
|
||||||
|
linter.NewConfig(golinters.NewGci()).
|
||||||
|
WithLoadForGoAnalysis().
|
||||||
|
WithURL("https://github.com/daixiang0/gci"),
|
||||||
linter.NewConfig(golinters.NewMaligned()).
|
linter.NewConfig(golinters.NewMaligned()).
|
||||||
WithLoadForGoAnalysis().
|
WithLoadForGoAnalysis().
|
||||||
WithPresets(linter.PresetPerformance).
|
WithPresets(linter.PresetPerformance).
|
||||||
|
@ -83,6 +83,22 @@ func TestGoimportsLocal(t *testing.T) {
|
|||||||
ExpectHasIssue("testdata/goimports/goimports.go:8: File is not `goimports`-ed")
|
ExpectHasIssue("testdata/goimports/goimports.go:8: File is not `goimports`-ed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGciLocal(t *testing.T) {
|
||||||
|
sourcePath := filepath.Join(testdataDir, "gci", "gci.go")
|
||||||
|
args := []string{
|
||||||
|
"--disable-all", "--print-issued-lines=false", "--print-linter-name=false", "--out-format=line-number",
|
||||||
|
sourcePath,
|
||||||
|
}
|
||||||
|
rc := extractRunContextFromComments(t, sourcePath)
|
||||||
|
args = append(args, rc.args...)
|
||||||
|
|
||||||
|
cfg, err := yaml.Marshal(rc.config)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testshared.NewLintRunner(t).RunWithYamlConfig(string(cfg), args...).
|
||||||
|
ExpectHasIssue("testdata/gci/gci.go:8: File is not `gci`-ed")
|
||||||
|
}
|
||||||
|
|
||||||
func saveConfig(t *testing.T, cfg map[string]interface{}) (cfgPath string, finishFunc func()) {
|
func saveConfig(t *testing.T, cfg map[string]interface{}) (cfgPath string, finishFunc func()) {
|
||||||
f, err := ioutil.TempFile("", "golangci_lint_test")
|
f, err := ioutil.TempFile("", "golangci_lint_test")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
15
test/testdata/gci.go
vendored
Normal file
15
test/testdata/gci.go
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//args: -Egci
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GoimportsLocalTest() {
|
||||||
|
fmt.Print("x")
|
||||||
|
_ = config.Config{}
|
||||||
|
_ = errors.New("")
|
||||||
|
}
|
17
test/testdata/gci/gci.go
vendored
Normal file
17
test/testdata/gci/gci.go
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//args: -Egci
|
||||||
|
//config: linters-settings.gci.local-prefixes=github.com/golangci/golangci-lint
|
||||||
|
package gci
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GoimportsLocalTest() {
|
||||||
|
fmt.Print("x")
|
||||||
|
_ = config.Config{}
|
||||||
|
_ = errors.New("")
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user