# See: https://olegk.dev/go-linters-configuration-the-right-version

run:
  # Depends on your hardware, my laptop can survive 8 threads.
  concurrency: 8

  # I really care about the result, so I'm fine to wait for it.
  timeout: 30m

  # Fail if the error was met.
  issues-exit-code: 1

  # This is very important, bugs in tests are not acceptable either.
  tests: true

  # In most cases this can be empty but there is a popular pattern
  # to keep integration tests under this tag. Such tests often require
  # additional setups like Postgres, Redis etc and are run separately.
  # (to be honest I don't find this useful but I have such tags)
  build-tags:
    - integration

  # Autogenerated files can be skipped (I'm looking at you gRPC).
  # AFAIK autogen files are skipped but skipping the whole directory should be somewhat faster.
  #skip-files:
  #  - "protobuf/.*.go"

  # With the read-only mode linter will fail if go.mod file is outdated.
  modules-download-mode: readonly

  # Till today I didn't know this param exists, never ran 2 golangci-lint at once.
  allow-parallel-runners: false

  # Keep this empty to use the Go version from the go.mod file.
  go: ""

linters:
  # Set to true runs only fast linters.
  # Good option for 'lint on save', pre-commit hook or CI.
  fast: false

  enable:
    # Check for pass []any as any in variadic func(...any).
    # Rare case but saved me from debugging a few times.
    - asasalint

    # I prefer plane ASCII identifiers.
    # Symbol `∆` instead of `delta` looks cool but no thanks.
    - asciicheck

    # Checks for dangerous unicode character sequences.
    # Super rare but why not to be a bit paranoid?
    - bidichk

    # Checks whether HTTP response body is closed successfully.
    - bodyclose

    # Check whether the function uses a non-inherited context.
    - contextcheck

    # Check for two durations multiplied together.
    - durationcheck

    # Forces to not skip error check.
    - errcheck

    # Checks `Err-` prefix for var and `-Error` suffix for error type.
    - errname

    # Suggests to use `%w` for error-wrapping.
    - errorlint

    # Checks for pointers to enclosing loop variables.
    - exportloopref

    # As you already know I'm a co-author. It would be strange to not use
    # one of my warmly loved projects.
    - gocritic

    # Forces to put `.` at the end of the comment. Code is poetry.
    - godot

    # Might not be that important but I prefer to keep all of them.
    # `gofumpt` is amazing, kudos to Daniel Marti https://github.com/mvdan/gofumpt
    - gofmt
    - gofumpt

    # Allow or ban replace directives in go.mod
    # or force explanation for retract directives.

    # Powerful security-oriented linter. But requires some time to
    # configure it properly, see https://github.com/securego/gosec#available-rules
    - gosec

    # Linter that specializes in simplifying code.
    - gosimple

    # Official Go tool. Must have.
    - govet

    # Detects when assignments to existing variables are not used
    # Last week I caught a bug with it.
    - ineffassign

    # Even with deprecation notice I find it useful.
    # There are situations when instead of io.ReaderCloser
    # I can use io.Reader. A small but good improvement.
    - staticcheck

    # Fix all the misspells, amazing thing.
    - misspell

    # Finds naked/bare returns and requires change them.
    - nakedret

    # Both require a bit more explicit returns.
    - nilerr
    - nilnil

    # Finds sending HTTP request without context.Context.
    - noctx

    # Forces comment why another check is disabled.
    # Better not to have //nolint: at all ;)
    - nolintlint

    # Finds slices that could potentially be pre-allocated.
    # Small performance win + cleaner code.
    - prealloc

    # Finds shadowing of Go's predeclared identifiers.
    # I hear a lot of complaints from junior developers.
    # But after some time they find it very useful.
    - predeclared

    # Lint your Prometheus metrics name.
    - promlinter

    # Checks that package variables are not reassigned.
    # Super rare case but can catch bad things (like `io.EOF = nil`)
    - reassign

    # Drop-in replacement of `golint`.
    - revive

    # Somewhat similar to `bodyclose` but for `database/sql` package.
    - rowserrcheck
    - sqlclosecheck

    # I have found that it's not the same as staticcheck binary :\
    - staticcheck

    # Is a replacement for `golint`, similar to `revive`.
    - stylecheck

    # Check struct tags.
    - tagliatelle

    # Test-related checks. All of them are good.
    - tenv
    - testableexamples
    - thelper
    - tparallel

    # Remove unnecessary type conversions, make code cleaner
    - unconvert

    # Might be noisy but better to know what is unused
    - unparam

    # Must have. Finds unused declarations.
    - unused

    # Detect the possibility to use variables/constants from stdlib.
    - usestdlibvars

    # Finds wasted assignment statements.
    - wastedassign

  disable:
    # Detects struct contained context.Context field. Not a problem.
    - containedctx

    # Checks function and package cyclomatic complexity.
    # I can have a long but trivial switch-case.
    #
    # Cyclomatic complexity is a measurement, not a goal.
    # (c) Bryan C. Mills / https://github.com/bcmills
    - cyclop

    # Check declaration order of types, consts, vars and funcs.
    # I like it but I don't use it.
    - decorder

    # Checks if package imports are in a list of acceptable packages.
    # I'm very picky about what I import, so no automation.
    - depguard

    # Checks assignments with too many blank identifiers. Very rare.
    - dogsled

    # Tool for code clone detection.
    - dupl

    # Find duplicate words, rare.
    - dupword

    # I'm fine to check the error from json.Marshal ¯\_(ツ)_/¯
    - errchkjson

    # All SQL queries MUST BE covered with tests.
    - execinquery

    # Forces to handle more cases. Cool but noisy.
    - exhaustive
    - exhaustruct

    # Forbids some identifiers. I don't have a case for it.
    - forbidigo

    # Finds forced type assertions, very good for juniors.
    - forcetypeassert

    # I might have long but a simple function.
    - funlen

    # Imports order. I do this manually ¯\_(ツ)_/¯
    - gci

    # I'm not a fan of ginkgo and gomega packages.
    - ginkgolinter

    # Checks that compiler directive comments (//go:) are valid. Rare.
    - gocheckcompilerdirectives

    # Globals and init() are ok.
    - gochecknoglobals
    - gochecknoinits

    # Same as `cyclop` linter (see above)
    - gocognit
    - goconst
    - gocyclo

    # TODO and friends are ok.
    - godox

    # Check the error handling expressions. Too noisy.
    - err113

    # I don't use file headers.
    - goheader

    # Reports magic consts. Might be noisy but still good.
    - gomnd

    # Allowed/blocked packages to import. I prefer to do it manually.
    - gomodguard

    # Printf-like functions must have -f.
    - goprintffuncname

    # Groupt declarations, I prefer manually.
    - grouper

    # Checks imports aliases, rare.
    - importas

    # Forces tiny interfaces, very subjective.
    - interfacebloat

    # Accept interfaces, return types. Not always.
    - ireturn

    # I don't set line length. 120 is fine by the way ;)
    - lll

    # Some log checkers, might be useful.
    - loggercheck

    # Maintainability index of each function, subjective.
    - maintidx

    # Slice declarations with non-zero initial length. Not my case.
    - makezero

    # Enforce tags in un/marshaled structs. Cool but not my case.
    - musttag

    # Deeply nested if statements, subjective.
    - nestif

    # Forces newlines in some places.
    - nlreturn

    # Reports all named returns, not that bad.
    - nonamedreturns

    # Finds misuse of Sprintf with host:port in a URL. Cool but rare.
    - nosprintfhostport

    # I don't use t.Parallel() that much.
    - paralleltest

    # Often non-`_test` package is ok.
    - testpackage

    # Compiler can do it too :)
    - typecheck

    # I'm fine with long variable names with a small scope.
    - varnamelen

    # gofmt,gofumpt covers that (from what I know).
    - whitespace

    # Don't find it useful to wrap all errors from external packages.
    - wrapcheck

    # Forces you to use empty lines. Great if configured correctly.
    # I mean there is an agreement in a team.
    - wsl

