# Kudos to Oleg Kovalov https://olegk.dev/go-linters-configuration-the-right-version

run:
  # Depends on your hardware
  concurrency: 1

  timeout: 30m

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

  # Check for bugs in tests.
  tests: false

  skip-dirs:
    - (^|/)vendor($|/)

  skip-files:
    - .*_test.go

  # When enabled linter will skip directories: vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
  skip-dirs-use-default: false

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

  # 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

    # Finds forced type assertions.
    - forcetypeassert

    # Imports order.
    - gci

    # Almost 100 diagnostics that check for bugs, performance and style issues
    # Highly extensible Go source code linter providing checks currently missing from other linters.
    - gocritic

    # Forces to put `.` at the end of the comment.
    - 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
    - goimports

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

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

    # Allowed/blocked packages to import.
    - gomodguard

    # 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

    # Groupt declarations.
    - grouper

    # Detects when assignments to existing variables are not used.
    - 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.
    - interfacer

    # Some log checkers, might be useful.
    - loggercheck

    # Fix all the misspellings, amazing thing.
    - misspell

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

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

    # Forces newlines in some places.
    - nlreturn

    # 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.
    - 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

    # Deprecated, replaced by `unused`.
    - deadcode

    # Check declaration order of types, consts, vars and funcs.
    - decorder

    # Checks if package imports are in a list of acceptable packages.
    - 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
    - exhaustivestruct # Deprecated, replaced by check below.
    - exhaustruct

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

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

    # 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.
    - goerr113

    # I don't use file headers.
    - goheader

    # 1st Go linter, deprecated :( use `revive`.
    - golint

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

    # Deprecated
    - ifshort

    # Checks imports aliases, rare.
    - importas

    # Forces tiny interfaces, very subjective.
    - interfacebloat

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

    # I don't set line length.
    - lll

    # Maintainability index of each function, subjective.
    - maintidx

    # Slice declarations with non-zero initial length.
    - makezero

    # Deprecated. Use govet `fieldalignment`.
    - maligned

    # Deeply nested if statements, subjective.
    - nestif

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

    # Deprecated. Replaced by `revive`.
    - nosnakecase

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

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

    # Deprecated
    - scopelint

    # Deprecated
    - structcheck

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

    # Compiler can do it too :)
    - typecheck

    # Deprecated
    - varcheck

    # 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:
  format: colored-line-number

  # I do not find this useful, parameter above already enables filepath
  # with a line and column.
  print-issued-lines: false

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

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

  # 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:
  # Found it strange to skip the errors, setting 0 to have all the results.
  max-issues-per-linter: 0

  # 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