Skip to content

Commit 6bae718

Browse files
authored
feat: format fixed files with the same formatters as the issues related to formatting (#5267)
1 parent 618f29a commit 6bae718

File tree

4 files changed

+108
-139
lines changed

4 files changed

+108
-139
lines changed

pkg/goformatters/meta_formatter.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package goformatters
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"go/format"
7+
8+
"github.com/golangci/golangci-lint/pkg/config"
9+
"github.com/golangci/golangci-lint/pkg/goformatters/gci"
10+
"github.com/golangci/golangci-lint/pkg/goformatters/gofmt"
11+
"github.com/golangci/golangci-lint/pkg/goformatters/gofumpt"
12+
"github.com/golangci/golangci-lint/pkg/goformatters/goimports"
13+
"github.com/golangci/golangci-lint/pkg/lint/linter"
14+
"github.com/golangci/golangci-lint/pkg/logutils"
15+
)
16+
17+
type MetaFormatter struct {
18+
log logutils.Log
19+
formatters []Formatter
20+
}
21+
22+
func NewMetaFormatter(log logutils.Log, cfg *config.Config, enabledLinters map[string]*linter.Config) (*MetaFormatter, error) {
23+
m := &MetaFormatter{log: log}
24+
25+
if _, ok := enabledLinters[gofmt.Name]; ok {
26+
m.formatters = append(m.formatters, gofmt.New(cfg.LintersSettings.Gofmt))
27+
}
28+
29+
if _, ok := enabledLinters[gofumpt.Name]; ok {
30+
m.formatters = append(m.formatters, gofumpt.New(cfg.LintersSettings.Gofumpt, cfg.Run.Go))
31+
}
32+
33+
if _, ok := enabledLinters[goimports.Name]; ok {
34+
m.formatters = append(m.formatters, goimports.New())
35+
}
36+
37+
// gci is a last because the only goal of gci is to handle imports.
38+
if _, ok := enabledLinters[gci.Name]; ok {
39+
formatter, err := gci.New(cfg.LintersSettings.Gci)
40+
if err != nil {
41+
return nil, fmt.Errorf("gci: creating formatter: %w", err)
42+
}
43+
44+
m.formatters = append(m.formatters, formatter)
45+
}
46+
47+
return m, nil
48+
}
49+
50+
func (m *MetaFormatter) Format(filename string, src []byte) []byte {
51+
if len(m.formatters) == 0 {
52+
data, err := format.Source(src)
53+
if err != nil {
54+
m.log.Warnf("(fmt) formatting file %s: %v", filename, err)
55+
return src
56+
}
57+
58+
return data
59+
}
60+
61+
data := bytes.Clone(src)
62+
63+
for _, formatter := range m.formatters {
64+
formatted, err := formatter.Format(filename, data)
65+
if err != nil {
66+
m.log.Warnf("(%s) formatting file %s: %v", formatter.Name(), filename, err)
67+
continue
68+
}
69+
70+
data = formatted
71+
}
72+
73+
return data
74+
}

pkg/lint/runner.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/golangci/golangci-lint/internal/errorutil"
1111
"github.com/golangci/golangci-lint/pkg/config"
1212
"github.com/golangci/golangci-lint/pkg/fsutils"
13+
"github.com/golangci/golangci-lint/pkg/goformatters"
1314
"github.com/golangci/golangci-lint/pkg/goutil"
1415
"github.com/golangci/golangci-lint/pkg/lint/linter"
1516
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
@@ -60,9 +61,9 @@ func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *gouti
6061
return nil, fmt.Errorf("failed to get enabled linters: %w", err)
6162
}
6263

63-
formatter, err := processors.NewFormatter(log, cfg, enabledLinters)
64+
metaFormatter, err := goformatters.NewMetaFormatter(log, cfg, enabledLinters)
6465
if err != nil {
65-
return nil, fmt.Errorf("failed to create formatter: %w", err)
66+
return nil, fmt.Errorf("failed to create meta-formatter: %w", err)
6667
}
6768

