From 6c7aba67ec4c6a897631f89c205569ed82cdeb55 Mon Sep 17 00:00:00 2001
From: Ludovic Fernandez <ldez@users.noreply.github.com>
Date: Fri, 16 Jun 2023 10:00:09 +0200
Subject: [PATCH] fix: include custom linters in `enable-all` (#3911)

---
 docs/src/docs/contributing/new-linters.mdx |  7 +++--
 pkg/commands/executor.go                   |  2 +-
 pkg/lint/lintersdb/custom_linters.go       | 19 +++++---------
 pkg/lint/lintersdb/manager.go              | 30 ++++++++++++++--------
 4 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/docs/src/docs/contributing/new-linters.mdx b/docs/src/docs/contributing/new-linters.mdx
index b5a9900b..ec82ec88 100644
--- a/docs/src/docs/contributing/new-linters.mdx
+++ b/docs/src/docs/contributing/new-linters.mdx
@@ -83,8 +83,11 @@ If you're looking for instructions on how to configure your own custom linter, t
 
 That is all the configuration that is required to run a custom linter in your project.
 
-Custom linters are disabled by default, and are not enabled when `linters.enable-all` is specified.
-They can be enabled by adding them the `linters.enable` list, or providing the enabled option on the command line (`golangci-lint run -Eexample`).
+Custom linters are enabled by default, but abide by the same rules as other linters.
+
+If the disable all option is specified either on command line or in `.golang.yml` files `linters.disable-all: true`, custom linters will be disabled;
+they can be re-enabled by adding them to the `linters:enable` list,
+or providing the enabled option on the command line, `golangci-lint run -Eexample`.
 
 The configuration inside the `settings` field of linter have some limitations (there are NOT related to the plugin system itself):
 we use Viper to handle the configuration but Viper put all the keys in lowercase, and `.` cannot be used inside a key.
diff --git a/pkg/commands/executor.go b/pkg/commands/executor.go
index 109edcb9..61e221cb 100644
--- a/pkg/commands/executor.go
+++ b/pkg/commands/executor.go
@@ -120,7 +120,7 @@ func NewExecutor(buildInfo BuildInfo) *Executor {
 	}
 
 	// recreate after getting config
-	e.DBManager = lintersdb.NewManager(e.cfg, e.log).WithCustomLinters()
+	e.DBManager = lintersdb.NewManager(e.cfg, e.log)
 
 	// Slice options must be explicitly set for proper merging of config and command-line options.
 	fixSlicesFlags(e.runCmd.Flags())
diff --git a/pkg/lint/lintersdb/custom_linters.go b/pkg/lint/lintersdb/custom_linters.go
index 69989abd..bb1c61c0 100644
--- a/pkg/lint/lintersdb/custom_linters.go
+++ b/pkg/lint/lintersdb/custom_linters.go
@@ -12,35 +12,30 @@ import (
 	"github.com/golangci/golangci-lint/pkg/config"
 	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
 	"github.com/golangci/golangci-lint/pkg/lint/linter"
-	"github.com/golangci/golangci-lint/pkg/logutils"
-	"github.com/golangci/golangci-lint/pkg/report"
 )
 
 type AnalyzerPlugin interface {
 	GetAnalyzers() []*analysis.Analyzer
 }
 
-// WithCustomLinters loads private linters that are specified in the golangci config file.
-func (m *Manager) WithCustomLinters() *Manager {
-	if m.log == nil {
-		m.log = report.NewLogWrapper(logutils.NewStderrLog(logutils.DebugKeyEmpty), &report.Data{})
+// getCustomLinterConfigs loads private linters that are specified in the golangci config file.
+func (m *Manager) getCustomLinterConfigs() []*linter.Config {
+	if m.cfg == nil || m.log == nil {
+		return nil
 	}
 
-	if m.cfg == nil {
-		return m
-	}
+	var linters []*linter.Config
 
 	for name, settings := range m.cfg.LintersSettings.Custom {
 		lc, err := m.loadCustomLinterConfig(name, settings)
-
 		if err != nil {
 			m.log.Errorf("Unable to load custom analyzer %s:%s, %v", name, settings.Path, err)
 		} else {
-			m.nameToLCs[name] = append(m.nameToLCs[name], lc)
+			linters = append(linters, lc)
 		}
 	}
 
-	return m
+	return linters
 }
 
 // loadCustomLinterConfig loads the configuration of private linters.
diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go
index b01d6116..ca227c9a 100644
--- a/pkg/lint/lintersdb/manager.go
+++ b/pkg/lint/lintersdb/manager.go
@@ -8,13 +8,16 @@ import (
 )
 
 type Manager struct {
-	nameToLCs map[string][]*linter.Config
-	cfg       *config.Config
-	log       logutils.Log
+	cfg *config.Config
+	log logutils.Log
+
+	nameToLCs     map[string][]*linter.Config
+	customLinters []*linter.Config
 }
 
 func NewManager(cfg *config.Config, log logutils.Log) *Manager {
 	m := &Manager{cfg: cfg, log: log}
+	m.customLinters = m.getCustomLinterConfigs()
 
 	nameToLCs := make(map[string][]*linter.Config)
 	for _, lc := range m.GetAllSupportedLinterConfigs() {
@@ -247,9 +250,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
 
 	const megacheckName = "megacheck"
 
+	var linters []*linter.Config
+	linters = append(linters, m.customLinters...)
+
 	// The linters are sorted in the alphabetical order (case-insensitive).
 	// When a new linter is added the version in `WithSince(...)` must be the next minor version of golangci-lint.
-	return []*linter.Config{
+	linters = append(linters,
 		linter.NewConfig(golinters.NewAsasalint(asasalintCfg)).
 			WithSince("1.47.0").
 			WithPresets(linter.PresetBugs).
@@ -867,18 +873,20 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
 			WithPresets(linter.PresetStyle).
 			WithURL("https://github.com/bombsimon/wsl"),
 
-		// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
-		linter.NewConfig(golinters.NewNoLintLint(noLintLintCfg)).
-			WithSince("v1.26.0").
-			WithPresets(linter.PresetStyle).
-			WithURL("https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint/README.md"),
-
 		linter.NewConfig(golinters.NewZerologLint()).
 			WithSince("v1.53.0").
 			WithPresets(linter.PresetBugs).
 			WithLoadForGoAnalysis().
 			WithURL("https://github.com/ykadowak/zerologlint"),
-	}
+
+		// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
+		linter.NewConfig(golinters.NewNoLintLint(noLintLintCfg)).
+			WithSince("v1.26.0").
+			WithPresets(linter.PresetStyle).
+			WithURL("https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint/README.md"),
+	)
+
+	return linters
 }
 
 func (m Manager) GetAllEnabledByDefaultLinters() []*linter.Config {