Skip to content

feat: new custom linters system #4437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
15c4050
feat: POC
ldez Feb 28, 2024
a9287ee
Revert "feat: POC"
ldez Mar 5, 2024
cd7fa6d
docs: create pages
ldez Mar 5, 2024
e58d90f
chore: ignore plugin artifacts
ldez Mar 5, 2024
a0a31ba
feat: update plugin configuration
ldez Mar 5, 2024
bf297c3
chore: rename builder_plugin.go to builder_plugin_go.go
ldez Mar 5, 2024
bc04824
chore: rename PluginBuilder to PluginGoBuilder
ldez Mar 5, 2024
7a5068b
feat: add new plugin builder (db)
ldez Mar 5, 2024
f318ed4
chore: add file to declare plugins
ldez Mar 5, 2024
4543af4
feat: add new command
ldez Mar 5, 2024
7848198
docs: add mygcl configuration file
ldez Mar 5, 2024
942725a
docs: update .golangci.reference.yml
ldez Mar 5, 2024
9f9eb2f
feat: use the new plugin builder inside the commands
ldez Mar 5, 2024
89333a8
docs: add requirements
ldez Mar 5, 2024
a0bd603
feat: change Builder interface to return error
ldez Mar 6, 2024
59c30d1
feat: filter to plugin type
ldez Mar 6, 2024
faff4e0
feat: support yml, yaml, json as file extension
ldez Mar 6, 2024
78280f7
chore: remove useless call to plugin builder
ldez Mar 6, 2024
d1f8a3f
tests: add tests on LintersSettings
ldez Mar 6, 2024
27334e8
tests: add tests on Configuration
ldez Mar 6, 2024
b7e762b
tests: add tests on generateImports
ldez Mar 6, 2024
664b6ef
chore: remove useless call to plugin builder
ldez Mar 6, 2024
0d7e33b
docs: add linter example
ldez Mar 6, 2024
00b90bc
review: verbose command
ldez Mar 6, 2024
6f971ed
review: sanitize and comment
ldez Mar 6, 2024
e13d2fa
review: mygcl -> custom-gcl
ldez Mar 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .custom-gcl.reference.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# The golangci-lint version used to build the custom binary.
# Require.
version: v1.56.2

# the name of the custom binary.
# Optional.
# Default: custom-gcl
name: custom-golangci-lint

# The directory path used to store the custom binary.
# Optional.
# Default: .
destination: ./my/path/

# The list of the plugins to integrate inside the custom binary.
plugins:
# a plugin from a Go proxy
- module: 'github.com/example/plugin3'
version: v1.2.3

# a plugin from a Go proxy (with a specific import path)
- module: 'github.com/example/plugin4'
import: 'github.com/example/plugin4/foo'
version: v1.0.0

# a plugin from local source (with absolute path)
- module: 'github.com/example/plugin2'
path: /my/local/path/plugin2

# a plugin from local source (with relative path)
- module: 'github.com/example/plugin1'
path: ./my/local/path/plugin1

# a plugin from local source (with absolute path and a specific import path)
- module: 'github.com/example/plugin2'
import: 'github.com/example/plugin4/foo'
path: /my/local/path/plugin2
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@
/vendor/
coverage.out
coverage.xml
/custom-golangci-lint
/custom-gcl
.custom-gcl.yml
.custom-gcl.yaml
4 changes: 4 additions & 0 deletions .golangci.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2472,6 +2472,10 @@ linters-settings:
custom:
# Each custom linter should have a unique name.
example:
# The plugin type.
# It can be `goplugin` or `module`.
# Default: goplugin
type: module
# The path to the plugin *.so. Can be absolute or local.
# Required for each custom linter.
path: /path/to/example.so
Expand Down
4 changes: 4 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ linters-settings:
- whyNoLint
gocyclo:
min-complexity: 15
godox:
keywords:
- FIXME
gofmt:
rewrite-rules:
- pattern: 'interface{}'
Expand Down Expand Up @@ -109,6 +112,7 @@ linters:
- goconst
- gocritic
- gocyclo
- godox
- gofmt
- goimports
- gomnd
Expand Down
3 changes: 3 additions & 0 deletions cmd/golangci-lint/plugins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package main

// This file is used to declare module plugins.
7 changes: 7 additions & 0 deletions docs/src/config/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,10 @@
link: /contributing/faq/
- label: This Website
link: /contributing/website/
- label: Plugins
items:
- label: Module Plugin System
link: /contributing/new-linters/
- label: Go Plugin System
link: /contributing/private-linters/

