Intro

If you program in Go, you probably have used the built-in linter, the go vet ./..., this linter is good and catches some common issues, but today we will explore some alternatives, and the chosen one was golangci-lint.

golangci-lint isn’t a linter; it is a collection of linters. Over 70 linters on it will point you from code style inconsistencies to nasty bugs.

As the name suggests, it is built to run on a continuous integration environment and is fast!

Examples of issues found

cmd/web/main.go:47:3: exitAfterDefer: os.Exit will exit, and defer cancel() will not run (gocritic) os.Exit(1)

This one a good example that may lead to serious problems of memory leaks and resource leaks.

internal/model/user.go:15:13: G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec) number := uint(rand.Uint64())

This one is good advice to use good random number generators.

pkg/errors/errors.go:14:74: occured is a misspelling of occurred (misspell) ErrUnexpected = &Error{Code: 9999, Err: errors.New(“an unexpected error occured”)}

It is always good to fix all spelling, this tool also catches missing periods for example.

Running locally

golangci-lint, like many Go projects, is a single binary. You can download it and put it into /usr/local/bin, it is also possible to install it using brew.

There are other methods, please refer to this page to check out.

My preferred method is through Docker:

docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint golangci-lint run

If you want to use all linters and possibly catch all issues, run with the flag --enable-all. Be prepared, because this tool takes serious code smell and possible sources of bugs.

Your project must have a go.mod and at least one source code, like main.go, for the tool runs.

Using it on GitHub Action

To run in an Action on GitHub it is pretty simple, just add the contents below to a file named .github/workflows/lint.yml.

name: golangci-lint
on:
  push:
    tags:
      - v*
    branches:
      - master
      - main
  pull_request:
permissions:
  contents: read
jobs:
  golangci:
    name: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-go@v3
        with:
          go-version: 1.19
      - name: Checkout
        uses: actions/checkout@v3
      - name: Lint
        uses: golangci/golangci-lint-action@v3
        with:
          version: latest

Please refer to the full documentation for more details.

Lint All The Things!
Lint All The Things!

Conclusion

Having lint in your tool belt is always a good idea; having multiple linters is even better.

Discuss on Twitter

Related articles: