From 02a8a2a55f1a05efbf005efe80f5add14b7be42b Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Sat, 3 Jun 2023 00:42:58 +0200
Subject: [PATCH 1/8] chore: clean

---
 .gitignore                             |  8 +++
 .golangci.yml => .golangci.example.yml | 11 ++--
 README.md                              | 86 ++++++++++++++------------
 example.go                             |  8 ++-
 go.mod                                 | 16 +++--
 go.sum                                 | 48 ++++----------
 lint_test.go                           |  6 +-
 plugin/example.go                      | 12 ++--
 8 files changed, 99 insertions(+), 96 deletions(-)
 create mode 100644 .gitignore
 rename .golangci.yml => .golangci.example.yml (54%)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7907424
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/.idea/
+/.vscode/
+/dist/
+.DS_Store
+/*.pprof
+/*.txt
+/golangci-lint
+/golangci-lint.exe
diff --git a/.golangci.yml b/.golangci.example.yml
similarity index 54%
rename from .golangci.yml
rename to .golangci.example.yml
index e02e275..8fbe074 100644
--- a/.golangci.yml
+++ b/.golangci.example.yml
@@ -1,15 +1,16 @@
 linters-settings:
   custom:
     example:
-#      Path is required
+      # Path is required
       path: example.so
-#      description is optional
+      # Description is optional
       description: The description of the linter. This is optional, but shows up when running `golangci-lint linters`.
-#      original-url is optional, and is only used for documentation purposes.
+      # Original-url is optional, and is only used for documentation purposes.
       original-url: github.com/golangci/example-linter
+
 linters:
   disable-all: true
   enable:
     - example
-#    Typecheck is how golangci-lint reports compile errors, so should always be enabled.
-    - typecheck
\ No newline at end of file
+    # Typecheck is how golangci-lint reports compile errors, so should always be enabled.
+    - typecheck
diff --git a/README.md b/README.md
index 0d3f21d..d06cb06 100644
--- a/README.md
+++ b/README.md
@@ -1,67 +1,75 @@
 This is an example linter that can be compiled into a plugin for `golangci-lint`.
 
-To use this:
-
 ### Create the Plugin From This Linter
 
-1. Download the source code \*
+1. Download the source code
 2. From the root project directory, run `go build -buildmode=plugin plugin/example.go`.
-3. Copy the generated `example.so` file into your project or to some other known location of your choosing. \**
-
+3. Copy the generated `example.so` file into your project or to some other known location of your choosing. [^1]
 
 ### Create a Copy of `golangci-lint` that Can Run with Plugins
 
-In order to use plugins, you'll need a golangci-lint executable that can run them. Plugin dependencies defined in the 
-`go.mod` file MUST have a matching version (or hash) as the same dependency in th `golangci-lint` binary if the 
-dependency is used in both. Because of the high probability of this both using the same dependency, it is recommended 
-to use a locally built binary. To do so:
+In order to use plugins, you'll need a golangci-lint executable that can run them.
+
+Plugin dependencies defined in the `go.mod` file MUST have a matching version (or hash) as the same dependency in th `golangci-lint` binary if the dependency is used in both.
+
+Because of the high probability of this both using the same dependency, it is recommended to use a locally built binary.
+
+To do so:
 
 1. Download [golangci-lint](https://github.com/golangci/golangci-lint) source code
-2. From the projects root directory, run `make`
+2. From the projects root directory, run `make build`
 3. Copy the `golangci-lint` executable that was created to your path, project, or other location
 
 ### Configure Your Project for Linting
 
-If you already have a linter plugin available, you can follow these steps to define its usage in a projects 
-`.golangci.yml` file. If you're looking for instructions on how to configure your own custom linter, they can be found 
-further down.
+If you already have a linter plugin available, you can follow these steps to define its usage in a projects `.golangci.yml` file.
 
-1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) 
-  to the root directory.
-2. Adjust the yaml to appropriate `linters-settings:custom` entries as so:
-```
-linters-settings:
- custom:
-  example:
-   path: /example.so
-   description: The description of the linter
-   original-url: github.com/golangci/example-linter
-```
+If you're looking for instructions on how to configure your own custom linter, they can be found further down.
+
+1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) to the root directory.
+2. Adjust the YAML to appropriate `linters-settings.custom` entries as so:
+    ```yml
+    linters-settings:
+     custom:
+      example:
+       path: /example.so
+       description: The description of the linter
+       original-url: github.com/golangci/example-linter
+    ```
 
-That is all the configuration that is required to run a custom linter in your project. 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`.
+That is all the configuration that is required to run a custom linter in your project.
+
+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`.
 
 ### To Create Your Own Custom Linter
 
 Your linter must implement one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
-Your project should also use `go.mod`. All versions of libraries that overlap `golangci-lint` (including replaced 
-libraries) MUST be set to the same version as `golangci-lint`. You can see the versions by running `go version -m golangci-lint`.
 
-You'll also need to create a go file like `plugin/example.go`. This MUST be in the package `main`, and define a 
-variable of name `AnalyzerPlugin`. The `AnalyzerPlugin` instance MUST implement the following interface:
-```
+Your project should also use `go.mod`.
+
+All versions of libraries that overlap `golangci-lint` (including replaced libraries) MUST be set to the same version as `golangci-lint`.
+You can see the versions by running `go version -m golangci-lint`.
+
+You'll also need to create a go file like `plugin/example.go`.
+
+This MUST be in the package `main`, and define a variable of name `AnalyzerPlugin`.
+The `AnalyzerPlugin` instance MUST implement the following interface:
+
+```go
 type AnalyzerPlugin interface {
     GetAnalyzers() []*analysis.Analyzer
 }
 ```
-The type of `AnalyzerPlugin` is not important, but is by convention `type analyzerPlugin struct {}`. See 
-[plugin/example.go](https://github.com/golangci/example-plugin-linter/plugin/example.go) for more info.
 
-To build the plugin, from the root project directory, run `go build -buildmode=plugin plugin/example.go`. This will create a plugin `*.so`
-file that can be copied into your project or another well known location for usage in golangci-lint.
+The type of `AnalyzerPlugin` is not important, but is by convention `type analyzerPlugin struct {}`.
+See [plugin/example.go](https://github.com/golangci/example-plugin-linter/plugin/example.go) for more info.
+
+To build the plugin, from the root project directory, run `go build -buildmode=plugin plugin/example.go`.
 
-\* Sorry, I haven't found a way to enable `go get` functionality for plugins yet. If you know how, let me know!
+This will create a plugin `*.so` file that can be copied into your project or another well known location for usage in golangci-lint.
 
-\** Alternately, you can use the `-o /path/to/location/example.so` output flag to have it put it there for you.
+[^1]: Alternately, you can use the `-o /path/to/location/example.so` output flag to have it put it there for you.
diff --git a/example.go b/example.go
index 446e1b0..88b0f8e 100644
--- a/example.go
+++ b/example.go
@@ -2,8 +2,9 @@ package linters
 
 import (
 	"go/ast"
-	"golang.org/x/tools/go/analysis"
 	"strings"
+
+	"golang.org/x/tools/go/analysis"
 )
 
 var TodoAnalyzer = &analysis.Analyzer{
@@ -16,8 +17,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
 	for _, file := range pass.Files {
 		ast.Inspect(file, func(n ast.Node) bool {
 			if comment, ok := n.(*ast.Comment); ok {
-				if strings.HasPrefix(comment.Text, "// TODO:") ||
-					strings.HasPrefix(comment.Text, "// TODO():") {
+				if strings.HasPrefix(comment.Text, "// TODO:") || strings.HasPrefix(comment.Text, "// TODO():") {
 					pass.Report(analysis.Diagnostic{
 						Pos:            comment.Pos(),
 						End:            0,
@@ -27,8 +27,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
 					})
 				}
 			}
+
 			return true
 		})
 	}
+
 	return nil, nil
 }
diff --git a/go.mod b/go.mod
index e6152de..bedcae4 100644
--- a/go.mod
+++ b/go.mod
@@ -1,10 +1,18 @@
-module github.com/dbraley/example-linter
+module github.com/golangci/example-linter
 
 // All versions here need to be the same as in golangci-lint/mod.go if present
 
-go 1.16
+go 1.19
 
 require (
-	github.com/stretchr/testify v1.7.0
-	golang.org/x/tools v0.1.9
+	github.com/stretchr/testify v1.8.4
+	golang.org/x/tools v0.9.3
+)
+
+require (
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	golang.org/x/mod v0.10.0 // indirect
+	golang.org/x/sys v0.8.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 19b6812..fc9fbbf 100644
--- a/go.sum
+++ b/go.sum
@@ -1,39 +1,17 @@
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
-golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
+golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
+golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/lint_test.go b/lint_test.go
index 71d58a3..e41c5c5 100644
--- a/lint_test.go
+++ b/lint_test.go
@@ -3,11 +3,11 @@ package linters
 // Tests for linters.
 
 import (
-	"github.com/stretchr/testify/suite"
 	"path/filepath"
 	"runtime"
 	"testing"
 
+	"github.com/stretchr/testify/suite"
 	"golang.org/x/tools/go/analysis/analysistest"
 )
 
@@ -16,8 +16,7 @@ type linterSuite struct {
 }
 
 func (suite *linterSuite) TestContextLinter() {
-	analysistest.Run(
-		suite.T(), TestdataDir(),
+	analysistest.Run(suite.T(), TestdataDir(),
 		TodoAnalyzer, "testlintdata/todo")
 }
 
@@ -30,5 +29,6 @@ func TestdataDir() string {
 	if !ok {
 		panic("unable to get current test filename")
 	}
+
 	return filepath.Join(filepath.Dir(testFilename), "testdata")
 }
diff --git a/plugin/example.go b/plugin/example.go
index bf0e687..5efce1a 100644
--- a/plugin/example.go
+++ b/plugin/example.go
@@ -2,18 +2,16 @@
 package main
 
 import (
-	linters "github.com/dbraley/example-linter"
+	linters "github.com/golangci/example-linter"
 	"golang.org/x/tools/go/analysis"
 )
 
+// This must be defined and named 'AnalyzerPlugin'
+var AnalyzerPlugin analyzerPlugin
+
 type analyzerPlugin struct{}
 
 // This must be implemented
 func (*analyzerPlugin) GetAnalyzers() []*analysis.Analyzer {
-	return []*analysis.Analyzer{
-		linters.TodoAnalyzer,
-	}
+	return []*analysis.Analyzer{linters.TodoAnalyzer}
 }
-
-// This must be defined and named 'AnalyzerPlugin'
-var AnalyzerPlugin analyzerPlugin

From 0042ea6919c678ea407934b3d386c64130729bed Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Sun, 4 Jun 2023 15:50:30 +0200
Subject: [PATCH 2/8] chore: ignore example.so

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 7907424..e8d3242 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
 /*.txt
 /golangci-lint
 /golangci-lint.exe
+/example.so

From 6fa025a9c82ac69e74411ce1b73aa26d3f43186b Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Sun, 4 Jun 2023 16:01:12 +0200
Subject: [PATCH 3/8] feat: example of the new plugin signature

---
 .golangci.example.yml |  6 ++++++
 README.md             | 47 ++++++++++++++++++++++++++-----------------
 plugin/example.go     | 15 ++++++++------
 3 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/.golangci.example.yml b/.golangci.example.yml
index 8fbe074..0d1097b 100644
--- a/.golangci.example.yml
+++ b/.golangci.example.yml
@@ -7,6 +7,12 @@ linters-settings:
       description: The description of the linter. This is optional, but shows up when running `golangci-lint linters`.
       # Original-url is optional, and is only used for documentation purposes.
       original-url: github.com/golangci/example-linter
+      settings:
+        one: Foo
+        two:
+          - name: Bar
+        three:
+          name: Bar
 
 linters:
   disable-all: true
diff --git a/README.md b/README.md
index d06cb06..2c46d13 100644
--- a/README.md
+++ b/README.md
@@ -28,13 +28,19 @@ If you're looking for instructions on how to configure your own custom linter, t
 
 1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) to the root directory.
 2. Adjust the YAML to appropriate `linters-settings.custom` entries as so:
-    ```yml
+    ```yaml
     linters-settings:
-     custom:
-      example:
-       path: /example.so
-       description: The description of the linter
-       original-url: github.com/golangci/example-linter
+      custom:
+        example:
+          path: /example.so
+          description: The description of the linter
+          original-url: github.com/golangci/example-linter
+          settings: # Settings are optional.
+            one: Foo
+            two:
+              - name: Bar
+            three:
+              name: Bar
     ```
 
 That is all the configuration that is required to run a custom linter in your project.
@@ -42,34 +48,37 @@ That is all the configuration that is required to run a custom linter in your pr
 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,
+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`.
 
-### To Create Your Own Custom Linter
+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.
 
-Your linter must implement one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
+### To Create Your Own Plugin
+
+Your linter must provide one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
 
 Your project should also use `go.mod`.
 
 All versions of libraries that overlap `golangci-lint` (including replaced libraries) MUST be set to the same version as `golangci-lint`.
 You can see the versions by running `go version -m golangci-lint`.
 
-You'll also need to create a go file like `plugin/example.go`.
-
-This MUST be in the package `main`, and define a variable of name `AnalyzerPlugin`.
-The `AnalyzerPlugin` instance MUST implement the following interface:
+You'll also need to create a Go file like `plugin/example.go`.
 
+This file MUST be in the package `main`, and MUST define an exposed function called `New` with the following signature:
 ```go
-type AnalyzerPlugin interface {
-    GetAnalyzers() []*analysis.Analyzer
+func New(conf any) ([]*analysis.Analyzer, error) {
+	// ...
 }
 ```
 
-The type of `AnalyzerPlugin` is not important, but is by convention `type analyzerPlugin struct {}`.
-See [plugin/example.go](https://github.com/golangci/example-plugin-linter/plugin/example.go) for more info.
+See [plugin/example.go](https://github.com/golangci/example-plugin-linter/blob/master/plugin/example.go) for more info.
 
-To build the plugin, from the root project directory, run `go build -buildmode=plugin plugin/example.go`.
+To build the plugin, from the root project directory, run:
+```bash
+go build -buildmode=plugin plugin/example.go
+```
 
-This will create a plugin `*.so` file that can be copied into your project or another well known location for usage in golangci-lint.
+This will create a plugin `*.so` file that can be copied into your project or another well known location for usage in `golangci-lint`.
 
 [^1]: Alternately, you can use the `-o /path/to/location/example.so` output flag to have it put it there for you.
diff --git a/plugin/example.go b/plugin/example.go
index 5efce1a..555dc41 100644
--- a/plugin/example.go
+++ b/plugin/example.go
@@ -2,16 +2,19 @@
 package main
 
 import (
+	"fmt"
+
 	linters "github.com/golangci/example-linter"
 	"golang.org/x/tools/go/analysis"
 )
 
-// This must be defined and named 'AnalyzerPlugin'
-var AnalyzerPlugin analyzerPlugin
+func New(conf any) ([]*analysis.Analyzer, error) {
+	// TODO: This must be implemented
+
+	fmt.Printf("My configuration (%[1]T): %#[1]v\n", conf)
 
-type analyzerPlugin struct{}
+	// The configuration type will be map[string]any or []interface, it depends on your configuration.
+	// You can use https://github.com/mitchellh/mapstructure to convert map to struct.
 
-// This must be implemented
-func (*analyzerPlugin) GetAnalyzers() []*analysis.Analyzer {
-	return []*analysis.Analyzer{linters.TodoAnalyzer}
+	return []*analysis.Analyzer{linters.TodoAnalyzer}, nil
 }

From 36793ffa7cd24252b28e490b7e24ad0c21e54a47 Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Fri, 2 Feb 2024 23:16:38 +0100
Subject: [PATCH 4/8] chore: update dependencies

---
 go.mod            |  7 +++----
 go.sum            | 13 ++++++-------
 plugin/example.go |  2 +-
 3 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/go.mod b/go.mod
index bedcae4..c8e0a09 100644
--- a/go.mod
+++ b/go.mod
@@ -2,17 +2,16 @@ module github.com/golangci/example-linter
 
 // All versions here need to be the same as in golangci-lint/mod.go if present
 
-go 1.19
+go 1.21
 
 require (
 	github.com/stretchr/testify v1.8.4
-	golang.org/x/tools v0.9.3
+	golang.org/x/tools v0.17.0
 )
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	golang.org/x/mod v0.10.0 // indirect
-	golang.org/x/sys v0.8.0 // indirect
+	golang.org/x/mod v0.14.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index fc9fbbf..6e98bd1 100644
--- a/go.sum
+++ b/go.sum
@@ -4,13 +4,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
-golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
-golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
-golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
+golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/plugin/example.go b/plugin/example.go
index 555dc41..eef287f 100644
--- a/plugin/example.go
+++ b/plugin/example.go
@@ -14,7 +14,7 @@ func New(conf any) ([]*analysis.Analyzer, error) {
 	fmt.Printf("My configuration (%[1]T): %#[1]v\n", conf)
 
 	// The configuration type will be map[string]any or []interface, it depends on your configuration.
-	// You can use https://github.com/mitchellh/mapstructure to convert map to struct.
+	// You can use https://github.com/go-viper/mapstructure to convert map to struct.
 
 	return []*analysis.Analyzer{linters.TodoAnalyzer}, nil
 }

From 2528e8653aabddf6073cf6c2fe4ca901a43b8b54 Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Wed, 6 Mar 2024 02:17:40 +0100
Subject: [PATCH 5/8] docs: clean configuration example

---
 .golangci.example.yml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/.golangci.example.yml b/.golangci.example.yml
index 0d1097b..a785e8a 100644
--- a/.golangci.example.yml
+++ b/.golangci.example.yml
@@ -18,5 +18,3 @@ linters:
   disable-all: true
   enable:
     - example
-    # Typecheck is how golangci-lint reports compile errors, so should always be enabled.
-    - typecheck

From bcb5c21f8aaa992d9e2953b7ce8c263379d79e22 Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Wed, 6 Mar 2024 02:32:56 +0100
Subject: [PATCH 6/8] chore: clean

---
 .golangci.example.yml |  2 +-
 example_test.go       | 25 +++++++++++++++++++++++++
 lint_test.go          | 34 ----------------------------------
 3 files changed, 26 insertions(+), 35 deletions(-)
 create mode 100644 example_test.go
 delete mode 100644 lint_test.go

diff --git a/.golangci.example.yml b/.golangci.example.yml
index a785e8a..d00b32c 100644
--- a/.golangci.example.yml
+++ b/.golangci.example.yml
@@ -6,7 +6,7 @@ linters-settings:
       # Description is optional
       description: The description of the linter. This is optional, but shows up when running `golangci-lint linters`.
       # Original-url is optional, and is only used for documentation purposes.
-      original-url: github.com/golangci/example-linter
+      original-url: github.com/golangci/example-plugin-linter
       settings:
         one: Foo
         two:
diff --git a/example_test.go b/example_test.go
new file mode 100644
index 0000000..ce46d93
--- /dev/null
+++ b/example_test.go
@@ -0,0 +1,25 @@
+package linters
+
+import (
+	"path/filepath"
+	"runtime"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+	"golang.org/x/tools/go/analysis/analysistest"
+)
+
+func TestTodoAnalyzer(t *testing.T) {
+	analysistest.Run(t, testdataDir(t), TodoAnalyzer, "testlintdata/todo")
+}
+
+func testdataDir(t *testing.T) string {
+	t.Helper()
+
+	_, testFilename, _, ok := runtime.Caller(1)
+	if !ok {
+		require.Fail(t, "unable to get current test filename")
+	}
+
+	return filepath.Join(filepath.Dir(testFilename), "testdata")
+}
diff --git a/lint_test.go b/lint_test.go
deleted file mode 100644
index e41c5c5..0000000
--- a/lint_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package linters
-
-// Tests for linters.
-
-import (
-	"path/filepath"
-	"runtime"
-	"testing"
-
-	"github.com/stretchr/testify/suite"
-	"golang.org/x/tools/go/analysis/analysistest"
-)
-
-type linterSuite struct {
-	suite.Suite
-}
-
-func (suite *linterSuite) TestContextLinter() {
-	analysistest.Run(suite.T(), TestdataDir(),
-		TodoAnalyzer, "testlintdata/todo")
-}
-
-func TestLinterSuite(t *testing.T) {
-	suite.Run(t, new(linterSuite))
-}
-
-func TestdataDir() string {
-	_, testFilename, _, ok := runtime.Caller(1)
-	if !ok {
-		panic("unable to get current test filename")
-	}
-
-	return filepath.Join(filepath.Dir(testFilename), "testdata")
-}

From 5b227aea582953badf9ebb040a5fbbc36f265b6f Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Wed, 12 Jun 2024 17:01:55 +0200
Subject: [PATCH 7/8] chore: update dependencies

---
 go.mod |  7 ++++---
 go.sum | 16 ++++++++--------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/go.mod b/go.mod
index c8e0a09..4262a02 100644
--- a/go.mod
+++ b/go.mod
@@ -5,13 +5,14 @@ module github.com/golangci/example-linter
 go 1.21
 
 require (
-	github.com/stretchr/testify v1.8.4
-	golang.org/x/tools v0.17.0
+	github.com/stretchr/testify v1.9.0
+	golang.org/x/tools v0.22.0
 )
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	golang.org/x/mod v0.14.0 // indirect
+	golang.org/x/mod v0.18.0 // indirect
+	golang.org/x/sync v0.7.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 6e98bd1..a29554d 100644
--- a/go.sum
+++ b/go.sum
@@ -2,14 +2,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
-golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
-golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

From 1d4f00fda884c1928a9dbbfea865e7dc01e16477 Mon Sep 17 00:00:00 2001
From: Fernandez Ludovic <ldez@users.noreply.github.com>
Date: Mon, 14 Apr 2025 00:39:34 +0200
Subject: [PATCH 8/8] chore: update example

---
 .golangci.example.yml | 34 ++++++++++++++++++----------------
 README.md             | 25 +++++++++++++------------
 go.mod                | 10 +++++-----
 go.sum                |  6 ++++++
 4 files changed, 42 insertions(+), 33 deletions(-)

diff --git a/.golangci.example.yml b/.golangci.example.yml
index d00b32c..5231bd0 100644
--- a/.golangci.example.yml
+++ b/.golangci.example.yml
@@ -1,20 +1,22 @@
-linters-settings:
-  custom:
-    example:
-      # Path is required
-      path: example.so
-      # Description is optional
-      description: The description of the linter. This is optional, but shows up when running `golangci-lint linters`.
-      # Original-url is optional, and is only used for documentation purposes.
-      original-url: github.com/golangci/example-plugin-linter
-      settings:
-        one: Foo
-        two:
-          - name: Bar
-        three:
-          name: Bar
+version: "2"
 
 linters:
-  disable-all: true
+  default: none
   enable:
     - example
+
+  settings:
+    custom:
+      example:
+        # Path is required
+        path: example.so
+        # Description is optional
+        description: The description of the linter. This is optional, but shows up when running `golangci-lint linters`.
+        # Original-url is optional, and is only used for documentation purposes.
+        original-url: github.com/golangci/example-plugin-linter
+        settings:
+          one: Foo
+          three:
+            name: Bar
+          two:
+            - name: Bar
diff --git a/README.md b/README.md
index 2c46d13..118e2e8 100644
--- a/README.md
+++ b/README.md
@@ -29,18 +29,19 @@ If you're looking for instructions on how to configure your own custom linter, t
 1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) to the root directory.
 2. Adjust the YAML to appropriate `linters-settings.custom` entries as so:
     ```yaml
-    linters-settings:
-      custom:
-        example:
-          path: /example.so
-          description: The description of the linter
-          original-url: github.com/golangci/example-linter
-          settings: # Settings are optional.
-            one: Foo
-            two:
-              - name: Bar
-            three:
-              name: Bar
+    linters:
+      settings:
+        custom:
+          example:
+            path: /example.so
+            description: The description of the linter
+            original-url: github.com/golangci/example-linter
+            settings: # Settings are optional.
+              one: Foo
+              two:
+                - name: Bar
+              three:
+                name: Bar
     ```
 
 That is all the configuration that is required to run a custom linter in your project.
diff --git a/go.mod b/go.mod
index 4262a02..7b34bce 100644
--- a/go.mod
+++ b/go.mod
@@ -2,17 +2,17 @@ module github.com/golangci/example-linter
 
 // All versions here need to be the same as in golangci-lint/mod.go if present
 
-go 1.21
+go 1.23.0
 
 require (
-	github.com/stretchr/testify v1.9.0
-	golang.org/x/tools v0.22.0
+	github.com/stretchr/testify v1.10.0
+	golang.org/x/tools v0.32.0
 )
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	golang.org/x/mod v0.18.0 // indirect
-	golang.org/x/sync v0.7.0 // indirect
+	golang.org/x/mod v0.24.0 // indirect
+	golang.org/x/sync v0.13.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index a29554d..22aa56c 100644
--- a/go.sum
+++ b/go.sum
@@ -4,12 +4,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
 golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
 golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
+golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
