Skip to content

Commit 40d6afb

Browse files
committed
dev: add suggested migration for linter configuration
1 parent 82147d5 commit 40d6afb

File tree

5 files changed

+145
-15
lines changed

5 files changed

+145
-15
lines changed

.golangci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,11 @@ linters:
191191
- path: pkg/lint/lintersdb/builder_linter.go
192192
text: "SA1019: wsl.NewV4 is deprecated: use NewV5 instead."
193193
linters:
194-
- staticcheck
194+
- staticcheck
195+
- path: pkg/golinters/wsl/wsl.go
196+
text: "SA1019: config.WSLv4Settings is deprecated: use WSLv5Settings instead."
197+
linters:
198+
- staticcheck
195199

196200
formatters:
197201
enable:

pkg/commands/run.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,17 @@ func (c *runCommand) printDeprecatedLinterMessages(enabledLinters map[string]*li
430430
}
431431

432432
c.log.Warnf("The linter '%s' is deprecated (since %s) due to: %s %s", name, lc.Deprecation.Since, lc.Deprecation.Message, extra)
433+
434+
if lc.Deprecation.ConfigSuggestion != nil {
435+
suggestion, err := lc.Deprecation.ConfigSuggestion()
436+
if err != nil {
437+
c.log.Errorf("New configuration suggestion error: %v", err)
438+
}
439+
440+
if suggestion != "" {
441+
c.log.Warnf("Suggested new configuration:\n%s", suggestion)
442+
}
443+
}
433444
}
434445
}
435446

pkg/golinters/wsl/wsl.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package wsl
22

33
import (
4+
"slices"
5+
46
wslv4 "github.com/bombsimon/wsl/v4"
7+
wslv5 "github.com/bombsimon/wsl/v5"
58

69
"github.com/golangci/golangci-lint/v2/pkg/config"
710
"github.com/golangci/golangci-lint/v2/pkg/goanalysis"
11+
"github.com/golangci/golangci-lint/v2/pkg/golinters/internal"
812
)
913

1014
// Deprecated: use NewV5 instead.
@@ -35,3 +39,67 @@ func NewV4(settings *config.WSLv4Settings) *goanalysis.Linter {
3539
NewLinterFromAnalyzer(wslv4.NewAnalyzer(conf)).
3640
WithLoadMode(goanalysis.LoadModeSyntax)
3741
}
42+
43+
// Only used the set YAML struct tags.
44+
type v5YAML struct {
45+
AllowFirstInBlock bool `yaml:"allow-first-in-block"`
46+
AllowWholeBlock bool `yaml:"allow-whole-block"`
47+
BranchMaxLines int `yaml:"branch-max-lines,omitempty"`
48+
CaseMaxLines int `yaml:"case-max-lines,omitempty"`
49+
Enable []string `yaml:"enable,omitempty"`
50+
Disable []string `yaml:"disable,omitempty"`
51+
}
52+
53+
func Migration(old *config.WSLv4Settings) any {
54+
if old == nil {
55+
return nil
56+
}
57+
58+
cfg := v5YAML{
59+
AllowFirstInBlock: true,
60+
AllowWholeBlock: false,
61+
BranchMaxLines: 2,
62+
CaseMaxLines: old.ForceCaseTrailingWhitespaceLimit,
63+
}
64+
65+
if !old.StrictAppend {
66+
cfg.Disable = append(cfg.Disable, wslv5.CheckAppend.String())
67+
}
68+
69+
if old.AllowAssignAndAnythingCuddle {
70+
cfg.Disable = append(cfg.Disable, wslv5.CheckAssign.String())
71+
}
72+
73+
if old.AllowMultiLineAssignCuddle {
74+
internal.LinterLogger.Warnf("`allow-multiline-assign` is deprecated and always allowed in wsl >= v5")
75+
}
76+
77+
if old.AllowTrailingComment {
78+
internal.LinterLogger.Warnf("`allow-trailing-comment` is deprecated and always allowed in wsl >= v5")
79+
}
80+
81+
if old.AllowSeparatedLeadingComment {
82+
internal.LinterLogger.Warnf("`allow-separated-leading-comment` is deprecated and always allowed in wsl >= v5")
83+
}
84+
85+
if old.AllowCuddleDeclaration {
86+
cfg.Disable = append(cfg.Disable, wslv5.CheckDecl.String())
87+
}
88+
89+
if old.ForceCuddleErrCheckAndAssign {
90+
cfg.Enable = append(cfg.Enable, wslv5.CheckErr.String())
91+
}
92+
93+
if old.ForceExclusiveShortDeclarations {
94+
cfg.Enable = append(cfg.Enable, wslv5.CheckAssignExclusive.String())
95+
}
96+
97+
if !old.AllowAssignAndCallCuddle {
98+
cfg.Enable = append(cfg.Enable, wslv5.CheckAssignExpr.String())
99+
}
100+
101+
slices.Sort(cfg.Enable)
102+
slices.Sort(cfg.Disable)
103+
104+
return cfg
105+
}

