Presentation slides and material for talk presented at Gophercon India 2024.
Ideally the slides should have been accessible at https://go-talks.appspot.com/github.com/sudo-suhas/operationalising-golangci-lint-v2/2024-12-gophercon-india.slide. However, due to golang/go#58906, the functionality is currently broken.
As an alternative, the slides have been hosted via Google App Engine and can be accessed here.
golangci-lint-linters-v1.61.0 sheet
This sheet helps to manage the configuration for golangci-lint
. It can also help with generating
the 2 configuration files.
v1.61.0
of golangci-lint
.
This sheet lists the linters that were available in version v1.61.0
with the following columns:
- Linter: The name of the linter with a link to the source or website for it. If applicable, there is also a link to the golangci-lint’s documentation for configuring the linter. For example, https://staticcheck.io/ and https://golangci-lint.run/usage/linters/#staticcheck.
- Description: A short description of the linter.
- Status: This field indicates whether the linter is enabled or disabled.
- Comments: Self explanatory. The comments try to justify why a particular linter is enabled or disabled.
- Settings: If the linter is enabled, the value in this field is used to configure the linter.
The settings are in TOML format. These settings are hand-coded with 2 exceptions. In case of
gocritic
andrevive
, the settings are generated from their respective sheets (explained below).
This sheet lists the checks that were available in version v0.11.5
of gocritic
that was packaged
into golangci-lint@v1.61.0
. The sheet is similar to the available-linters
sheet and is used to
manage the 100+ checks provided by gocritic
. The checks that are enabled along with their optional
settings are used to build the complete settings for gocritic
in golangci-lint
’s configuration.
📒 The function BUILD_GOCRITIC_SETTINGS
is defined in the Apps Script project
linked to the sheet.
This sheet lists the checks that were available in version v1.4.0
of revive
that was packaged
into golangci-lint@v1.61.0
. The sheet is similar to the available-linters
sheet and is used to
manage the 77 checks provided by revive
. The checks that are enabled along with their optional
settings are used to build the complete settings for revive
in golangci-lint
’s configuration.
📒 The function BUILD_REVIVE_SETTINGS
is defined in the Apps Script project
linked to the sheet.
This has the static header and footer for the generation of golangci-lint
configuration.
This has the configuration for golangci-lint
generated by stitching together the following:
- Header from the
sections
sheet. - Linters enabled in the
available-linters
sheet. - Linter settings for enabled linters in
available-linters
sheet. - Footer from the
sections
sheet.
The configuration is updated in a few seconds whenever any change is made in the sheet by the Apps Script project linked to the sheet.
""
with "
and remove the quotes at the beginning and the end.
One way to use the sheet is to copy the generated configuration and modify as needed. However, if you want to be able to edit the sheet and regenerate the configuration, follow the instructions below.
Step by step instructions
Make a copy of the sheet. This will copy over the apps script project as well:
Open the apps script project via "Extensions > Apps Script". Open the triggers tab and create a new trigger with the following settings:
When you click "Save" it will ask you to authorise the apps script. This isn't an app verified by Google so you will need to click "Advanced" and click "Go to golangci-lint-linters-v1.61.0 (v2) ( unsafe)"
Finally click "Allow" to complete setting up the trigger. Now, whenever any cell in the sheet is
edited the configuration in .golangci.toml
will be rebuilt.
YAML: probably not so great after all
When we are creating a new project, it is straightforward to integrate golangci-lint
into it.
However, if we are integrating golangci-lint
into a pre-existing project where either the linter
was not integrated or the configuration was minimal, we need a strategy to iteratively fix the large
number of issues that would be reported by the linter with the new/updated configuration. Fixing all
the issues in a single effort can be inhibitively expensive. golangci-lint
provides a mechanism
for doing so by reporting issues only for new and modified lines in the commit.
See golangci-lint FAQ.
Most repositories utilise multiple tools for formatting, code/doc generation and testing. Some examples:
golangci-lint
: github.com/golangci/golangci-lintgofumpt
: github.com/mvdan/gofumptmockery
: github.com/vektra/mockery
The version of these tools needs to be kept consistent between local and CI. Sometimes the version of these tools are different across projects and different developers might have different local versions of these tools.
We can leverage Go modules to manage the necessary tooling by doing the following:
- Add a
go.mod
file undertools
directory:go mod init github.com/netskope/spm-{{repo}}/tools
- Add a
tools.go
file in the same folder with a build constraint so that it does not get included in the build://go:build tools package tools import ( _ "github.com/golangci/golangci-lint/cmd/golangci-lint" // add more imports as needed )
- Run
go mod tidy
to sync thetools/go.mod
with the tools that are declared intools.go
.
Using the tools/go.mod
, we can build the tool binaries. Task can be used for building the
binaries on demand and for managing the commonly used commands. Taskfile is a more modern
replacement for Makefiles and also has features for re-building the tools based on checksum of
module files. Taskfile example: Taskfile.yml
Developer workflow (with Task)
To install task on macOS with Homebrew, following command needs to be executed:
brew install go-task
For other operating systems please refer task installation page.
Users can install and cache tools locally for formatting, linter checks etc. by using the below command:
task install-tools
User can run task --list
to list all configured commands for the current repository.
Formatting issues can be reported by github.com/mvdan/gofumpt
and github.com/daixiang0/gci
. We just need to run task fmt
to fix all formatting issues.
It is also possible to only fix the order of import statements by running task imports
.
➜ task fmt
task: Task "install-gci" is up to date
task: Task "install-gofumpt" is up to date
task: [imports] .tools/gci write ./ --section standard --section default --section "Prefix(github.com/netskope,github.com/netSkope)" --skip-generated --skip-vendor
task: [fmt] .tools/gofumpt -l -w -extra .
By integrating the tools to the IDE, we can enable format on save so that files are always formatted correctly.
- Install the Go Linter plugin for GoLand.
- Under Tools | Go Linter, For the "Path to golangci-lint", select the
golangci-lint
binary present in the.tools
directory inside the project (runtask install-tools
if binary is not present under.tools
).
Go Linter should automatically pick .golangci.toml
as the configuration file. It is recommended to
use this with the IDE plugin to avoid running some of the heavy linters like unused
during
development. task lint
can be used to lint the source files against .golangci-prod.toml
.
- Open IDE preferences with
⌘
+,
. - Navigate to the 'File Watchers' settings: Tools | File Watchers.
- Click the 'Import' icon () and select the file
.idea/watchers-cfg.xml
. To show hidden folders in the Finder app on macOS, press⌘
+⇧
+.
.
These file watchers will run gci
and gofumpt
for updating import lines and formatting the code
idiomatically on saving the file.
- Under Code Style | Go:
- Select the "Imports" tab and set "Sorting type" to "None".
- Under the "Other" tab:
- Deselect "On Reformat Code action"
- Select "Add a leading space to comments". under "Except for comments starting with:" add
nolint
andgo:
. - Under Tools | Actions on Save, deselect "Reformat Code".
False positives are inevitable but golangci-lint
provides flexible mechanisms for working around
false positives. We can either use //nolint
directives to ignore a specific error or we can update
the .golangci-lint*.toml
and add an exclude-rule
.
See https://golangci-lint.run/usage/false-positives/ for more details.
When adding or updating exclude-rules
, remember to update both .golangci.toml
and
.golangci-prod.toml
.