[run]
  deadline = "10m"

  tests = true

[linters]
  disable-all = true
  enable = [
    "asciicheck",
    "bidichk",
    "bodyclose",
    "containedctx",
    "contextcheck",
    "deadcode",
    "depguard",
    "durationcheck",
    "errcheck",
    "errchkjson",
    "errname",
    "errorlint",
    "exportloopref",
    "forbidigo",
    #"forcetypeassert",
    "goconst",
    "gocyclo",
    "gocritic",
    "godot",
    "gofumpt",
    "gomodguard",
    "gosec",
    "gosimple",
    "govet",
    "grouper",
    "ineffassign",
    "lll",
    "makezero",
    "maintidx",
    "misspell",
    "nakedret",
    "nilerr",
    "noctx",
    "nolintlint",
    "nosprintfhostport",
    "predeclared",
    "revive",
    "rowserrcheck",
    "sqlclosecheck",
    "staticcheck",
    "structcheck",
    "stylecheck",
    "tenv",
    "tparallel",
    "typecheck",
    "unconvert",
    "unparam",
    "unused",
    "varcheck",
    "vetshadow",
    "wastedassign",
  ]

# Please note that we only use depguard for stdlib as gomodguard only
# supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12
[linters-settings.depguard]
  list-type = "blacklist"
  include-go-root = true
  packages = [
    # ioutil is deprecated. The functions have been moved elsewhere:
    # https://golang.org/doc/go1.16#ioutil
    "io/ioutil",
  ]

[linters-settings.errcheck]
    # Don't allow setting of error to the blank identifier. If there is a legtimate
    # reason, there should be a nolint with an explanation.
    check-blank = true

    exclude-functions = [
        # If we are rolling back a transaction, we are often already in an error
        # state.
        '(*database/sql.Tx).Rollback',

        # It is reasonable to ignore errors if Cleanup fails in most cases.
        '(*github.com/google/renameio/v2.PendingFile).Cleanup',

        # We often don't care if removing a file failed (e.g., it doesn't exist)
        'os.Remove',
        'os.RemoveAll',
    ]

    # Ignoring Close so that we don't have to have a bunch of
    # `defer func() { _ = r.Close() }()` constructs when we
    # don't actually care about the error.
    ignore = "Close,fmt:.*"

[linters-settings.errorlint]
    errorf = true
    asserts = true
    comparison = true

[linters-settings.exhaustive]
    default-signifies-exhaustive = true

[linters-settings.forbidigo]
    # Forbid the following identifiers
    forbid = [
        "^minFraud*",
        "^maxMind*",
    ]

