How it works
Linting is the process of running static checks on the codebase to catch common mistakes and provide an automatically-enforceable set of best practices. We use a tool called
golangci-lint, which bundles a large number of common linters into a single binary.
golangci-lint is configured using the
.golangci.yml in the root of the repository.
Running the linters
The easiest way to check locally if your changes will pass the lint step in CI is to run
./dev/check/go-lint.sh. This is run as part of
./dev/check/all.sh, so if it passes, linting should be good in CI as well.
We do our best to only enable lints that either reduce minor change churn (like
goimports) or find common issues in our code (like
ineffassign), but occasionally there will be false positives from the linters. In these cases,
golangci-lint provides a way to ignore lint issues with a comment:
//nolint:lintname. For more information on how to use
//nolint, see the
golangci-lint false positives page.
If a lint is routinely ignored or is just adding to development noise, consider disabling it.
Recommendations for making linting less annoying
The goal of linting is to provide value without excess development noise, but it can quickly become annoying to push up a change, make a PR, and see CI fail because of a misplaced import statement. Here are some ideas to make working with a linter less painful:
Integrate the linter with your editor
Most editors provide a way to provide in-line lints with
golangci-lint as a source. This can significantly reduce development friction relative to running the linter outside of your editor since it will show you issues as you develop.
See the integrations page in the
golangci-lint docs for more info on integrating
golangci-lint into your editor.
Run the lints before you push
Depending on CI to run all your tests when you create a PR increase friction linting since you might wait 5-10 minutes for a failure. Running the lints in advance can alleviate that.
Rather than attempting to remember to run
./dev/check/go-lint.sh every time, some people prefer to add git hooks that run automatically on either commit or push.
Use the linters for fast, iterative feedback
Depending on your workflow,
golangci-lint can often replace
go vet or (sometimes)
go build in the
write code -> build -> fix errors cycle. One of the configured linters is the
typecheck linter, which will catch most type errors that you'd normally get with
go build. Using
golangci-lint instead of
go vet gives you compile warnings and lint warnings as part of your development cycle, cutting out the disconnect between developing and linting.