pkg/lint/linter/config.go

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package linter
22

33
import (
4+
"bytes"
45
"fmt"
56

67
"golang.org/x/tools/go/packages"
8+
"gopkg.in/yaml.v3"
79

810
"github.com/golangci/golangci-lint/v2/pkg/config"
911
)
@@ -20,10 +22,11 @@ const (
2022
)
2123

2224
type Deprecation struct {
23-
Since string
24-
Message string
25-
Replacement string
26-
Level DeprecationLevel
25+
Since string
26+
Message string
27+
Replacement string
28+
Level DeprecationLevel
29+
ConfigSuggestion func() (string, error)
2730
}
2831

2932
type Config struct {
@@ -119,22 +122,26 @@ func (lc *Config) WithSince(version string) *Config {
119122
return lc
120123
}
121124

122-
func (lc *Config) Deprecated(message, version, replacement string, level DeprecationLevel) *Config {
125+
func (lc *Config) Deprecated(message, version string, level DeprecationLevel, opts ...func(*Deprecation)) *Config {
123126
lc.Deprecation = &Deprecation{
124-
Since: version,
125-
Message: message,
126-
Replacement: replacement,
127-
Level: level,
127+
Since: version,
128+
Message: message,
129+
Level: level,
130+
}
131+
132+
for _, opt := range opts {
133+
opt(lc.Deprecation)
128134
}
135+
129136
return lc
130137
}
131138

132-
func (lc *Config) DeprecatedWarning(message, version, replacement string) *Config {
133-
return lc.Deprecated(message, version, replacement, DeprecationWarning)
139+
func (lc *Config) DeprecatedWarning(message, version string, opts ...func(*Deprecation)) *Config {
140+
return lc.Deprecated(message, version, DeprecationWarning, opts...)
134141
}
135142

136-
func (lc *Config) DeprecatedError(message, version, replacement string) *Config {
137-
return lc.Deprecated(message, version, replacement, DeprecationError)
143+
func (lc *Config) DeprecatedError(message, version string, opts ...func(*Deprecation)) *Config {
144+
return lc.Deprecated(message, version, DeprecationError, opts...)
138145
}
139146

140147
func (lc *Config) IsDeprecated() bool {
@@ -160,6 +167,45 @@ func (lc *Config) WithNoopFallback(cfg *config.Config, cond func(cfg *config.Con
160167
return lc
161168
}
162169

170+
func Replacement[T any](replacement string, mgr func(T) any, data T) func(*Deprecation) {
171+
return func(d *Deprecation) {
172+
if replacement == "" {
173+
return
174+
}
175+
176+
d.Replacement = replacement
177+
178+
if mgr == nil {
179+
return
180+
}
181+
182+
d.ConfigSuggestion = func() (string, error) {
183+
buf := bytes.NewBuffer([]byte{})
184+
185+
encoder := yaml.NewEncoder(buf)
186+
encoder.SetIndent(2)
187+
188+
suggestion := map[string]any{
189+
"linters": map[string]any{
190+
"enable": []string{
191+
d.Replacement,
192+
},
193+
"settings": map[string]any{
194+
d.Replacement: mgr(data),
195+
},
196+
},
197+
}
198+
199+
err := encoder.Encode(suggestion)
200+
if err != nil {
201+
return "", fmt.Errorf("%s: invalid configuration: %w", d.Replacement, err)
202+
}
203+
204+
return buf.String(), nil
205+
}
206+
}
207+
}
208+
163209
func IsGoLowerThanGo122() func(cfg *config.Config) error {
164210
return isGoLowerThanGo("1.22")
165211
}

pkg/lint/lintersdb/builder_linter.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,8 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
692692
WithURL("https://github.com/tomarrell/wrapcheck"),
693693

694694
linter.NewConfig(wsl.NewV4(&cfg.Linters.Settings.WSL)).
695-
DeprecatedWarning("new major version.", "v2.2.0", "wsl_v5").
695+
DeprecatedWarning("new major version.", "v2.2.0",
696+
linter.Replacement("wsl_v5", wsl.Migration, &cfg.Linters.Settings.WSL)).
696697
WithSince("v1.20.0").
697698
WithAutoFix().
698699
WithURL("https://github.com/bombsimon/wsl"),

0 commit comments

Comments
 (0)