6 changes: 1 addition & 5 deletions docs/src/docs/contributing/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
title: Contributing FAQ
---

## How to write a custom linter

See [there](/contributing/new-linters#how-to-write-a-custom-linter).

## How to add a new open-source linter to `golangci-lint`

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

## How to update existing linter

Just update it's version in `go.mod`.
Just update its version in `go.mod`.

## How to add configuration option to existing linter

Expand Down
74 changes: 3 additions & 71 deletions docs/src/docs/contributing/new-linters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,75 +46,7 @@ After that:
Some people and organizations may choose to have custom-made linters run as a part of `golangci-lint`.
Typically, these linters can't be open-sourced or too specific.

Such linters can be added through Go's plugin library.
Such linters can be added through 2 plugin systems:

For a private linter (which acts as a plugin) to work properly,
the plugin as well as the golangci-lint binary **needs to be built for the same environment**.

`CGO_ENABLED` is another requirement.

This means that `golangci-lint` needs to be built for whatever machine you intend to run it on
(cloning the golangci-lint repository and running a `CGO_ENABLED=1 make build` should do the trick for your machine).

### Configure a Plugin

If you already have a linter plugin available, you can follow these steps to define its usage in a projects `.golangci.yml` file.

An example linter can be found at [here](https://github.com/golangci/example-plugin-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:
```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
```

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`.

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.

### Create a 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 file MUST be in the package `main`, and MUST define an exposed function called `New` with the following signature:
```go
func New(conf any) ([]*analysis.Analyzer, error) {
// ...
}
```

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:
```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`.
- [Go Plugin System](/plugins/module-plugins)
- [Module Plugin System](/plugins/go-plugins)
76 changes: 76 additions & 0 deletions docs/src/docs/plugins/go-plugins.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
title: Go Plugin System
---

Private linters can be added through [Go's plugin system](https://pkg.go.dev/plugin).

For a private linter (which acts as a plugin) to work properly,
the plugin as well as the golangci-lint binary **needs to be built for the same environment**.

`CGO_ENABLED` is another requirement.

This means that `golangci-lint` needs to be built for whatever machine you intend to run it on
(cloning the golangci-lint repository and running a `CGO_ENABLED=1 make build` should do the trick for your machine).

## Create a 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 file MUST be in the package `main`, and MUST define an exposed function called `New` with the following signature:
```go
func New(conf any) ([]*analysis.Analyzer, error) {
// ...
}
```

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:
```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`.

## Configure a Plugin

If you already have a linter plugin available, you can follow these steps to define its usage in a projects `.golangci.yml` file.

An example linter can be found at [here](https://github.com/golangci/example-plugin-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:
```yaml title=.golangci.yml
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.

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.
71 changes: 71 additions & 0 deletions docs/src/docs/plugins/module-plugins.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: Module Plugin System
---

An example linter can be found at [here](https://github.com/golangci/example-plugin-module-linter/settings).

## The Automatic Way

- define your building configuration into `.custom-gcl.yml`
- run the command `golangci-lint custom` ( or `golangci-lint custom -v` to have logs)
- define the plugin inside the `linters-settings.custom` section with the type `module`.
- run your custom version of golangci-lint

Requirements:
- Go
- git

### Configuration Example

```yaml title=.custom-gcl.yml
version: v1.57.0
plugins:
# a plugin from a Go proxy
- module: 'github.com/golangci/plugin1'
import: 'github.com/golangci/plugin1/foo'
version: v1.0.0

# a plugin from local source
- module: 'github.com/golangci/plugin2'
path: /my/local/path/plugin2
```

```yaml title=.golangci.yml
linters-settings:
custom:
foo:
type: "module"
description: This is an example usage of a plugin linter.
settings:
message: hello

linters:
disable-all: true
enable:
- foo
```

## The Manual Way

- add a blank-import of your module inside `cmd/golangci-lint/plugins.go`
- run `go mod tidy`. (the module containing the plugin will be imported)
- run `make build`
- define the plugin inside the configuration `linters-settings.custom` section with the type `module`.
- run your custom version of golangci-lint

### Configuration Example

```yaml title=.golangci.yml
linters-settings:
custom:
foo:
type: "module"
description: This is an example usage of a plugin linter.
settings:
message: hello

linters:
disable-all: true
enable:
- foo
```
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a
github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e
github.com/golangci/misspell v0.4.1
github.com/golangci/plugin-module-register v0.0.0-20240305222101-f76272ec86ee
github.com/golangci/revgrep v0.5.2
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4
github.com/gordonklaus/ineffassign v0.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading