New linters

How to write a custom linter

Use go/analysis and take a look at this tutorial: it shows how to write go/analysis linter from scratch and integrate it into golangci-lint.

How to add a public linter to golangci-lint

You need to implement a new linter using go/analysis API. We don't accept non go/analysis linters.

After that:

  1. Implement functional tests for the linter:
    • Add one file into directory test/testdata.
    • Run T=yourlintername.go make test_linters to ensure that test fails.
    • Run go run ./cmd/golangci-lint/ run --no-config --disable-all --enable=yourlintername ./test/testdata/yourlintername.go
  2. Add a new file pkg/golinters/{yourlintername}.go. Look at other linters in this directory. Implement linter integration and check that test passes.
  3. Add the new struct for the linter (which you've implemented in pkg/golinters/{yourlintername}.go) to the list of all supported linters in pkg/lint/lintersdb/manager.go to the function GetAllSupportedLinterConfigs.
    • Add WithSince("next_version"), where next_version must be replaced by the next minor version. (ex: v1.2.0 if the current version is v1.1.0)
  4. Find out what options do you need to configure for the linter. For example, nakedret has only 1 option: max-func-lines. Choose default values to not being annoying for users of golangci-lint. Add configuration options to:
  5. Take a look at the example of Pull Request with new linter support.

How to add a private linter to golangci-lint

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.

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 it's usage in a projects .golangci.yml file. An example linter can be found at here. 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 to the root directory.
  2. Adjust the yaml to appropriate linters-settings:custom entries as so:
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 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).

Create a Plugin

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:

type AnalyzerPlugin interface {
GetAnalyzers() []*analysis.Analyzer

The type of AnalyzerPlugin is not important, but is by convention type analyzerPlugin struct {}. See 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.

Edit this page on GitHub