[linters-settings.gocritic]
    enabled-checks = [
        "appendAssign",
        "appendCombine",
        "argOrder",
        "assignOp",
        "badCall",
        "badCond",
        "badLock",
        "badRegexp",
        "badSorting",
        "boolExprSimplify",
        "builtinShadow",
        "builtinShadowDecl",
        "captLocal",
        "caseOrder",
        "codegenComment",
        "commentedOutCode",
        "commentedOutImport",
        "commentFormatting",
        "defaultCaseOrder",
        # Revive's defer rule already captures this. This caught no extra cases.
        # "deferInLoop",
        "deferUnlambda",
        "deprecatedComment",
        "docStub",
        "dupArg",
        "dupBranchBody",
        "dupCase",
        "dupImport",
        "dupSubExpr",
        "dynamicFmtString",
        "elseif",
        "emptyDecl",
        "emptyFallthrough",
        "emptyStringTest",
        "equalFold",
        "evalOrder",
        "exitAfterDefer",
        "exposedSyncMutex",
        "externalErrorReassign",
        # Given that all of our code runs on Linux and the / separate should
        # work fine, this seems less important.
        # "filepathJoin",
        "flagDeref",
        "flagName",
        "hexLiteral",
        "ifElseChain",
        "importShadow",
        "indexAlloc",
        "initClause",
        "ioutilDeprecated",
        "mapKey",
        "methodExprCall",
        "nestingReduce",
        "newDeref",
        "nilValReturn",
        "octalLiteral",
        "offBy1",
        "paramTypeCombine",
        "preferDecodeRune",
        "preferFilepathJoin",
        "preferFprint",
        "preferStringWriter",
        "preferWriteByte",
        "ptrToRefParam",
        "rangeExprCopy",
        "rangeValCopy",
        "redundantSprint",
        "regexpMust",
        "regexpPattern",
        # This might be good, but I don't think we want to encourage
        # significant changes to regexes as we port stuff from Perl.
        # "regexpSimplify",
        "ruleguard",
        "singleCaseSwitch",
        "sliceClear",
        "sloppyLen",
        # This seems like it might also be good, but a lot of existing code
        # fails.
        # "sloppyReassign",
        "returnAfterHttpError",
        "sloppyTypeAssert",
        "sortSlice",
        "sprintfQuotedString",
        "sqlQuery",
        "stringsCompare",
        "stringXbytes",
        "switchTrue",
        "syncMapLoadAndDelete",
        "timeExprSimplify",
        "todoCommentWithoutDetail",
        "tooManyResultsChecker",
        "truncateCmp",
        "typeAssertChain",
        "typeDefFirst",
        "typeSwitchVar",
        "typeUnparen",
        "underef",
        "unlabelStmt",
        "unlambda",
        # I am not sure we would want this linter and a lot of existing
        # code fails.
        # "unnamedResult",
        "unnecessaryBlock",
        "unnecessaryDefer",
        "unslice",
        "valSwap",
        "weakCond",
        "wrapperFunc",
        "yodaStyleExpr",
        # This requires explanations for "nolint" directives. This would be
        # nice for gosec ones, but I am not sure we want it generally unless
        # we can get the false positive rate lower.
        # "whyNoLint"
    ]

[linters-settings.gofumpt]
    extra-rules = true
    lang-version = "1.18"

[linters-settings.govet]
    "enable-all" = true

[linters-settings.lll]
    line-length = 120
    tab-width = 4

[linters-settings.nolintlint]
    allow-leading-space = false
    allow-unused = false
    allow-no-explanation = ["lll", "misspell"]
    require-explanation = true
    require-specific = true