linters-settings:
  # I'm biased and I'm enabling more than 100 checks
  # Might be too much for you. See https://go-critic.com/overview.html
  gocritic:
    enabled-tags:
      - diagnostic
      - experimental
      - opinionated
      - performance
      - style
    disabled-checks:
      # These 3 will detect many cases, but they do sense
      # if it's performance oriented code
      - hugeParam
      - rangeExprCopy
      - rangeValCopy

  errcheck:
    # Report `a := b.(MyStruct)` when `a, ok := ...` should be.
    check-type-assertions: true # Default: false

    # Report skipped checks:`num, _ := strconv.Atoi(numStr)`.
    check-blank: true # Default: false

    # Function to skip.
    exclude-functions:
      - io/ioutil.ReadFile
      - io.Copy(*bytes.Buffer)
      - io.Copy(os.Stdout)

  govet:
    disable:
      - fieldalignment # I'm ok to waste some bytes

  nakedret:
    # No naked returns, ever.
    max-func-lines: 1 # Default: 30

  tagliatelle:
    case:
      rules:
        json: snake # why it's not a `snake` by default?!
        yaml: snake # why it's not a `snake` by default?!
        xml: camel
        bson: camel
        avro: snake
        mapstructure: kebab

# See also https://gist.github.com/cristaloleg/dc29ca0ef2fb554de28d94c3c6f6dc88

output:
  # I prefer the simplest one: `line-number` and saving to `lint.txt`
  #
  # The `tab` also looks good and with the next release I will switch to it
  # (ref: https://github.com/golangci/golangci-lint/issues/3728)
  #
  # There are more formats which can be used on CI or by your IDE.


  # I do not find this useful, parameter above already enables filepath
  # with a line and column. For me, it's easier to follow the path and
  # see the line in an IDE where I see more code and understand it better.
  print-issued-lines: true

  # Must have. Easier to understand the output.
  print-linter-name: true

  # No, no skips, everything should be reported.
  uniq-by-line: true

  # To be honest no idea when this can be needed, maybe a multi-module setup?
  path-prefix: ""

  # Slightly easier to follow the results + getting deterministic output.
  sort-results: true

issues:
  # I found it strange to skip the errors, setting 0 to have all the results.
  max-issues-per-linter: 0

  exclude-files:
    - ".*_test.go"

  # Same here, nothing should be skipped to not miss errors.
  max-same-issues: 0

  # When set to `true` linter will analyze only new code which are
  # not committed or after some specific revision. This is a cool
  # feature when you're going to introduce linter into a big project.
  # But I prefer going gradually package by package.
  # So, it's set to `false` to scan all code.
  new: false

  # 2 other params regarding git integration

  # Even with a recent GPT-4 release I still believe that
  # I know better how to do my job and fix the suggestions.
  fix: false