diff --git a/go.mod b/go.mod index a9dc39466bd0..43c5150fa83c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/golangci/golangci-lint -go 1.19 +go 1.20 require ( 4d63.com/gocheckcompilerdirectives v1.2.1 diff --git a/netlify.toml b/netlify.toml index dcd0c45f1cf1..32db72872c08 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,5 +1,5 @@ [context.production.environment] - GO_VERSION = "1.19" + GO_VERSION = "1.20" NODE_VERSION = "17" # TODO https://github.com/golangci/golangci-lint/pull/2904#issuecomment-1146870535 # NPM_FLAGS = "--legacy-peer-deps" @@ -7,7 +7,7 @@ NPM_VERSION = "8.5.5" [context.deploy-preview.environment] - GO_VERSION = "1.19" + GO_VERSION = "1.20" NODE_VERSION = "17" # TODO https://github.com/golangci/golangci-lint/pull/2904#issuecomment-1146870535 # NPM_FLAGS = "--legacy-peer-deps" @@ -15,7 +15,7 @@ NPM_VERSION = "8.5.5" [context.branch-deploy.environment] - GO_VERSION = "1.19" + GO_VERSION = "1.20" NODE_VERSION = "17" # TODO https://github.com/golangci/golangci-lint/pull/2904#issuecomment-1146870535 # NPM_FLAGS = "--legacy-peer-deps" diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index b520ea4c6eeb..c219be1b792d 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -828,6 +828,9 @@ type CustomLinterSettings struct { Path string // Description describes the purpose of the private linter. Description string - // The URL containing the source code for the private linter. + // OriginalURL The URL containing the source code for the private linter. OriginalURL string `mapstructure:"original-url"` + + // Settings plugin settings only work with linterdb.PluginConstructor symbol. + Settings any } diff --git a/pkg/lint/lintersdb/custom_linters.go b/pkg/lint/lintersdb/custom_linters.go index f7369aa68fb1..32ee4a343004 100644 --- a/pkg/lint/lintersdb/custom_linters.go +++ b/pkg/lint/lintersdb/custom_linters.go @@ -1,6 +1,7 @@ package lintersdb import ( + "errors" "fmt" "path/filepath" "plugin" @@ -45,14 +46,14 @@ func (m *Manager) WithCustomLinters() *Manager { // loadCustomLinterConfig loads the configuration of private linters. // Private linters are dynamically loaded from .so plugin files. func (m *Manager) loadCustomLinterConfig(name string, settings config.CustomLinterSettings) (*linter.Config, error) { - analyzer, err := m.getAnalyzerPlugin(settings.Path) + analyzers, err := m.getAnalyzerPlugin(settings.Path, settings.Settings) if err != nil { return nil, err } m.log.Infof("Loaded %s: %s", settings.Path, name) - customLinter := goanalysis.NewLinter(name, settings.Description, analyzer.GetAnalyzers(), nil). + customLinter := goanalysis.NewLinter(name, settings.Description, analyzers, nil). WithLoadMode(goanalysis.LoadModeTypesInfo) linterConfig := linter.NewConfig(customLinter) @@ -68,7 +69,7 @@ func (m *Manager) loadCustomLinterConfig(name string, settings config.CustomLint // and returns the 'AnalyzerPlugin' interface implemented by the private plugin. // An error is returned if the private linter cannot be loaded // or the linter does not implement the AnalyzerPlugin interface. -func (m *Manager) getAnalyzerPlugin(path string) (AnalyzerPlugin, error) { +func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Analyzer, error) { if !filepath.IsAbs(path) { // resolve non-absolute paths relative to config file's directory configFilePath := viper.ConfigFileUsed() @@ -84,6 +85,34 @@ func (m *Manager) getAnalyzerPlugin(path string) (AnalyzerPlugin, error) { return nil, err } + analyzers, errP := lookupPluginNew(plug, settings) + if errP != nil { + // fallback to the old plugin interface. + analyzers, err = lookupAnalyzerPlugin(plug) + if err != nil { + return nil, fmt.Errorf("lookup plugin %s: %w", path, errors.Join(errP, err)) + } + } + + return analyzers, nil +} + +func lookupPluginNew(plug *plugin.Plugin, settings any) ([]*analysis.Analyzer, error) { + symbol, err := plug.Lookup("New") + if err != nil { + return nil, err + } + + // The type func cannot be used here, must be the explicit signature. + constructor, ok := symbol.(func(any) ([]*analysis.Analyzer, error)) + if !ok { + return nil, fmt.Errorf("plugin does not abide by 'New' function: %T", symbol) + } + + return constructor(settings) +} + +func lookupAnalyzerPlugin(plug *plugin.Plugin) ([]*analysis.Analyzer, error) { symbol, err := plug.Lookup("AnalyzerPlugin") if err != nil { return nil, err @@ -91,8 +120,8 @@ func (m *Manager) getAnalyzerPlugin(path string) (AnalyzerPlugin, error) { analyzerPlugin, ok := symbol.(AnalyzerPlugin) if !ok { - return nil, fmt.Errorf("plugin %s does not abide by 'AnalyzerPlugin' interface", path) + return nil, fmt.Errorf("plugin does not abide by 'AnalyzerPlugin' interface: %T", symbol) } - return analyzerPlugin, nil + return analyzerPlugin.GetAnalyzers(), nil }