[linters-settings.revive]
    ignore-generated-header = true
    severity = "warning"

    # This might be nice but it is so common that it is hard
    # to enable.
    # [[linters-settings.revive.rules]]
    # name = "add-constant"

    # [[linters-settings.revive.rules]]
    # name = "argument-limit"

    [[linters-settings.revive.rules]]
    name = "atomic"

    [[linters-settings.revive.rules]]
    name = "bare-return"

    [[linters-settings.revive.rules]]
    name = "blank-imports"

    [[linters-settings.revive.rules]]
    name = "bool-literal-in-expr"

    [[linters-settings.revive.rules]]
    name = "call-to-gc"

    # [[linters-settings.revive.rules]]
    # name = "cognitive-complexity"

    # Probably a good rule, but we have a lot of names that
    # only have case differences.
    # [[linters-settings.revive.rules]]
    # name = "confusing-naming"

    # [[linters-settings.revive.rules]]
    # name = "confusing-results"

    [[linters-settings.revive.rules]]
    name = "constant-logical-expr"

    [[linters-settings.revive.rules]]
    name = "context-as-argument"

    [[linters-settings.revive.rules]]
    name = "context-keys-type"

    # [[linters-settings.revive.rules]]
    # name = "cyclomatic"

    # [[linters-settings.revive.rules]]
    # name = "deep-exit"

    [[linters-settings.revive.rules]]
    name = "defer"

    [[linters-settings.revive.rules]]
    name = "dot-imports"

    [[linters-settings.revive.rules]]
    name = "duplicated-imports"

    [[linters-settings.revive.rules]]
    name = "early-return"

    [[linters-settings.revive.rules]]
    name = "empty-block"

    [[linters-settings.revive.rules]]
    name = "empty-lines"

    [[linters-settings.revive.rules]]
    name = "errorf"

    [[linters-settings.revive.rules]]
    name = "error-naming"

    [[linters-settings.revive.rules]]
    name = "error-return"

    [[linters-settings.revive.rules]]
    name = "error-strings"

    [[linters-settings.revive.rules]]
    name = "exported"

    # [[linters-settings.revive.rules]]
    # name = "file-header"

    # We have a lot of flag parameters. This linter probably makes
    # a good point, but we would need some cleanup or a lot of nolints.
    # [[linters-settings.revive.rules]]
    # name = "flag-parameter"

    # [[linters-settings.revive.rules]]
    # name = "function-result-limit"

    [[linters-settings.revive.rules]]
    name = "get-return"

    [[linters-settings.revive.rules]]
    name = "identical-branches"

    [[linters-settings.revive.rules]]
    name = "if-return"

    [[linters-settings.revive.rules]]
    name = "imports-blacklist"

    [[linters-settings.revive.rules]]
    name = "import-shadowing"

    [[linters-settings.revive.rules]]
    name = "increment-decrement"

    [[linters-settings.revive.rules]]
    name = "indent-error-flow"

    # [[linters-settings.revive.rules]]
    # name = "line-length-limit"

    # [[linters-settings.revive.rules]]
    # name = "max-public-structs"

    [[linters-settings.revive.rules]]
    name = "modifies-parameter"

    [[linters-settings.revive.rules]]
    name = "modifies-value-receiver"

    # We frequently use nested structs, particularly in tests.
    # [[linters-settings.revive.rules]]
    # name = "nested-structs"

    [[linters-settings.revive.rules]]
    name = "optimize-operands-order"

    [[linters-settings.revive.rules]]
    name = "package-comments"

    [[linters-settings.revive.rules]]
    name = "range"

    [[linters-settings.revive.rules]]
    name = "range-val-address"

    [[linters-settings.revive.rules]]
    name = "range-val-in-closure"

    [[linters-settings.revive.rules]]
    name = "receiver-naming"

    [[linters-settings.revive.rules]]
    name = "redefines-builtin-id"

    [[linters-settings.revive.rules]]
    name = "string-of-int"

    [[linters-settings.revive.rules]]
    name = "struct-tag"

    [[linters-settings.revive.rules]]
    name = "superfluous-else"

    [[linters-settings.revive.rules]]
    name = "time-naming"

    [[linters-settings.revive.rules]]
    name = "unconditional-recursion"

    [[linters-settings.revive.rules]]
    name = "unexported-naming"

    [[linters-settings.revive.rules]]
    name = "unexported-return"

    # This is covered elsewhere and we want to ignore some
    # functions such as fmt.Fprintf.
    # [[linters-settings.revive.rules]]
    # name = "unhandled-error"

    [[linters-settings.revive.rules]]
    name = "unnecessary-stmt"

    [[linters-settings.revive.rules]]
    name = "unreachable-code"

    [[linters-settings.revive.rules]]
    name = "unused-parameter"

    # We generally have unused receivers in tests for meeting the
    # requirements of an interface.
    # [[linters-settings.revive.rules]]
    # name = "unused-receiver"

    # This probably makes sense after we upgrade to 1.18
    # [[linters-settings.revive.rules]]
    # name = "use-any"

    [[linters-settings.revive.rules]]
    name = "useless-break"

    [[linters-settings.revive.rules]]
    name = "var-declaration"

    [[linters-settings.revive.rules]]
    name = "var-naming"

    [[linters-settings.revive.rules]]
    name = "waitgroup-by-value"

[linters-settings.unparam]
    check-exported = true

[[issues.exclude-rules]]
  linters = [
    "govet"
  ]
  # we want to enable almost all govet rules. It is easier to just filter out
  # the ones we don't want:
  #
  # * fieldalignment - way too noisy. Although it is very useful in particular
  #   cases where we are trying to use as little memory as possible, having
  #   it go off on every struct isn't helpful.
  # * shadow - although often useful, it complains about _many_ err
  #   shadowing assignments and some others where shadowing is clear.
  text = "^(fieldalignment|shadow)"
