feat: log an error when using previously deprecated linters (#4681)

This commit is contained in:
Ludovic Fernandez 2024-04-28 22:06:06 +02:00 committed by GitHub
parent e4dae2a211
commit 38fac89315
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 74 additions and 28 deletions

View File

@ -27,10 +27,19 @@ const (
// LastLinter nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives. // LastLinter nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives.
const LastLinter = "nolintlint" const LastLinter = "nolintlint"
type DeprecationLevel int
const (
DeprecationNone DeprecationLevel = iota
DeprecationWarning
DeprecationError
)
type Deprecation struct { type Deprecation struct {
Since string Since string
Message string Message string
Replacement string Replacement string
Level DeprecationLevel
} }
type Config struct { type Config struct {
@ -113,15 +122,24 @@ func (lc *Config) WithSince(version string) *Config {
return lc return lc
} }
func (lc *Config) Deprecated(message, version, replacement string) *Config { func (lc *Config) Deprecated(message, version, replacement string, level DeprecationLevel) *Config {
lc.Deprecation = &Deprecation{ lc.Deprecation = &Deprecation{
Since: version, Since: version,
Message: message, Message: message,
Replacement: replacement, Replacement: replacement,
Level: level,
} }
return lc return lc
} }
func (lc *Config) DeprecatedWarning(message, version, replacement string) *Config {
return lc.Deprecated(message, version, replacement, DeprecationWarning)
}
func (lc *Config) DeprecatedError(message, version, replacement string) *Config {
return lc.Deprecated(message, version, replacement, DeprecationError)
}
func (lc *Config) IsDeprecated() bool { func (lc *Config) IsDeprecated() bool {
return lc.Deprecation != nil return lc.Deprecation != nil
} }

View File

@ -17,6 +17,7 @@ type Noop struct {
name string name string
desc string desc string
reason string reason string
level DeprecationLevel
} }
func NewNoop(l Linter, reason string) Noop { func NewNoop(l Linter, reason string) Noop {
@ -27,11 +28,12 @@ func NewNoop(l Linter, reason string) Noop {
} }
} }
func NewNoopDeprecated(name string, cfg *config.Config) Noop { func NewNoopDeprecated(name string, cfg *config.Config, level DeprecationLevel) Noop {
noop := Noop{ noop := Noop{
name: name, name: name,
desc: "Deprecated", desc: "Deprecated",
reason: "This linter is fully inactivated: it will not produce any reports.", reason: "This linter is fully inactivated: it will not produce any reports.",
level: level,
} }
if cfg.InternalCmdTest { if cfg.InternalCmdTest {
@ -42,9 +44,17 @@ func NewNoopDeprecated(name string, cfg *config.Config) Noop {
} }
func (n Noop) Run(_ context.Context, lintCtx *Context) ([]result.Issue, error) { func (n Noop) Run(_ context.Context, lintCtx *Context) ([]result.Issue, error) {
if n.reason != "" { if n.reason == "" {
return nil, nil
}
switch n.level {
case DeprecationError:
lintCtx.Log.Errorf("%s: %s", n.name, n.reason)
default:
lintCtx.Log.Warnf("%s: %s", n.name, n.reason) lintCtx.Log.Warnf("%s: %s", n.name, n.reason)
} }
return nil, nil return nil, nil
} }

View File

@ -190,12 +190,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithPresets(linter.PresetFormatting, linter.PresetStyle). WithPresets(linter.PresetFormatting, linter.PresetStyle).
WithURL("https://gitlab.com/bosi/decorder"), WithURL("https://gitlab.com/bosi/decorder"),
linter.NewConfig(linter.NewNoopDeprecated("deadcode", cfg)). linter.NewConfig(linter.NewNoopDeprecated("deadcode", cfg, linter.DeprecationError)).
WithSince("v1.0.0"). WithSince("v1.0.0").
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithPresets(linter.PresetUnused). WithPresets(linter.PresetUnused).
WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode"). WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode").
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), DeprecatedError("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
linter.NewConfig(depguard.New(&cfg.LintersSettings.Depguard)). linter.NewConfig(depguard.New(&cfg.LintersSettings.Depguard)).
WithSince("v1.4.0"). WithSince("v1.4.0").
@ -253,7 +253,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithPresets(linter.PresetSQL). WithPresets(linter.PresetSQL).
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithURL("https://github.com/1uf3/execinquery"). WithURL("https://github.com/1uf3/execinquery").
Deprecated("The repository of the linter has been archived by the owner.", "v1.58.0", ""), DeprecatedWarning("The repository of the linter has been archived by the owner.", "v1.58.0", ""),
linter.NewConfig(exhaustive.New(&cfg.LintersSettings.Exhaustive)). linter.NewConfig(exhaustive.New(&cfg.LintersSettings.Exhaustive)).
WithSince(" v1.28.0"). WithSince(" v1.28.0").
@ -261,12 +261,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithURL("https://github.com/nishanths/exhaustive"), WithURL("https://github.com/nishanths/exhaustive"),
linter.NewConfig(linter.NewNoopDeprecated("exhaustivestruct", cfg)). linter.NewConfig(linter.NewNoopDeprecated("exhaustivestruct", cfg, linter.DeprecationError)).
WithSince("v1.32.0"). WithSince("v1.32.0").
WithPresets(linter.PresetStyle, linter.PresetTest). WithPresets(linter.PresetStyle, linter.PresetTest).
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithURL("https://github.com/mbilski/exhaustivestruct"). WithURL("https://github.com/mbilski/exhaustivestruct").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.46.0", "exhaustruct"), DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.46.0", "exhaustruct"),
linter.NewConfig(exhaustruct.New(&cfg.LintersSettings.Exhaustruct)). linter.NewConfig(exhaustruct.New(&cfg.LintersSettings.Exhaustruct)).
WithSince("v1.46.0"). WithSince("v1.46.0").
@ -403,12 +403,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithAutoFix(). WithAutoFix().
WithURL("https://pkg.go.dev/golang.org/x/tools/cmd/goimports"), WithURL("https://pkg.go.dev/golang.org/x/tools/cmd/goimports"),
linter.NewConfig(linter.NewNoopDeprecated("golint", cfg)). linter.NewConfig(linter.NewNoopDeprecated("golint", cfg, linter.DeprecationError)).
WithSince("v1.0.0"). WithSince("v1.0.0").
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/golang/lint"). WithURL("https://github.com/golang/lint").
Deprecated("The repository of the linter has been archived by the owner.", "v1.41.0", "revive"), DeprecatedError("The repository of the linter has been archived by the owner.", "v1.41.0", "revive"),
linter.NewConfig(mnd.New(&cfg.LintersSettings.Mnd)). linter.NewConfig(mnd.New(&cfg.LintersSettings.Mnd)).
WithSince("v1.22.0"). WithSince("v1.22.0").
@ -418,8 +418,8 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
linter.NewConfig(mnd.NewGoMND(&cfg.LintersSettings.Gomnd)). linter.NewConfig(mnd.NewGoMND(&cfg.LintersSettings.Gomnd)).
WithSince("v1.22.0"). WithSince("v1.22.0").
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
Deprecated("The linter has been renamed.", "v1.58.0", "mnd"). WithURL("https://github.com/tommy-muehle/go-mnd").
WithURL("https://github.com/tommy-muehle/go-mnd"), DeprecatedWarning("The linter has been renamed.", "v1.58.0", "mnd"),
linter.NewConfig(gomoddirectives.New(&cfg.LintersSettings.GoModDirectives)). linter.NewConfig(gomoddirectives.New(&cfg.LintersSettings.GoModDirectives)).
WithSince("v1.39.0"). WithSince("v1.39.0").
@ -470,11 +470,11 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/leonklingele/grouper"), WithURL("https://github.com/leonklingele/grouper"),
linter.NewConfig(linter.NewNoopDeprecated("ifshort", cfg)). linter.NewConfig(linter.NewNoopDeprecated("ifshort", cfg, linter.DeprecationError)).
WithSince("v1.36.0"). WithSince("v1.36.0").
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/esimonov/ifshort"). WithURL("https://github.com/esimonov/ifshort").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.0", ""), DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.48.0", ""),
linter.NewConfig(importas.New(&cfg.LintersSettings.ImportAs)). linter.NewConfig(importas.New(&cfg.LintersSettings.ImportAs)).
WithSince("v1.38.0"). WithSince("v1.38.0").
@ -498,12 +498,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/sashamelentyev/interfacebloat"), WithURL("https://github.com/sashamelentyev/interfacebloat"),
linter.NewConfig(linter.NewNoopDeprecated("interfacer", cfg)). linter.NewConfig(linter.NewNoopDeprecated("interfacer", cfg, linter.DeprecationError)).
WithSince("v1.0.0"). WithSince("v1.0.0").
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/mvdan/interfacer"). WithURL("https://github.com/mvdan/interfacer").
Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", ""), DeprecatedError("The repository of the linter has been archived by the owner.", "v1.38.0", ""),
linter.NewConfig(intrange.New()). linter.NewConfig(intrange.New()).
WithSince("v1.57.0"). WithSince("v1.57.0").
@ -538,12 +538,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithURL("https://github.com/ashanbrown/makezero"), WithURL("https://github.com/ashanbrown/makezero"),
linter.NewConfig(linter.NewNoopDeprecated("maligned", cfg)). linter.NewConfig(linter.NewNoopDeprecated("maligned", cfg, linter.DeprecationError)).
WithSince("v1.0.0"). WithSince("v1.0.0").
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithPresets(linter.PresetPerformance). WithPresets(linter.PresetPerformance).
WithURL("https://github.com/mdempsky/maligned"). WithURL("https://github.com/mdempsky/maligned").
Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", "govet 'fieldalignment'"), DeprecatedError("The repository of the linter has been archived by the owner.", "v1.38.0", "govet 'fieldalignment'"),
linter.NewConfig(mirror.New()). linter.NewConfig(mirror.New()).
WithSince("v1.53.0"). WithSince("v1.53.0").
@ -603,11 +603,11 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/firefart/nonamedreturns"), WithURL("https://github.com/firefart/nonamedreturns"),
linter.NewConfig(linter.NewNoopDeprecated("nosnakecase", cfg)). linter.NewConfig(linter.NewNoopDeprecated("nosnakecase", cfg, linter.DeprecationError)).
WithSince("v1.47.0"). WithSince("v1.47.0").
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/sivchari/nosnakecase"). WithURL("https://github.com/sivchari/nosnakecase").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.1", "revive 'var-naming'"), DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.48.1", "revive 'var-naming'"),
linter.NewConfig(nosprintfhostport.New()). linter.NewConfig(nosprintfhostport.New()).
WithSince("v1.46.0"). WithSince("v1.46.0").
@ -672,11 +672,11 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithPresets(linter.PresetStyle, linter.PresetFormatting). WithPresets(linter.PresetStyle, linter.PresetFormatting).
WithURL("https://github.com/go-simpler/sloglint"), WithURL("https://github.com/go-simpler/sloglint"),
linter.NewConfig(linter.NewNoopDeprecated("scopelint", cfg)). linter.NewConfig(linter.NewNoopDeprecated("scopelint", cfg, linter.DeprecationError)).
WithSince("v1.12.0"). WithSince("v1.12.0").
WithPresets(linter.PresetBugs). WithPresets(linter.PresetBugs).
WithURL("https://github.com/kyoh86/scopelint"). WithURL("https://github.com/kyoh86/scopelint").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.39.0", "exportloopref"), DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.39.0", "exportloopref"),
linter.NewConfig(sqlclosecheck.New()). linter.NewConfig(sqlclosecheck.New()).
WithSince("v1.28.0"). WithSince("v1.28.0").
@ -698,12 +698,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithAlternativeNames(megacheckName). WithAlternativeNames(megacheckName).
WithURL("https://staticcheck.io/"), WithURL("https://staticcheck.io/"),
linter.NewConfig(linter.NewNoopDeprecated("structcheck", cfg)). linter.NewConfig(linter.NewNoopDeprecated("structcheck", cfg, linter.DeprecationError)).
WithSince("v1.0.0"). WithSince("v1.0.0").
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithPresets(linter.PresetUnused). WithPresets(linter.PresetUnused).
WithURL("https://github.com/opennota/check"). WithURL("https://github.com/opennota/check").
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), DeprecatedError("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
linter.NewConfig(stylecheck.New(&cfg.LintersSettings.Stylecheck)). linter.NewConfig(stylecheck.New(&cfg.LintersSettings.Stylecheck)).
WithSince("v1.20.0"). WithSince("v1.20.0").
@ -788,12 +788,12 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/sashamelentyev/usestdlibvars"), WithURL("https://github.com/sashamelentyev/usestdlibvars"),
linter.NewConfig(linter.NewNoopDeprecated("varcheck", cfg)). linter.NewConfig(linter.NewNoopDeprecated("varcheck", cfg, linter.DeprecationError)).
WithSince("v1.0.0"). WithSince("v1.0.0").
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().
WithPresets(linter.PresetUnused). WithPresets(linter.PresetUnused).
WithURL("https://github.com/opennota/check"). WithURL("https://github.com/opennota/check").
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), DeprecatedError("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
linter.NewConfig(varnamelen.New(&cfg.LintersSettings.Varnamelen)). linter.NewConfig(varnamelen.New(&cfg.LintersSettings.Varnamelen)).
WithSince("v1.43.0"). WithSince("v1.43.0").

View File

@ -303,6 +303,10 @@ func AllPresets() []string {
func linterConfigsToMap(lcs []*linter.Config) map[string]*linter.Config { func linterConfigsToMap(lcs []*linter.Config) map[string]*linter.Config {
ret := map[string]*linter.Config{} ret := map[string]*linter.Config{}
for _, lc := range lcs { for _, lc := range lcs {
if lc.IsDeprecated() && lc.Deprecation.Level > linter.DeprecationWarning {
continue
}
ret[lc.Name()] = lc ret[lc.Name()] = lc
} }

View File

@ -10,6 +10,7 @@ import (
"path/filepath" "path/filepath"
"github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/lint/lintersdb" "github.com/golangci/golangci-lint/pkg/lint/lintersdb"
"github.com/golangci/golangci-lint/scripts/website/types" "github.com/golangci/golangci-lint/scripts/website/types"
) )
@ -36,6 +37,10 @@ func saveLinters() error {
var wraps []types.LinterWrapper var wraps []types.LinterWrapper
for _, l := range linters { for _, l := range linters {
if l.IsDeprecated() && l.Deprecation.Level > linter.DeprecationWarning {
continue
}
wrapper := types.LinterWrapper{ wrapper := types.LinterWrapper{
Name: l.Linter.Name(), Name: l.Linter.Name(),
Desc: l.Linter.Desc(), Desc: l.Linter.Desc(),

View File

@ -8,6 +8,7 @@ import (
"golang.org/x/exp/maps" "golang.org/x/exp/maps"
"github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/lint/lintersdb" "github.com/golangci/golangci-lint/pkg/lint/lintersdb"
) )
@ -31,6 +32,10 @@ func getThanksList() string {
continue continue
} }
if lc.IsDeprecated() && lc.Deprecation.Level > linter.DeprecationWarning {
continue
}
linterURL := lc.OriginalURL linterURL := lc.OriginalURL
if lc.Name() == "staticcheck" { if lc.Name() == "staticcheck" {
linterURL = "https://github.com/dominikh/go-tools" linterURL = "https://github.com/dominikh/go-tools"

View File

@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/lint/lintersdb" "github.com/golangci/golangci-lint/pkg/lint/lintersdb"
"github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/pkg/logutils"
"github.com/golangci/golangci-lint/test/testshared" "github.com/golangci/golangci-lint/test/testshared"
@ -163,15 +164,18 @@ func getEnabledByDefaultFastLintersExcept(t *testing.T, except ...string) []stri
func getAllFastLintersWith(t *testing.T, with ...string) []string { func getAllFastLintersWith(t *testing.T, with ...string) []string {
t.Helper() t.Helper()
ret := append([]string{}, with...)
dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder()) dbManager, err := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
require.NoError(t, err) require.NoError(t, err)
linters := dbManager.GetAllSupportedLinterConfigs() linters := dbManager.GetAllSupportedLinterConfigs()
ret := append([]string{}, with...)
for _, lc := range linters { for _, lc := range linters {
if lc.IsSlowLinter() || lc.Internal { if lc.IsSlowLinter() || lc.Internal || (lc.IsDeprecated() && lc.Deprecation.Level > linter.DeprecationWarning) {
continue continue
} }
ret = append(ret, lc.Name()) ret = append(ret, lc.Name())
} }