Skip to content

Commit 8a76e20

Browse files
committed
feat: post-process formatters
1 parent f996a66 commit 8a76e20

File tree

11 files changed

+357
-28
lines changed

11 files changed

+357
-28
lines changed

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ require (
4444
github.com/gofrs/flock v0.12.1
4545
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a
4646
github.com/golangci/go-printf-func-name v0.1.0
47-
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9
47+
github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9
4848
github.com/golangci/misspell v0.6.0
4949
github.com/golangci/plugin-module-register v0.1.1
5050
github.com/golangci/revgrep v0.5.3
@@ -65,7 +65,7 @@ require (
6565
github.com/kyoh86/exportloopref v0.1.11
6666
github.com/lasiar/canonicalheader v1.1.2
6767
github.com/ldez/gomoddirectives v0.6.0
68-
github.com/ldez/grignotin v0.6.0
68+
github.com/ldez/grignotin v0.7.0
6969
github.com/ldez/tagliatelle v0.7.1
7070
github.com/ldez/usetesting v0.2.2
7171
github.com/leonklingele/grouper v1.1.2

go.sum

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

pkg/config/config.go

+32-22
Original file line numberDiff line numberDiff line change
@@ -93,32 +93,13 @@ func detectGoVersion() string {
9393
// else it returns `go` version if present,
9494
// else it returns empty.
9595
func detectGoVersionFromGoMod() string {
96-
info, err := gomod.GetModuleInfo()
97-
if err != nil {
98-
return ""
99-
}
100-
101-
wd, err := os.Getwd()
96+
modPath, err := gomod.GetGoModPath()
10297
if err != nil {
98+
modPath = detectGoModFallback()
10399
return ""
104100
}
105101

106-
slices.SortFunc(info, func(a, b gomod.ModInfo) int {
107-
return cmp.Compare(len(b.Path), len(a.Path))
108-
})
109-
110-
goMod := info[0]
111-
for _, m := range info {
112-
if !strings.HasPrefix(wd, m.Dir) {
113-
continue
114-
}
115-
116-
goMod = m
117-
118-
break
119-
}
120-
121-
file, err := parseGoMod(goMod.GoMod)
102+
file, err := parseGoMod(modPath)
122103
if err != nil {
123104
return ""
124105
}
@@ -144,3 +125,32 @@ func parseGoMod(goMod string) (*modfile.File, error) {
144125

145126
return modfile.Parse("go.mod", raw, nil)
146127
}
128+
129+
func detectGoModFallback() string {
130+
info, err := gomod.GetModuleInfo()
131+
if err != nil {
132+
return ""
133+
}
134+
135+
wd, err := os.Getwd()
136+
if err != nil {
137+
return ""
138+
}
139+
140+
slices.SortFunc(info, func(a, b gomod.ModInfo) int {
141+
return cmp.Compare(len(b.Path), len(a.Path))
142+
})
143+
144+
goMod := info[0]
145+
for _, m := range info {
146+
if !strings.HasPrefix(wd, m.Dir) {
147+
continue
148+
}
149+
150+
goMod = m
151+
152+
break
153+
}
154+
155+
return goMod.GoMod
156+
}

pkg/goformatters/formaters.go

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package goformatters
2+
3+
type Formatter interface {
4+
Name() string
5+
Format(filename string, src []byte) ([]byte, error)
6+
}

pkg/goformatters/gci/gci.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package gci
2+
3+
import (
4+
gcicfg "github.com/daixiang0/gci/pkg/config"
5+
"github.com/daixiang0/gci/pkg/gci"
6+
"github.com/ldez/grignotin/gomod"
7+
8+
"github.com/golangci/golangci-lint/pkg/config"
9+
)
10+
11+
const Name = "gci"
12+
13+
type Formatter struct {
14+
config *gcicfg.Config
15+
}
16+
17+
func New(cfg config.GciSettings) (*Formatter, error) {
18+
modPath, err := gomod.GetModulePath()
19+
if err != nil {
20+
return nil, err
21+
}
22+
23+
parsedCfg, err := gcicfg.YamlConfig{
24+
Cfg: gcicfg.BoolConfig{
25+
NoInlineComments: cfg.NoInlineComments,
26+
NoPrefixComments: cfg.NoPrefixComments,
27+
SkipGenerated: cfg.SkipGenerated,
28+
CustomOrder: cfg.CustomOrder,
29+
NoLexOrder: cfg.NoLexOrder,
30+
},
31+
SectionStrings: cfg.Sections,
32+
ModPath: modPath,
33+
}.Parse()
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
return &Formatter{config: parsedCfg}, nil
39+
}
40+
41+
func (*Formatter) Name() string {
42+
return Name
43+
}
44+
45+
func (f *Formatter) Format(filename string, src []byte) ([]byte, error) {
46+
_, formatted, err := gci.LoadFormat(src, filename, *f.config)
47+
return formatted, err
48+
}

pkg/goformatters/gofmt/gofmt.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package gofmt
2+
3+
import (
4+
"github.com/golangci/gofmt/gofmt"
5+
6+
"github.com/golangci/golangci-lint/pkg/config"
7+
)
8+
9+
const Name = "gofmt"
10+
11+
type Formatter struct {
12+
options gofmt.Options
13+
}
14+
15+
func New(cfg config.GoFmtSettings) *Formatter {
16+
var rewriteRules []gofmt.RewriteRule
17+
for _, rule := range cfg.RewriteRules {
18+
rewriteRules = append(rewriteRules, gofmt.RewriteRule(rule))
19+
}
20+
21+
return &Formatter{
22+
options: gofmt.Options{
23+
NeedSimplify: cfg.Simplify,
24+
RewriteRules: rewriteRules,
25+
},
26+
}
27+
}
28+
29+
func (*Formatter) Name() string {
30+
return Name
31+
}
32+
33+
func (f *Formatter) Format(filename string, src []byte) ([]byte, error) {
34+
return gofmt.Source(filename, src, f.options)
35+
}

pkg/goformatters/gofumpt/gofumpt.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package gofumpt
2+
3+
import (
4+
"strings"
5+
6+
gofumpt "mvdan.cc/gofumpt/format"
7+
8+
"github.com/golangci/golangci-lint/pkg/config"
9+
)
10+
11+
const Name = "gofumpt"
12+
13+
type Formatter struct {
14+
options gofumpt.Options
15+
}
16+
17+
func New(cfg config.GofumptSettings, goVersion string) *Formatter {
18+
return &Formatter{
19+
options: gofumpt.Options{
20+
LangVersion: getLangVersion(goVersion),
21+
ModulePath: cfg.ModulePath,
22+
ExtraRules: cfg.ExtraRules,
23+
},
24+
}
25+
}
26+
27+
func (*Formatter) Name() string {
28+
return Name
29+
}
30+
31+
func (f *Formatter) Format(_ string, src []byte) ([]byte, error) {
32+
return gofumpt.Source(src, f.options)
33+
}
34+
35+
// modified copy of pkg/golinters/gofumpt/gofumpt.go
36+
func getLangVersion(v string) string {
37+
if v == "" {
38+
// TODO: defaults to "1.15", in the future (v2) must be removed.
39+
return "go1.15"
40+
}
41+
42+
return "go" + strings.TrimPrefix(v, "go")
43+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package goimports
2+
3+
import (
4+
"golang.org/x/tools/imports"
5+
)
6+
7+
const Name = "goimports"
8+
9+
type Formatter struct{}
10+
11+
func New() *Formatter {
12+
return &Formatter{}
13+
}
14+
15+
func (*Formatter) Name() string {
16+
return Name
17+
}
18+
19+
func (*Formatter) Format(filename string, src []byte) ([]byte, error) {
20+
// The `imports.LocalPrefix` (`settings.LocalPrefixes`) is a global var.
21+
return imports.Process(filename, src, nil)
22+
}

pkg/lint/runner.go

+7
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *gouti
6060
return nil, fmt.Errorf("failed to get enabled linters: %w", err)
6161
}
6262

63+
formatter, err := processors.NewFormatter(log, cfg, fileCache, enabledLinters)
64+
if err != nil {
65+
return nil, fmt.Errorf("failed to create formatter: %w", err)
66+
}
67+
6368
return &Runner{
6469
Processors: []processors.Processor{
6570
processors.NewCgo(goenv),
@@ -95,6 +100,8 @@ func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *gouti
95100

96101
// The fixer still needs to see paths for the issues that are relative to the current directory.
97102
processors.NewFixer(cfg, log, fileCache),
103+
// The fommatter needs to be after the fixer and the last processor that use fileCache.
104+
formatter,
98105

99106
// Now we can modify the issues for output.
100107
processors.NewPathPrefixer(cfg.Output.PathPrefix),

pkg/result/processors/fixer.go

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import (
1313
"os"
1414
"slices"
1515

16+
"github.com/golangci/golangci-lint/pkg/goformatters/gci"
17+
"github.com/golangci/golangci-lint/pkg/goformatters/gofmt"
18+
"github.com/golangci/golangci-lint/pkg/goformatters/gofumpt"
19+
"github.com/golangci/golangci-lint/pkg/goformatters/goimports"
1620
"golang.org/x/exp/maps"
1721

1822
"github.com/golangci/golangci-lint/internal/x/tools/diff"
@@ -71,11 +75,18 @@ func (p Fixer) process(issues []result.Issue) ([]result.Issue, error) {
7175
// filenames / linters / edits
7276
editsByLinter := make(map[string]map[string][]diff.Edit)
7377

78+
formatters := []string{gofumpt.Name, goimports.Name, gofmt.Name, gci.Name}
79+
7480
var notFixableIssues []result.Issue
7581

7682
for i := range issues {
7783
issue := issues[i]
7884

85+
if slices.Contains(formatters, issue.FromLinter) {
86+
notFixableIssues = append(notFixableIssues, issue)
87+
continue
88+
}
89+
7990
if issue.SuggestedFixes == nil || skipNoTextEdit(&issue) {
8091
notFixableIssues = append(notFixableIssues, issue)
8192
continue

0 commit comments

Comments
 (0)