6869
return &Runner{
@@ -99,9 +100,7 @@ func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *gouti
99100
processors.NewSeverity(log.Child(logutils.DebugKeySeverityRules), files, &cfg.Severity),
100101

101102
// The fixer still needs to see paths for the issues that are relative to the current directory.
102-
processors.NewFixer(cfg, log, fileCache),
103-
// The formatter needs to be after the fixer and the last processor that write files.
104-
formatter,
103+
processors.NewFixer(cfg, log, fileCache, metaFormatter),
105104

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

pkg/result/processors/fixer.go

+30-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ package processors
99
import (
1010
"errors"
1111
"fmt"
12-
"go/format"
1312
"os"
1413
"slices"
1514

@@ -18,6 +17,7 @@ import (
1817
"github.com/golangci/golangci-lint/internal/x/tools/diff"
1918
"github.com/golangci/golangci-lint/pkg/config"
2019
"github.com/golangci/golangci-lint/pkg/fsutils"
20+
"github.com/golangci/golangci-lint/pkg/goformatters"
2121
"github.com/golangci/golangci-lint/pkg/goformatters/gci"
2222
"github.com/golangci/golangci-lint/pkg/goformatters/gofmt"
2323
"github.com/golangci/golangci-lint/pkg/goformatters/gofumpt"
@@ -36,14 +36,16 @@ type Fixer struct {
3636
log logutils.Log
3737
fileCache *fsutils.FileCache
3838
sw *timeutils.Stopwatch
39+
formatter *goformatters.MetaFormatter
3940
}
4041

41-
func NewFixer(cfg *config.Config, log logutils.Log, fileCache *fsutils.FileCache) *Fixer {
42+
func NewFixer(cfg *config.Config, log logutils.Log, fileCache *fsutils.FileCache, formatter *goformatters.MetaFormatter) *Fixer {
4243
return &Fixer{
4344
cfg: cfg,
4445
log: log,
4546
fileCache: fileCache,
4647
sw: timeutils.NewStopwatch("fixer", log),
48+
formatter: formatter,
4749
}
4850
}
4951

@@ -79,11 +81,13 @@ func (p Fixer) process(issues []result.Issue) ([]result.Issue, error) {
7981

8082
var notFixableIssues []result.Issue
8183

84+
toBeFormattedFiles := make(map[string]struct{})
85+
8286
for i := range issues {
8387
issue := issues[i]
8488

8589
if slices.Contains(formatters, issue.FromLinter) {
86-
notFixableIssues = append(notFixableIssues, issue)
90+
toBeFormattedFiles[issue.FilePath()] = struct{}{}
8791
continue
8892
}
8993

@@ -173,6 +177,8 @@ func (p Fixer) process(issues []result.Issue) ([]result.Issue, error) {
173177

174178
var editError error
175179

180+
var formattedFiles []string
181+
176182
// Now we've got a set of valid edits for each file. Apply them.
177183
for path, edits := range editsByPath {
178184
contents, err := p.fileCache.GetFileBytes(path)
@@ -188,14 +194,32 @@ func (p Fixer) process(issues []result.Issue) ([]result.Issue, error) {
188194
}
189195

190196
// Try to format the file.
191-
if formatted, err := format.Source(out); err == nil {
192-
out = formatted
193-
}
197+
out = p.formatter.Format(path, out)
194198

195199
if err := os.WriteFile(path, out, filePerm); err != nil {
196200
editError = errors.Join(editError, fmt.Errorf("%s: %w", path, err))
197201
continue
198202
}
203+
204+
formattedFiles = append(formattedFiles, path)
205+
}
206+
207+
for path := range toBeFormattedFiles {
208+
// Skips files already formatted by the previous fix step.
209+
if !slices.Contains(formattedFiles, path) {
210+
content, err := p.fileCache.GetFileBytes(path)
211+
if err != nil {
212+
p.log.Warnf("Error reading file %s: %v", path, err)
213+
continue
214+
}
215+
216+
out := p.formatter.Format(path, content)
217+
218+
if err := os.WriteFile(path, out, filePerm); err != nil {
219+
editError = errors.Join(editError, fmt.Errorf("%s: %w", path, err))
220+
continue
221+
}
222+
}
199223
}
200224

201225
return notFixableIssues, editError

pkg/result/processors/formatter.go

-128
This file was deleted.

0 commit comments

Comments
 (0)