Skip to content

Commit 167204c

Browse files
authored
feat: new custom linters system (#4437)
1 parent f0fdea0 commit 167204c

31 files changed

+1339
-110
lines changed

.custom-gcl.reference.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# The golangci-lint version used to build the custom binary.
2+
# Require.
3+
version: v1.56.2
4+
5+
# the name of the custom binary.
6+
# Optional.
7+
# Default: custom-gcl
8+
name: custom-golangci-lint
9+
10+
# The directory path used to store the custom binary.
11+
# Optional.
12+
# Default: .
13+
destination: ./my/path/
14+
15+
# The list of the plugins to integrate inside the custom binary.
16+
plugins:
17+
# a plugin from a Go proxy
18+
- module: 'github.com/example/plugin3'
19+
version: v1.2.3
20+
21+
# a plugin from a Go proxy (with a specific import path)
22+
- module: 'github.com/example/plugin4'
23+
import: 'github.com/example/plugin4/foo'
24+
version: v1.0.0
25+
26+
# a plugin from local source (with absolute path)
27+
- module: 'github.com/example/plugin2'
28+
path: /my/local/path/plugin2
29+
30+
# a plugin from local source (with relative path)
31+
- module: 'github.com/example/plugin1'
32+
path: ./my/local/path/plugin1
33+
34+
# a plugin from local source (with absolute path and a specific import path)
35+
- module: 'github.com/example/plugin2'
36+
import: 'github.com/example/plugin4/foo'
37+
path: /my/local/path/plugin2

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@
1818
/vendor/
1919
coverage.out
2020
coverage.xml
21+
/custom-golangci-lint
22+
/custom-gcl
23+
.custom-gcl.yml
24+
.custom-gcl.yaml

.golangci.reference.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,6 +2481,10 @@ linters-settings:
24812481
custom:
24822482
# Each custom linter should have a unique name.
24832483
example:
2484+
# The plugin type.
2485+
# It can be `goplugin` or `module`.
2486+
# Default: goplugin
2487+
type: module
24842488
# The path to the plugin *.so. Can be absolute or local.
24852489
# Required for each custom linter.
24862490
path: /path/to/example.so

.golangci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ linters-settings:
4646
- whyNoLint
4747
gocyclo:
4848
min-complexity: 15
49+
godox:
50+
keywords:
51+
- FIXME
4952
gofmt:
5053
rewrite-rules:
5154
- pattern: 'interface{}'
@@ -109,6 +112,7 @@ linters:
109112
- goconst
110113
- gocritic
111114
- gocyclo
115+
- godox
112116
- gofmt
113117
- goimports
114118
- gomnd

cmd/golangci-lint/plugins.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package main
2+
3+
// This file is used to declare module plugins.

docs/src/config/sidebar.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,10 @@
4646
link: /contributing/faq/
4747
- label: This Website
4848
link: /contributing/website/
49+
- label: Plugins
50+
items:
51+
- label: Module Plugin System
52+
link: /contributing/new-linters/
53+
- label: Go Plugin System
54+
link: /contributing/private-linters/
55+

docs/src/docs/contributing/faq.mdx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
title: Contributing FAQ
33
---
44

5-
## How to write a custom linter
6-
7-
See [there](/contributing/new-linters#how-to-write-a-custom-linter).
8-
95
## How to add a new open-source linter to `golangci-lint`
106

117
See [there](/contributing/new-linters#how-to-add-a-public-linter-to-golangci-lint).
@@ -16,7 +12,7 @@ See [there](/contributing/new-linters#how-to-add-a-private-linter-to-golangci-li
1612

1713
## How to update existing linter
1814

19-
Just update it's version in `go.mod`.
15+
Just update its version in `go.mod`.
2016

2117
## How to add configuration option to existing linter
2218

docs/src/docs/contributing/new-linters.mdx

Lines changed: 3 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -46,75 +46,7 @@ After that:
4646
Some people and organizations may choose to have custom-made linters run as a part of `golangci-lint`.
4747
Typically, these linters can't be open-sourced or too specific.
4848

49-
Such linters can be added through Go's plugin library.
49+
Such linters can be added through 2 plugin systems:
5050

51-
For a private linter (which acts as a plugin) to work properly,
52-
the plugin as well as the golangci-lint binary **needs to be built for the same environment**.
53-
54-
`CGO_ENABLED` is another requirement.
55-
56-
This means that `golangci-lint` needs to be built for whatever machine you intend to run it on
57-
(cloning the golangci-lint repository and running a `CGO_ENABLED=1 make build` should do the trick for your machine).
58-
59-
### Configure a Plugin
60-
61-
If you already have a linter plugin available, you can follow these steps to define its usage in a projects `.golangci.yml` file.
62-
63-
An example linter can be found at [here](https://github.com/golangci/example-plugin-linter).
64-
65-
If you're looking for instructions on how to configure your own custom linter, they can be found further down.
66-
67-
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.
68-
2. Adjust the yaml to appropriate `linters-settings:custom` entries as so:
69-
```yaml
70-
linters-settings:
71-
custom:
72-
example:
73-
path: /example.so
74-
description: The description of the linter
75-
original-url: github.com/golangci/example-linter
76-
settings: # Settings are optional.
77-
one: Foo
78-
two:
79-
- name: Bar
80-
three:
81-
name: Bar
82-
```
83-
84-
That is all the configuration that is required to run a custom linter in your project.
85-
86-
Custom linters are enabled by default, but abide by the same rules as other linters.
87-
88-
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;
89-
they can be re-enabled by adding them to the `linters:enable` list,
90-
or providing the enabled option on the command line, `golangci-lint run -Eexample`.
91-
92-
The configuration inside the `settings` field of linter have some limitations (there are NOT related to the plugin system itself):
93-
we use Viper to handle the configuration but Viper put all the keys in lowercase, and `.` cannot be used inside a key.
94-
95-
### Create a Plugin
96-
97-
Your linter must provide one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
98-
99-
Your project should also use `go.mod`.
100-
101-
All versions of libraries that overlap `golangci-lint` (including replaced libraries) MUST be set to the same version as `golangci-lint`.
102-
You can see the versions by running `go version -m golangci-lint`.
103-
104-
You'll also need to create a Go file like `plugin/example.go`.
105-
106-
This file MUST be in the package `main`, and MUST define an exposed function called `New` with the following signature:
107-
```go
108-
func New(conf any) ([]*analysis.Analyzer, error) {
109-
// ...
110-
}
111-
```
112-
113-
See [plugin/example.go](https://github.com/golangci/example-plugin-linter/blob/master/plugin/example.go) for more info.
114-
115-
To build the plugin, from the root project directory, run:
116-
```bash
117-
go build -buildmode=plugin plugin/example.go
118-
```
119-
120-
This will create a plugin `*.so` file that can be copied into your project or another well known location for usage in `golangci-lint`.
51+
- [Go Plugin System](/plugins/module-plugins)
52+
- [Module Plugin System](/plugins/go-plugins)

docs/src/docs/plugins/go-plugins.mdx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
title: Go Plugin System
3+
---
4+
5+
Private linters can be added through [Go's plugin system](https://pkg.go.dev/plugin).
6+
7+
For a private linter (which acts as a plugin) to work properly,
8+
the plugin as well as the golangci-lint binary **needs to be built for the same environment**.
9+
10+
`CGO_ENABLED` is another requirement.
11+
12+
This means that `golangci-lint` needs to be built for whatever machine you intend to run it on
13+
(cloning the golangci-lint repository and running a `CGO_ENABLED=1 make build` should do the trick for your machine).
14+
15+
## Create a Plugin
16+
17+
Your linter must provide one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
18+
19+
Your project should also use `go.mod`.
20+
21+
All versions of libraries that overlap `golangci-lint` (including replaced libraries) MUST be set to the same version as `golangci-lint`.
22+
You can see the versions by running `go version -m golangci-lint`.
23+
24+
You'll also need to create a Go file like `plugin/example.go`.
25+
26+
This file MUST be in the package `main`, and MUST define an exposed function called `New` with the following signature:
27+
```go
28+
func New(conf any) ([]*analysis.Analyzer, error) {
29+
// ...
30+
}
31+
```
32+
33+
See [plugin/example.go](https://github.com/golangci/example-plugin-linter/blob/master/plugin/example.go) for more info.
34+
35+
To build the plugin, from the root project directory, run:
36+
```bash
37+
go build -buildmode=plugin plugin/example.go
38+
```
39+
40+
This will create a plugin `*.so` file that can be copied into your project or another well known location for usage in `golangci-lint`.
41+
42+
## Configure a Plugin
43+
44+
If you already have a linter plugin available, you can follow these steps to define its usage in a projects `.golangci.yml` file.
45+
46+
An example linter can be found at [here](https://github.com/golangci/example-plugin-linter).
47+
48+
If you're looking for instructions on how to configure your own custom linter, they can be found further down.
49+
50+
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.
51+
2. Adjust the yaml to appropriate `linters-settings.custom` entries as so:
52+
```yaml title=.golangci.yml
53+
linters-settings:
54+
custom:
55+
example:
56+
path: /example.so
57+
description: The description of the linter
58+
original-url: github.com/golangci/example-linter
59+
settings: # Settings are optional.
60+
one: Foo
61+
two:
62+
- name: Bar
63+
three:
64+
name: Bar
65+
```
66+
67+
That is all the configuration that is required to run a custom linter in your project.
68+
69+
Custom linters are enabled by default, but abide by the same rules as other linters.
70+
71+
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;
72+
they can be re-enabled by adding them to the `linters.enable` list,
73+
or providing the enabled option on the command line, `golangci-lint run -Eexample`.
74+
75+
The configuration inside the `settings` field of linter have some limitations (there are NOT related to the plugin system itself):
76+
we use Viper to handle the configuration but Viper put all the keys in lowercase, and `.` cannot be used inside a key.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
title: Module Plugin System
3+
---
4+
5+
An example linter can be found at [here](https://github.com/golangci/example-plugin-module-linter/settings).
6+
7+
## The Automatic Way
8+
9+
- define your building configuration into `.custom-gcl.yml`
10+
- run the command `golangci-lint custom` ( or `golangci-lint custom -v` to have logs)
11+
- define the plugin inside the `linters-settings.custom` section with the type `module`.
12+
- run your custom version of golangci-lint
13+
14+
Requirements:
15+
- Go
16+
- git
17+
18+
### Configuration Example
19+
20+
```yaml title=.custom-gcl.yml
21+
version: v1.57.0
22+
plugins:
23+
# a plugin from a Go proxy
24+
- module: 'github.com/golangci/plugin1'
25+
import: 'github.com/golangci/plugin1/foo'
26+
version: v1.0.0
27+
28+
# a plugin from local source
29+
- module: 'github.com/golangci/plugin2'
30+
path: /my/local/path/plugin2
31+
```
32+
33+
```yaml title=.golangci.yml
34+
linters-settings:
35+
custom:
36+
foo:
37+
type: "module"
38+
description: This is an example usage of a plugin linter.
39+
settings:
40+
message: hello
41+
42+
linters:
43+
disable-all: true
44+
enable:
45+
- foo
46+
```
47+
48+
## The Manual Way
49+
50+
- add a blank-import of your module inside `cmd/golangci-lint/plugins.go`
51+
- run `go mod tidy`. (the module containing the plugin will be imported)
52+
- run `make build`
53+
- define the plugin inside the configuration `linters-settings.custom` section with the type `module`.
54+
- run your custom version of golangci-lint
55+
56+
### Configuration Example
57+
58+
```yaml title=.golangci.yml
59+
linters-settings:
60+
custom:
61+
foo:
62+
type: "module"
63+
description: This is an example usage of a plugin linter.
64+
settings:
65+
message: hello
66+
67+
linters:
68+
disable-all: true
69+
enable:
70+
- foo
71+
```

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ require (
4444
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a
4545
github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e
4646
github.com/golangci/misspell v0.4.1
47+
github.com/golangci/plugin-module-register v0.0.0-20240305222101-f76272ec86ee
4748
github.com/golangci/revgrep v0.5.2
4849
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed
4950
github.com/gordonklaus/ineffassign v0.1.0

go.sum

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)