diff --git a/.golangci.yaml b/.golangci.yaml index b36b0da..ada6abc 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,46 +1,33 @@ # This file contains all available configuration options -# with their default values. +# with their default values (in comments). +# +# This file is not a configuration example, +# it contains the exhaustive configuration with explanations of the options. -# options for analysis running +# Options for analysis running. run: - # default concurrency is a available CPU number - concurrency: 4 + # Number of operating system threads (`GOMAXPROCS`) that can execute golangci-lint simultaneously. + # If it is explicitly set to 0 (i.e. not the default) then golangci-lint will automatically set the value to match Linux container CPU quota. + # Default: the number of logical CPUs in the machine + concurrency: 0 - # timeout for analysis, e.g. 30s, 5m, default is 1m - timeout: 5m + # Timeout for analysis, e.g. 30s, 5m. + # Default: 1m + timeout: 10m - # exit code when at least one issue was found, default is 1 - issues-exit-code: 1 + # Exit code when at least one issue was found. + # Default: 1 + issues-exit-code: 2 - # include test files or not, default is true + # Include test files or not. + # Default: true tests: false - # list of build tags, all linters use it. Default is empty list. - build-tags: - - # which dirs to skip: issues from them won't be reported; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but default dirs are skipped independently - # from this option's value (see skip-dirs-use-default). - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-dirs: - - logger - - serializable - - # default is true. Enables skipping of directories: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs-use-default: true - - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-files: - - # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # List of build tags, all linters use it. + # Default: [] + build-tags: [] + + # If set, we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit # automatic updating of go.mod described above. Instead, it fails when any changes # to go.mod are needed. This setting is most useful to check that go.mod does @@ -48,559 +35,2923 @@ run: # If invoked with -mod=vendor, the go command assumes that the vendor # directory holds the correct copies of dependencies and ignores # the dependency descriptions in go.mod. + # + # Allowed values: readonly|vendor|mod + # Default: "" modules-download-mode: readonly # Allow multiple parallel golangci-lint instances running. - # If false (default) - golangci-lint acquires file lock on start. - allow-parallel-runners: false + # If false, golangci-lint acquires file lock on start. + # Default: false + allow-parallel-runners: true + + # Allow multiple golangci-lint instances running, but serialize them around a lock. + # If false, golangci-lint exits with an error if it fails to acquire file lock on start. + # Default: false + allow-serial-runners: true + + # Define the Go version limit. + # Mainly related to generics support since go1.18. + # Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.17 + go: '' # output configuration options output: - # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - format: colored-line-number + # The formats used to render issues. + # Formats: + # - `colored-line-number` + # - `line-number` + # - `json` + # - `colored-tab` + # - `tab` + # - `html` + # - `checkstyle` + # - `code-climate` + # - `junit-xml` + # - `github-actions` + # - `teamcity` + # - `sarif` + # Output path can be either `stdout`, `stderr` or path to the file to write to. + # + # For the CLI flag (`--out-format`), multiple formats can be specified by separating them by comma. + # The output can be specified for each of them by separating format name and path by colon symbol. + # Example: "--out-format=checkstyle:report.xml,json:stdout,colored-line-number" + # The CLI flag (`--out-format`) override the configuration file. + # + # Default: + # formats: + # - format: colored-line-number + # path: stdout + formats: + - format: json + path: stderr + # - format: checkstyle + # path: report.xml + - format: colored-line-number - # print lines of code with issue, default is true + # Print lines of code with issue. + # Default: true print-issued-lines: true - # print linter name in the end of issue text, default is true + # Print linter name in the end of issue text. + # Default: true print-linter-name: true - # make issues output unique by line, default is true + # Make issues output unique by line. + # Default: true uniq-by-line: true - # add a prefix to the output file references; default is no prefix + # Add a prefix to the output file references. + # Default: "" path-prefix: "" - # sorts results by: filepath, line and column - sort-results: false + # Sort results by the order defined in `sort-order`. + # Default: false + sort-results: true + + # Order to use when sorting results. + # Require `sort-results` to `true`. + # Possible values: `file`, `linter`, and `severity`. + # + # If the severity values are inside the following list, they are ordered in this order: + # 1. error + # 2. warning + # 3. high + # 4. medium + # 5. low + # Either they are sorted alphabetically. + # + # Default: ["file"] + sort-order: + - linter + - severity + - file # filepath, line, and column. + + # Show statistics per linter. + # Default: false + show-stats: true -# all available settings of specific linters +# All available settings of specific linters. linters-settings: + asasalint: + # To specify a set of function names to exclude. + # The values are merged with the builtin exclusions. + # The builtin exclusions can be disabled by setting `use-builtin-exclusions` to `false`. + # Default: ["^(fmt|log|logger|t|)\.(Print|Fprint|Sprint|Fatal|Panic|Error|Warn|Warning|Info|Debug|Log)(|f|ln)$"] + exclude: + - Append + - \.Wrapf + # To enable/disable the asasalint builtin exclusions of function names. + # See the default value of `exclude` to get the builtin exclusions. + # Default: true + use-builtin-exclusions: false + # Ignore *_test.go files. + # Default: false + ignore-test: true + + bidichk: + # The following configurations check for all mentioned invisible unicode runes. + # All runes are enabled by default. + left-to-right-embedding: false + right-to-left-embedding: false + pop-directional-formatting: false + left-to-right-override: false + right-to-left-override: false + left-to-right-isolate: false + right-to-left-isolate: false + first-strong-isolate: false + pop-directional-isolate: false + + copyloopvar: + # Check all assigning the loop variable to another variable. + # Default: false + check-alias: true + + cyclop: + # The maximal code complexity to report. + # Default: 10 + max-complexity: 15 + # The maximal average package complexity. + # If it's higher than 0.0 (float) the check is enabled + # Default: 0.0 + package-average: 0.0 + # Should ignore tests. + # Default: false + skip-tests: false + + decorder: + # Required order of `type`, `const`, `var` and `func` declarations inside a file. + # Default: types before constants before variables before functions. + dec-order: + - type + - const + - var + - func + + # If true, underscore vars (vars with "_" as the name) will be ignored at all checks + # Default: false (underscore vars are not ignored) + ignore-underscore-vars: false + + # If true, order of declarations is not checked at all. + # Default: true (disabled) + disable-dec-order-check: false + + # If true, `init` func can be anywhere in file (does not have to be declared before all other functions). + # Default: true (disabled) + disable-init-func-first-check: false + + # If true, multiple global `type`, `const` and `var` declarations are allowed. + # Default: true (disabled) + disable-dec-num-check: true + + # If true, type declarations will be ignored for dec num check + # Default: false (type statements are not ignored) + disable-type-dec-num-check: false + + # If true, const declarations will be ignored for dec num check + # Default: false (const statements are not ignored) + disable-const-dec-num-check: false + + # If true, var declarations will be ignored for dec num check + # Default: false (var statements are not ignored) + disable-var-dec-num-check: false + + depguard: + # Rules to apply. + # + # Variables: + # - File Variables + # you can still use and exclamation mark ! in front of a variable to say not to use it. + # Example !$test will match any file that is not a go test file. + # + # `$all` - matches all go files + # `$test` - matches all go test files + # + # - Package Variables + # + # `$gostd` - matches all of go's standard library (Pulled from `GOROOT`) + # + # Default: Only allow $gostd in all files. + rules: + # Name of a rule. + main: + # Used to determine the package matching priority. + # There are three different modes: `original`, `strict`, and `lax`. + # Default: "original" + list-mode: lax + # List of file globs that will match this list of settings to compare against. + # Default: $all + files: + - "!**/*_a _file.go" + # List of allowed packages. + allow: + - $gostd + # Packages that are not allowed where the value is a suggestion. + deny: + - pkg: "github.com/sirupsen/logrus" + desc: not allowed + - pkg: "github.com/pkg/errors" + desc: Should be replaced by standard lib errors package + dogsled: - # checks assignments with too many blank identifiers; default is 2 - max-blank-identifiers: 2 + # Checks assignments with too many blank identifiers. + # Default: 2 + max-blank-identifiers: 3 + dupl: - # tokens count to trigger issue, 150 by default - threshold: 100 + # Tokens count to trigger issue. + # Default: 150 + threshold: 120 + + dupword: + # Keywords for detecting duplicate words. + # If this list is not empty, only the words defined in this list will be detected. + # Default: [] + keywords: + - "the" + - "and" + - "a" + # Keywords used to ignore detection. + # Default: [] + ignore: + - "0C0C" + errcheck: - # report about not checking of errors in type assertions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. - check-type-assertions: false + # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. + # Such cases aren't reported by default. + # Default: false + check-type-assertions: true - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; - # default is false: such cases aren't reported by default. + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`. + # Such cases aren't reported by default. + # Default: false check-blank: false - # [deprecated] comma-separated list of pairs of the form pkg:regex - # the regex is used to ignore names within pkg. (default "fmt:.*"). - # see https://github.com/kisielk/errcheck#the-deprecated-method for details - ignore: fmt:.*,io/ioutil:^Read.* + # To disable the errcheck built-in exclude list. + # See `-excludeonly` option in https://github.com/kisielk/errcheck#excluding-functions for details. + # Default: false + disable-default-exclusions: false + + # List of functions to exclude from checking, where each entry is a single function to exclude. + # See https://github.com/kisielk/errcheck#excluding-functions for details. + exclude-functions: + - io/ioutil.ReadFile + - io.Copy(*bytes.Buffer) + - io.Copy(os.Stdout) + + errchkjson: + # With check-error-free-encoding set to true, errchkjson does warn about errors + # from json encoding functions that are safe to be ignored, + # because they are not possible to happen. + # + # if check-error-free-encoding is set to true and errcheck linter is enabled, + # it is recommended to add the following exceptions to prevent from false positives: + # + # linters-settings: + # errcheck: + # exclude-functions: + # - encoding/json.Marshal + # - encoding/json.MarshalIndent + # + # Default: false + check-error-free-encoding: true + + # Issue on struct encoding that doesn't have exported fields. + # Default: false + report-no-exported: true + + errorlint: + # Check whether fmt.Errorf uses the %w verb for formatting errors. + # See the https://github.com/polyfloyd/go-errorlint for caveats. + # Default: true + errorf: true + # Permit more than 1 %w verb, valid per Go 1.20 (Requires errorf:true) + # Default: true + errorf-multi: false + # Check for plain type assertions and type switches. + # Default: true + asserts: true + # Check for plain error comparisons. + # Default: true + comparison: true + # Allowed errors. + # Default: [] + allowed-errors: [] + # - err: "io.EOF" + # fun: "example.com/pkg.Read" + # Allowed error "wildcards". + # Default: [] + allowed-errors-wildcard: [] + # - err: "example.com/pkg.ErrMagic" + # fun: "example.com/pkg.Magic" - # path to a file containing a list of functions to exclude from checking - # see https://github.com/kisielk/errcheck#excluding-functions for details - # exclude: /path/to/file.txt exhaustive: - # check switch statements in generated files also + # Program elements to check for exhaustiveness. + # Default: [ switch ] + check: + - switch + - map + # Check switch statements in generated files also. + # Default: false check-generated: false - # indicates that switch statements are to be considered exhaustive if a - # 'default' case is present, even if all enum members aren't listed in the - # switch - default-signifies-exhaustive: false - exhaustivestruct: - struct-patterns: - - '*.Test' - - '*.Test2' - - '*.Embedded' - - '*.External' + # Presence of "default" case in switch statements satisfies exhaustiveness, + # even if all enum members are not listed. + # Default: false + default-signifies-exhaustive: true + # Enum members matching the supplied regex do not have to be listed in + # switch statements to satisfy exhaustiveness. + # Default: "" + ignore-enum-members: "Example.+" + # Enum types matching the supplied regex do not have to be listed in + # switch statements to satisfy exhaustiveness. + # Default: "" + ignore-enum-types: "Example.+" + # Consider enums only in package scopes, not in inner scopes. + # Default: false + package-scope-only: true + # Only run exhaustive check on switches with "//exhaustive:enforce" comment. + # Default: false + explicit-exhaustive-switch: true + # Only run exhaustive check on map literals with "//exhaustive:enforce" comment. + # Default: false + explicit-exhaustive-map: true + # Switch statement requires default case even if exhaustive. + # Default: false + default-case-required: true + + exhaustruct: + # List of regular expressions to match struct packages and their names. + # Regular expressions must match complete canonical struct package/name/structname. + # If this list is empty, all structs are tested. + # Default: [] + include: + - '.+\.Test' + - 'example\.com/package\.ExampleStruct[\d]{1,2}' + # List of regular expressions to exclude struct packages and their names from checks. + # Regular expressions must match complete canonical struct package/name/structname. + # Default: [] + exclude: + - '.+/cobra\.Command$' + + forbidigo: + # Forbid the following identifiers (list of regexp). + # Default: ["^(fmt\\.Print(|f|ln)|print|println)$"] + forbid: + # Builtin function: + - ^print.*$ + # Optional message that gets included in error reports. + - p: ^fmt\.Print.*$ + msg: Do not commit print statements. + # Alternatively, put messages at the end of the regex, surrounded by `(# )?` + # Escape any special characters. Those messages get included in error reports. + - 'fmt\.Print.*(# Do not commit print statements\.)?' + # Forbid spew Dump, whether it is called as function or method. + # Depends on analyze-types below. + - ^spew\.(ConfigState\.)?Dump$ + # The package name might be ambiguous. + # The full import path can be used as additional criteria. + # Depends on analyze-types below. + - p: ^v1.Dump$ + pkg: ^example.com/pkg/api/v1$ + # Exclude godoc examples from forbidigo checks. + # Default: true + exclude-godoc-examples: false + # Instead of matching the literal source code, + # use type information to replace expressions with strings that contain the package name + # and (for methods and fields) the type name. + # This makes it possible to handle import renaming and forbid struct fields and methods. + # Default: false + analyze-types: true + funlen: + # Checks the number of lines in a function. + # If lower than 0, disable the check. + # Default: 60 lines: 120 + # Checks the number of statements in a function. + # If lower than 0, disable the check. + # Default: 40 statements: 40 + # Ignore comments when counting lines. + # Default false + ignore-comments: true + gci: - # put imports beginning with prefix after 3rd-party packages; - # only support one prefix - # if not set, use goimports.local-prefixes - local-prefixes: github.com/org/project + # Section configuration to compare against. + # Section names are case-insensitive and may contain parameters in (). + # The default order of sections is `standard > default > custom > blank > dot > alias > localmodule`, + # If `custom-order` is `true`, it follows the order of `sections` option. + # Default: ["standard", "default"] + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - prefix(github.com/org/project) # Custom section: groups all imports with the specified Prefix. + - blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled. + - dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled. + - alias # Alias section: contains all alias imports. This section is not present unless explicitly enabled. + - localmodule # Local module section: contains all local packages. This section is not present unless explicitly enabled. + + # Skip generated files. + # Default: true + skip-generated: true + + # Enable custom order of sections. + # If `true`, make the section order the same as the order of `sections`. + # Default: false + custom-order: false + + ginkgolinter: + # Suppress the wrong length assertion warning. + # Default: false + suppress-len-assertion: false + + # Suppress the wrong nil assertion warning. + # Default: false + suppress-nil-assertion: false + + # Suppress the wrong error assertion warning. + # Default: false + suppress-err-assertion: false + + # Suppress the wrong comparison assertion warning. + # Default: false + suppress-compare-assertion: false + + # Suppress the function all in async assertion warning. + # Default: false + suppress-async-assertion: false + + # Suppress warning for comparing values from different types, like `int32` and `uint32` + # Default: false + suppress-type-compare-assertion: false + + # Trigger warning for ginkgo focus containers like `FDescribe`, `FContext`, `FWhen` or `FIt` + # Default: false + forbid-focus-container: false + + # Don't trigger warnings for HaveLen(0) + # Default: false + allow-havelen-zero: false + + # Force using `Expect` with `To`, `ToNot` or `NotTo`. + # Reject using `Expect` with `Should` or `ShouldNot`. + # Default: false + force-expect-to: false + + # Best effort validation of async intervals (timeout and polling). + # Ignored the suppress-async-assertion is true. + # Default: false + validate-async-intervals: false + + # Trigger a warning for variable assignments in ginkgo containers like `Describe`, `Context` and `When`, instead of in `BeforeEach()`. + # Default: false + forbid-spec-pollution: false + gocognit: - # minimal code complexity to report, 30 by default (but we recommend 10-20) + # Minimal code complexity to report. + # Default: 30 (but we recommend 10-20) min-complexity: 30 - nestif: - # minimal complexity of if statements to report, 5 by default - min-complexity: 10 + goconst: - # minimal length of string constant, 3 by default + # Minimal length of string constant. + # Default: 3 min-len: 3 - # minimal occurrences count to trigger, 3 by default - min-occurrences: 3 + # Minimum occurrences of constant string count to trigger issue. + # Default: 3 + min-occurrences: 4 + # Ignore test files. + # Default: false + ignore-tests: true + # Look for existing constants matching the values. + # Default: true + match-constant: false + # Search also for duplicated numbers. + # Default: false + numbers: false + # Minimum value, only works with goconst.numbers + # Default: 3 + min: 3 + # Maximum value, only works with goconst.numbers + # Default: 3 + max: 3 + # Ignore when constant is not used as function argument. + # Default: true + ignore-calls: false + # Exclude strings matching the given regular expression. + # Default: "" + ignore-strings: '+.%w.+' + gocritic: - # Which checks should be enabled; can't be combined with 'disabled-checks'; - # See https://go-critic.github.io/overview#checks-overview - # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` - # By default list of stable checks is used. - enabled-checks: - - rangeValCopy - - # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty + # Disable all checks. + # Default: false + disable-all: false + # Which checks should be enabled in addition to default checks; can't be combined with 'disabled-checks'. + # By default, list of stable checks is used (https://go-critic.github.io/overview#checks-overview): + # appendAssign, argOrder, assignOp, badCall, badCond, captLocal, caseOrder, codegenComment, commentFormatting, + # defaultCaseOrder, deprecatedComment, dupArg, dupBranchBody, dupCase, dupSubExpr, elseif, exitAfterDefer, + # flagDeref, flagName, ifElseChain, mapKey, newDeref, offBy1, regexpMust, singleCaseSwitch, sloppyLen, + # sloppyTypeAssert, switchTrue, typeSwitchVar, underef, unlambda, unslice, valSwap, wrapperFunc + # To see which checks are enabled run `GL_DEBUG=gocritic golangci-lint run --enable=gocritic`. + enabled-checks: [] #enable-all + # - nestingReduce + # - unnamedResult + # - ruleguard + # - truncateCmp + + # Enable all checks. + # Default: false + enable-all: true + # Which checks should be disabled; can't be combined with 'enabled-checks'. + # Default: [] disabled-checks: + - whyNoLint - regexpMust - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". - enabled-tags: - - performance - disabled-tags: - - experimental + # Enable multiple checks by tags in addition to default checks. + # Run `GL_DEBUG=gocritic golangci-lint run --enable=gocritic` to see all tags and checks. + # See https://github.com/go-critic/go-critic#usage -> section "Tags". + # Default: [] + enabled-tags: [] + # - performance + disabled-tags: [] + # - diagnostic + # - style + # - performance + # - experimental + # - opinionated # Settings passed to gocritic. # The settings key is the name of a supported gocritic checker. # The list of supported checkers can be find in https://go-critic.github.io/overview. settings: - captLocal: # must be valid enabled check name - # whether to restrict checker to params only (default true) + # Must be valid enabled check name. + captLocal: + # Whether to restrict checker to params only. + # Default: true paramsOnly: true + commentedOutCode: + # Min length of the comment that triggers a warning. + # Default: 15 + minLength: 100 elseif: - # whether to skip balanced if-else pairs (default true) + # Whether to skip balanced if-else pairs. + # Default: true skipBalanced: true hugeParam: - # size in bytes that makes the warning trigger (default 80) - sizeThreshold: 80 + # Size in bytes that makes the warning trigger. + # Default: 80 + sizeThreshold: 512 + ifElseChain: + # Min number of if-else blocks that makes the warning trigger. + # Default: 2 + minThreshold: 2 nestingReduce: - # min number of statements inside a branch to trigger a warning (default 5) + # Min number of statements inside a branch to trigger a warning. + # Default: 5 bodyWidth: 5 rangeExprCopy: - # size in bytes that makes the warning trigger (default 512) + # Size in bytes that makes the warning trigger. + # Default: 512 sizeThreshold: 512 - # whether to check test functions (default true) + # Whether to check test functions + # Default: true skipTestFuncs: true rangeValCopy: - # size in bytes that makes the warning trigger (default 128) + # Size in bytes that makes the warning trigger. + # Default: 128 sizeThreshold: 128 - # whether to check test functions (default true) + # Whether to check test functions. + # Default: true skipTestFuncs: true ruleguard: - # path to a gorules file for the ruleguard checker - rules: '' + # Enable debug to identify which 'Where' condition was rejected. + # The value of the parameter is the name of a function in a ruleguard file. + # + # When a rule is evaluated: + # If: + # The Match() clause is accepted; and + # One of the conditions in the Where() clause is rejected, + # Then: + # ruleguard prints the specific Where() condition that was rejected. + # + # The option is passed to the ruleguard 'debug-group' argument. + # Default: "" + debug: "" + # Determines the behavior when an error occurs while parsing ruleguard files. + # If flag is not set, log error and skip rule files that contain an error. + # If flag is set, the value must be a comma-separated list of error conditions. + # - 'all': fail on all errors. + # - 'import': ruleguard rule imports a package that cannot be found. + # - 'dsl': gorule file does not comply with the ruleguard DSL. + # Default: "" + failOn: dsl,import + # Comma-separated list of file paths containing ruleguard rules. + # If a path is relative, it is relative to the directory where the golangci-lint command is executed. + # The special '${configDir}' variable is substituted with the absolute directory containing the golangci config file. + # Glob patterns such as 'rules-*.go' may be specified. + # Default: "" + rules: "" + # Comma-separated list of enabled groups or skip empty to enable everything. + # Tags can be defined with # character prefix. + # Default: "" + enable: "" + # Comma-separated list of disabled groups or skip empty to enable everything. + # Tags can be defined with # character prefix. + # Default: "" + disable: "" + tooManyResultsChecker: + # Maximum number of results. + # Default: 5 + maxResults: 10 truncateCmp: - # whether to skip int/uint/uintptr types (default true) + # Whether to skip int/uint/uintptr types. + # Default: true skipArchDependent: true underef: - # whether to skip (*x).method() calls where x is a pointer receiver (default true) + # Whether to skip (*x).method() calls where x is a pointer receiver. + # Default: true skipRecvDeref: true - unnamedResult: - # whether to check exported functions - # checkExported: true + unnamedResult: + # Whether to check exported functions. + # Default: false + checkExported: true + gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) + # Minimal code complexity to report. + # Default: 30 (but we recommend 10-20) min-complexity: 15 - cyclop: - # the maximal code complexity to report - max-complexity: 15 - # the maximal average package complexity. If it's higher than 0.0 (float) the check is enabled (default 0.0) - package-average: 0.0 - # should ignore tests (default false) - skip-tests: false godot: - # comments to be checked: `declarations`, `toplevel`, or `all` + # Comments to be checked: `declarations`, `toplevel`, or `all`. + # Default: declarations scope: declarations - # list of regexps for excluding particular comment lines from check - exclude: - # example: exclude comments which contain numbers - # - '[0-9]+' - # check that each sentence starts with a capital letter - capital: false + # List of regexps for excluding particular comment lines from check. + # Default: [] + exclude: [] + # # Exclude todo and fixme comments. + # - "^fixme:" + # - "^todo:" + # Check that each sentence ends with a period. + # Default: true + period: true + # Check that each sentence starts with a capital letter. + # Default: false + capital: true + godox: - # report any comments starting with keywords, this is useful for TODO or FIXME comments that - # might be left in the code accidentally and should be resolved before merging - keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting + # Report any comments starting with keywords, this is useful for TODO or FIXME comments that + # might be left in the code accidentally and should be resolved before merging. + # Default: ["TODO", "BUG", "FIXME"] + keywords: - NOTE - OPTIMIZE # marks code that should be optimized before merging - - HACK # marks hack-arounds that should be removed before merging + - HACK # marks hack-around that should be removed before merging + gofmt: - # simplify code: gofmt with `-s` option, true by default + # Simplify code: gofmt with `-s` option. + # Default: true simplify: true + # Apply the rewrite rules to the source before reformatting. + # https://pkg.go.dev/cmd/gofmt + # Default: [] + rewrite-rules: + - pattern: 'interface{}' + replacement: 'any' + - pattern: 'a[b:len(a)]' + replacement: 'a[b:]' + + gofumpt: + # Module path which contains the source code being formatted. + # Default: "" + module-path: "" + + # Choose whether to use the extra rules. + # Default: false + extra-rules: false + goheader: + # Supports two types 'const` and `regexp`. + # Values can be used recursively. + # Default: {} values: const: - # define here const type values in format k:v, for example: - # COMPANY: MY COMPANY - regexp: - # define here regexp type values, for example - # AUTHOR: .*@mycompany\.com - template: # | - # put here copyright header template for source code files, for example: - # Note: {{ YEAR }} is a builtin value that returns the year relative to the current machine time. + NONE: "" + regexp: {} + # The template use for checking. + # Default: "" + #template: | # - # {{ AUTHOR }} {{ COMPANY }} {{ YEAR }} - # SPDX-License-Identifier: Apache-2.0 - - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at: - - # http://www.apache.org/licenses/LICENSE-2.0 - - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - template-path: - # also as alternative of directive 'template' you may put the path to file with the template source + # As alternative of directive 'template', you may put the path to file with the template source. + # Useful if you need to load the template from a specific file. + # Default: "" + template-path: "" + goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes - # local-prefixes: github.com/org/project - golint: - # minimal confidence for issues, default is 0.8 - min-confidence: 0.8 - gomnd: - settings: - mnd: - # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. - checks: argument,case,condition,operation,return,assign - # ignored-numbers: 1000 - # ignored-files: magic_.*.go - # ignored-functions: math.* + # A comma-separated list of prefixes, which, if set, checks import paths + # with the given prefixes are grouped after 3rd-party packages. + # Default: "" + local-prefixes: "" + + gomoddirectives: + # Allow local `replace` directives. + # Default: false + replace-local: false + # List of allowed `replace` directives. + # Default: [] + replace-allow-list: [] + # - launchpad.net/gocheck + # Allow to not explain why the version has been retracted in the `retract` directives. + # Default: false + retract-allow-no-explanation: false + # Forbid the use of the `exclude` directives. + # Default: false + exclude-forbidden: false + gomodguard: allowed: - modules: # List of allowed modules - # - gopkg.in/yaml.v2 - domains: # List of allowed module domains - # - golang.org + # List of allowed modules. + # Default: [] + modules: + - "go.uber.org/zap" + - "go.uber.org/zap/zapcore" + - "github.com/gofrs/uuid" + - "github.com/nats-io/stan.go" + - "github.com/nats-io/nats.go" + # List of allowed module domains. + # Default: [] + domains: + - golang.org blocked: - modules: # List of blocked modules - # - github.com/uudashr/go-module: # Blocked module - # recommendations: # Recommended modules that should be used instead (Optional) - # - golang.org/x/mod - # reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional) - versions: # List of blocked module version constraints - # - github.com/mitchellh/go-homedir: # Blocked module with version constraint - # version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons - # reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional) - local_replace_directives: false # Set to true to raise lint issues for packages that are loaded from a local path via replace directive + # List of blocked modules. + # Default: [] + modules: + # Blocked module. + - github.com/uudashr/go-module: + # Recommended modules that should be used instead. (Optional) + recommendations: + - golang.org/x/mod + # Reason why the recommended module should be used. (Optional) + reason: "`mod` is the official go.mod parser library." + # List of blocked module version constraints. + # Default: [] + versions: + # Blocked module with version constraint. + - github.com/mitchellh/go-homedir: + # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons. + version: "< 1.1.0" + # Reason why the version constraint exists. (Optional) + reason: "testing if blocked version constraint works." + # Set to true to raise lint issues for packages that are loaded from a local path via replace directive. + # Default: false + local_replace_directives: false + + gosimple: + # Sxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: [ "all" ] + + gosec: + # To select a subset of rules to run. + # Available rules: https://github.com/securego/gosec#available-rules + # Default: [] - means include all rules + includes: + - G101 # Look for hard coded credentials + - G102 # Bind to all interfaces + - G103 # Audit the use of unsafe block + - G104 # Audit errors not checked + - G106 # Audit the use of ssh.InsecureIgnoreHostKey + - G107 # Url provided to HTTP request as taint input + - G108 # Profiling endpoint automatically exposed on /debug/pprof + - G109 # Potential Integer overflow made by strconv.Atoi result conversion to int16/32 + - G110 # Potential DoS vulnerability via decompression bomb + - G111 # Potential directory traversal + - G112 # Potential slowloris attack + - G113 # Usage of Rat.SetString in math/big with an overflow (CVE-2022-23772) + - G114 # Use of net/http serve function that has no support for setting timeouts + - G201 # SQL query construction using format string + - G202 # SQL query construction using string concatenation + - G203 # Use of unescaped data in HTML templates + - G204 # Audit use of command execution + - G301 # Poor file permissions used when creating a directory + - G302 # Poor file permissions used with chmod + - G303 # Creating tempfile using a predictable path + - G304 # File path provided as taint input + - G305 # File traversal when extracting zip/tar archive + - G306 # Poor file permissions used when writing to a new file + - G307 # Poor file permissions used when creating a file with os.Create + - G401 # Detect the usage of DES, RC4, MD5 or SHA1 + - G402 # Look for bad TLS connection settings + - G403 # Ensure minimum RSA key length of 2048 bits + - G404 # Insecure random number source (rand) + - G501 # Import blocklist: crypto/md5 + - G502 # Import blocklist: crypto/des + - G503 # Import blocklist: crypto/rc4 + - G504 # Import blocklist: net/http/cgi + - G505 # Import blocklist: crypto/sha1 + - G601 # Implicit memory aliasing of items from a range statement + - G602 # Slice access out of bounds + + # To specify a set of rules to explicitly exclude. + # Available rules: https://github.com/securego/gosec#available-rules + # Default: [] + excludes: [] + # - G101 # Look for hard coded credentials + # - G102 # Bind to all interfaces + # - G103 # Audit the use of unsafe block + # - G104 # Audit errors not checked + # - G106 # Audit the use of ssh.InsecureIgnoreHostKey + # - G107 # Url provided to HTTP request as taint input + # - G108 # Profiling endpoint automatically exposed on /debug/pprof + # - G109 # Potential Integer overflow made by strconv.Atoi result conversion to int16/32 + # - G110 # Potential DoS vulnerability via decompression bomb + # - G111 # Potential directory traversal + # - G112 # Potential slowloris attack + # - G113 # Usage of Rat.SetString in math/big with an overflow (CVE-2022-23772) + # - G114 # Use of net/http serve function that has no support for setting timeouts + # - G201 # SQL query construction using format string + # - G202 # SQL query construction using string concatenation + # - G203 # Use of unescaped data in HTML templates + # - G204 # Audit use of command execution + # - G301 # Poor file permissions used when creating a directory + # - G302 # Poor file permissions used with chmod + # - G303 # Creating tempfile using a predictable path + # - G304 # File path provided as taint input + # - G305 # File traversal when extracting zip/tar archive + # - G306 # Poor file permissions used when writing to a new file + # - G307 # Poor file permissions used when creating a file with os.Create + # - G401 # Detect the usage of DES, RC4, MD5 or SHA1 + # - G402 # Look for bad TLS connection settings + # - G403 # Ensure minimum RSA key length of 2048 bits + # - G404 # Insecure random number source (rand) + # - G501 # Import blocklist: crypto/md5 + # - G502 # Import blocklist: crypto/des + # - G503 # Import blocklist: crypto/rc4 + # - G504 # Import blocklist: net/http/cgi + # - G505 # Import blocklist: crypto/sha1 + # - G601 # Implicit memory aliasing of items from a range statement + # - G602 # Slice access out of bounds + + # Exclude generated files + # Default: false + exclude-generated: true + + # Filter out the issues with a lower severity than the given value. + # Valid options are: low, medium, high. + # Default: low + severity: medium + + # Filter out the issues with a lower confidence than the given value. + # Valid options are: low, medium, high. + # Default: low + confidence: medium + + # Concurrency value. + # Default: the number of logical CPUs usable by the current process. + concurrency: 12 + + # To specify the configuration of rules. + config: + # Globals are applicable to all rules. + global: + # If true, ignore #nosec in comments (and an alternative as well). + # Default: false + nosec: true + # Add an alternative comment prefix to #nosec (both will work at the same time). + # Default: "" + "#nosec": "#my-custom-nosec" + # Define whether nosec issues are counted as finding or not. + # Default: false + show-ignored: true + # Audit mode enables addition checks that for normal code analysis might be too nosy. + # Default: false + audit: true + G101: + # Regexp pattern for variables and constants to find. + # Default: "(?i)passwd|pass|password|pwd|secret|token|pw|apiKey|bearer|cred" + pattern: "(?i)example" + # If true, complain about all cases (even with low entropy). + # Default: false + ignore_entropy: false + # Maximum allowed entropy of the string. + # Default: "80.0" + entropy_threshold: "80.0" + # Maximum allowed value of entropy/string length. + # Is taken into account if entropy >= entropy_threshold/2. + # Default: "3.0" + per_char_threshold: "3.0" + # Calculate entropy for first N chars of the string. + # Default: "16" + truncate: "32" + # Additional functions to ignore while checking unhandled errors. + # Following functions always ignored: + # bytes.Buffer: + # - Write + # - WriteByte + # - WriteRune + # - WriteString + # fmt: + # - Print + # - Printf + # - Println + # - Fprint + # - Fprintf + # - Fprintln + # strings.Builder: + # - Write + # - WriteByte + # - WriteRune + # - WriteString + # io.PipeWriter: + # - CloseWithError + # hash.Hash: + # - Write + # os: + # - Unsetenv + # Default: {} + G104: + fmt: + - Fscanf + G111: + # Regexp pattern to find potential directory traversal. + # Default: "http\\.Dir\\(\"\\/\"\\)|http\\.Dir\\('\\/'\\)" + pattern: "custom\\.Dir\\(\\)" + # Maximum allowed permissions mode for os.Mkdir and os.MkdirAll + # Default: "0750" + G301: "0750" + # Maximum allowed permissions mode for os.OpenFile and os.Chmod + # Default: "0600" + G302: "0600" + # Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile + # Default: "0600" + G306: "0600" + + gosmopolitan: + # Allow and ignore `time.Local` usages. + # + # Default: false + allow-time-local: true + # List of fully qualified names in the `full/pkg/path.name` form, to act as "i18n escape hatches". + # String literals inside call-like expressions to, or struct literals of those names, + # are exempt from the writing system check. + # + # Default: [] + escape-hatches: + - 'github.com/nicksnyder/go-i18n/v2/i18n.Message' + - 'example.com/your/project/i18n/markers.Raw' + - 'example.com/your/project/i18n/markers.OK' + - 'example.com/your/project/i18n/markers.TODO' + - 'command-line-arguments.Simple' + # Ignore test files. + # + # Default: true + ignore-tests: false + # List of Unicode scripts to watch for any usage in string literals. + # https://pkg.go.dev/unicode#pkg-variables + # + # Default: ["Han"] + watch-for-scripts: + - Devanagari + - Han + - Hangul + - Hiragana + - Katakana + govet: - # report about shadowed variables - check-shadowing: false + # Disable all analyzers. + # Default: false + disable-all: false + # Enable analyzers by name. + # (in addition to default: + # appends, asmdecl, assign, atomic, bools, buildtag, cgocall, composites, copylocks, defers, directive, errorsas, + # framepointer, httpresponse, ifaceassert, loopclosure, lostcancel, nilfunc, printf, shift, sigchanyzer, slog, + # stdmethods, stringintconv, structtag, testinggoroutine, tests, timeformat, unmarshal, unreachable, unsafeptr, + # unusedresult + # ). + # Run `GL_DEBUG=govet golangci-lint run --enable=govet` to see default, all available analyzers, and enabled analyzers. + # Default: [] + enable: [] + # - appends + # - asmdecl + # - assign + # - atomic + # - atomicalign + # - bools + # - buildtag + # - cgocall + # - composites + # - copylocks + # - deepequalerrors + # - defers + # - directive + # - errorsas + # - fieldalignment + # - findcall + # - framepointer + # - httpresponse + # - ifaceassert + # - loopclosure + # - lostcancel + # - nilfunc + # - nilness + # - printf + # - reflectvaluecompare + # - shadow + # - shift + # - sigchanyzer + # - slog + # - sortslice + # - stdmethods + # - stringintconv + # - structtag + # - testinggoroutine + # - tests + # - unmarshal + # - unreachable + # - unsafeptr + # - unusedresult + # - unusedwrite + + # Enable all analyzers. + # Default: false + enable-all: true + # Disable analyzers by name. + # (in addition to default + # atomicalign, deepequalerrors, fieldalignment, findcall, nilness, reflectvaluecompare, shadow, sortslice, + # timeformat, unusedwrite + # ). + # Run `GL_DEBUG=govet golangci-lint run --enable=govet` to see default, all available analyzers, and enabled analyzers. + # Default: [] + disable: + # - appends + # - asmdecl + # - assign + # - atomic + # - atomicalign + # - bools + # - buildtag + # - cgocall + # - composites + # - copylocks + # - deepequalerrors + # - defers + # - directive + # - errorsas + - fieldalignment + # - findcall + # - framepointer + # - httpresponse + # - ifaceassert + # - loopclosure + # - lostcancel + # - nilfunc + # - nilness + # - printf + # - reflectvaluecompare + # - shadow + # - shift + # - sigchanyzer + # - slog + # - sortslice + # - stdmethods + # - stringintconv + # - structtag + # - testinggoroutine + # - tests + # - unmarshal + # - unreachable + # - unsafeptr + # - unusedresult + # - unusedwrite - # settings per analyzer + # Settings per analyzer. settings: - printf: # analyzer name, run `go tool vet help` to see all analyzers - funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer + # Analyzer name, run `go tool vet help` to see all analyzers. + printf: + # Comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`). + # Default: [] + funcs: - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + shadow: + # Whether to be strict about shadowing; can be noisy. + # Default: false + strict: true + unusedresult: + # Comma-separated list of functions whose results must be used + # (in addition to default: + # context.WithCancel, context.WithDeadline, context.WithTimeout, context.WithValue, errors.New, fmt.Errorf, + # fmt.Sprint, fmt.Sprintf, sort.Reverse + # ). + # Default: [] + funcs: [] + # Comma-separated list of names of methods of type func() string whose results must be used + # (in addition to default Error,String) + # Default: [] + stringmethods: [] + + grouper: + # Require the use of a single global 'const' declaration only. + # Default: false + const-require-single-const: false + # Require the use of grouped global 'const' declarations. + # Default: false + const-require-grouping: false + + # Require the use of a single 'import' declaration only. + # Default: false + import-require-single-import: false + # Require the use of grouped 'import' declarations. + # Default: false + import-require-grouping: false + + # Require the use of a single global 'type' declaration only. + # Default: false + type-require-single-type: false + # Require the use of grouped global 'type' declarations. + # Default: false + type-require-grouping: false + + # Require the use of a single global 'var' declaration only. + # Default: false + var-require-single-var: false + # Require the use of grouped global 'var' declarations. + # Default: false + var-require-grouping: false + + importas: + # Do not allow unaliased imports of aliased packages. + # Default: false + no-unaliased: false + # Do not allow non-required aliases. + # Default: false + no-extra-aliases: false + # List of aliases + # Default: [] + alias: [] + # # Using `servingv1` alias for `knative.dev/serving/pkg/apis/serving/v1` package. + # - pkg: knative.dev/serving/pkg/apis/serving/v1 + # alias: servingv1 + # # Using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package. + # - pkg: knative.dev/serving/pkg/apis/autoscaling/v1alpha1 + # alias: autoscalingv1alpha1 + # # You can specify the package path by regular expression, + # # and alias by regular expression expansion syntax like below. + # # see https://github.com/julz/importas#use-regular-expression for details + # - pkg: knative.dev/serving/pkg/apis/(\w+)/(v[\w\d]+) + # alias: $1$2 + + inamedparam: + # Skips check for interface methods with only a single parameter. + # Default: false + skip-single-param: true + + interfacebloat: + # The maximum number of methods allowed for an interface. + # Default: 10 + max: 20 + + ireturn: + # ireturn does not allow using `allow` and `reject` settings at the same time. + # Both settings are lists of the keywords and regular expressions matched to interface or package names. + # keywords: + # - `empty` for `interface{}` + # - `error` for errors + # - `stdlib` for standard library + # - `anon` for anonymous interfaces + # - `generic` for generic interfaces added in go 1.18 + + # By default, it allows using errors, empty interfaces, anonymous interfaces, + # and interfaces provided by the standard library. + allow: + - anon + - error + - empty + - stdlib + - Option + - Engine + - github.com/ClickHouse/clickhouse-go/v2/lib/driver.Batch + # You can specify idiomatic endings for interface + - (or|er|I)$ + + # reject-list of interfaces + reject: [] + # - github.com\/user\/package\/v4\.Type - # enable or disable analyzers by name - # run `go tool vet help` to see all analyzers - enable: - - atomicalign - enable-all: false - disable: - - shadow - disable-all: false - depguard: - list-type: blacklist - include-go-root: false - packages: - - github.com/sirupsen/logrus - packages-with-error-message: - # specify an error message to output when a blacklisted package is used - - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log" - ifshort: - # Maximum length of variable declaration measured in number of lines, after which linter won't suggest using short syntax. - # Has higher priority than max-decl-chars. - max-decl-lines: 1 - # Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax. - max-decl-chars: 30 lll: - # max line length, lines longer will be reported. Default is 120. - # '\t' is counted as 1 character by default, and can be changed with the tab-width option + # Max line length, lines longer will be reported. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option. + # Default: 120. line-length: 120 - # tab width in spaces. Default to 1. + # Tab width in spaces. + # Default: 1 tab-width: 1 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true + + loggercheck: + # Allow check for the github.com/go-kit/log library. + # Default: true + kitlog: false + # Allow check for the k8s.io/klog/v2 library. + # Default: true + klog: false + # Allow check for the github.com/go-logr/logr library. + # Default: true + logr: false + # Allow check for the "sugar logger" from go.uber.org/zap library. + # Default: true + zap: true + # Require all logging keys to be inlined constant strings. + # Default: false + require-string-key: true + # Require printf-like format specifier (%s, %d for example) not present. + # Default: false + no-printf-like: true + # List of custom rules to check against, where each rule is a single logger pattern, useful for wrapped loggers. + # For example: https://github.com/timonwong/loggercheck/blob/7395ab86595781e33f7afba27ad7b55e6956ebcd/testdata/custom-rules.txt + # Default: empty + rules: + - k8s.io/klog/v2.InfoS # package level exported functions + - (github.com/go-logr/logr.Logger).Error # "Methods" + - (*go.uber.org/zap.SugaredLogger).With # Also "Methods", but with a pointer receiver + + maintidx: + # Show functions with maintainability index lower than N. + # A high index indicates better maintainability (it's kind of the opposite of complexity). + # Default: 20 + under: 40 + + makezero: + # Allow only slices initialized with a length of zero. + # Default: false + always: true + misspell: # Correct spellings using locale preferences for US or UK. - # Default is to use a neutral variety of English. # Setting locale to US will correct the British spelling of 'colour' to 'color'. + # Default is to use a neutral variety of English. locale: US + # Typos to ignore. + # Should be in lower case. + # Default: [] ignore-words: - someword + # Extra word corrections. + # `typo` and `correction` should only contain letters. + # The words are case-insensitive. + # Default: [] + extra-words: + - typo: "iff" + correction: "if" + - typo: "cancelation" + correction: "cancellation" + # Mode of the analysis: + # - default: checks all the file content. + # - restricted: checks only comments. + # Default: "" + mode: restricted + + mnd: + # List of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. + # Default: ["argument", "case", "condition", "operation", "return", "assign"] + checks: + - argument + - case + - condition + - operation + - return + - assign + # List of numbers to exclude from analysis. + # The numbers should be written as string. + # Values always ignored: "1", "1.0", "0" and "0.0" + # Default: [] + ignored-numbers: + - '0666' + - '0755' + - '42' + # List of file patterns to exclude from analysis. + # Values always ignored: `.+_test.go` + # Default: [] + ignored-files: + - 'magic1_.+\.go$' + # List of function patterns to exclude from analysis. + # Following functions are always ignored: `time.Date`, + # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, + # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. + # Default: [] + ignored-functions: + - '^math\.' + - '^http\.StatusText$' + + musttag: + # A set of custom functions to check in addition to the builtin ones. + # Default: json, xml, gopkg.in/yaml.v3, BurntSushi/toml, mitchellh/mapstructure, jmoiron/sqlx + functions: + # The full name of the function, including the package. + - name: github.com/hashicorp/hcl/v2/hclsimple.DecodeFile + # The struct tag whose presence should be ensured. + tag: hcl + # The position of the argument to check. + arg-pos: 2 + nakedret: - # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 - max-func-lines: 30 + # Make an issue if func has more lines of code than this setting, and it has naked returns. + # Default: 30 + max-func-lines: 60 + + nestif: + # Minimal complexity of if statements to report. + # Default: 5 + min-complexity: 4 + + nilnil: + # List of return types to check. + # Default: ["ptr", "func", "iface", "map", "chan", "uintptr", "unsafeptr"] + checked-types: + - ptr + - func + - iface + - map + - chan + - uintptr + - unsafeptr + + nlreturn: + # Size of the block (including return statement that is still "OK") + # so no return split required. + # Default: 1 + block-size: 1 + + nolintlint: + # Disable to ensure that all nolint directives actually have an effect. + # Default: false + allow-unused: false + # Exclude following linters from requiring an explanation. + # Default: [] + allow-no-explanation: [ ] + # Enable to require an explanation of nonzero length after each nolint directive. + # Default: false + require-explanation: false + # Enable to require nolint directives to mention the specific linter being suppressed. + # Default: false + require-specific: false + + nonamedreturns: + # Report named error if it is assigned inside defer. + # Default: false + report-error-in-defer: false + + paralleltest: + # Ignore missing calls to `t.Parallel()` and only report incorrect uses of it. + # Default: false + ignore-missing: true + # Ignore missing calls to `t.Parallel()` in subtests. Top-level tests are + # still required to have `t.Parallel`, but subtests are allowed to skip it. + # Default: false + ignore-missing-subtests: true + + perfsprint: + # Optimizes even if it requires an int or uint type cast. + # Default: true + int-conversion: false + # Optimizes into `err.Error()` even if it is only equivalent for non-nil errors. + # Default: false + err-error: true + # Optimizes `fmt.Errorf`. + # Default: true + errorf: false + # Optimizes `fmt.Sprintf` with only one argument. + # Default: true + sprintf1: false + # Optimizes into strings concatenation. + # Default: true + strconcat: false + prealloc: - # XXX: we don't recommend using this linter before doing performance profiling. + # IMPORTANT: we don't recommend using this linter before doing performance profiling. # For most programs usage of prealloc will be a premature optimization. - # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. - # True by default. - simple: true - range-loops: true # Report preallocation suggestions on range loops, true by default - for-loops: false # Report preallocation suggestions on for loops, false by default + # Report pre-allocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. + # Default: true + simple: false + # Report pre-allocation suggestions on range loops. + # Default: true + range-loops: false + # Report pre-allocation suggestions on for loops. + # Default: false + for-loops: true + predeclared: - # comma-separated list of predeclared identifiers to not report on - ignore: "" - # include method names and field names (i.e., qualified names) in checks - q: false - nolintlint: - # Enable to ensure that nolint directives are all used. Default is true. - allow-unused: false - # Disable to ensure that nolint directives don't have a leading space. Default is true. - allow-leading-space: true - # Exclude following linters from requiring an explanation. Default is []. - allow-no-explanation: [] - # Enable to require an explanation of nonzero length after each nolint directive. Default is false. - require-explanation: true - # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. - require-specific: true - rowserrcheck: - packages: - - github.com/jmoiron/sqlx + # Comma-separated list of predeclared identifiers to not report on. + # Default: "" + ignore: "new,int" + # Include method names and field names (i.e., qualified names) in checks. + # Default: false + q: true + + promlinter: + # Promlinter cannot infer all metrics name in static analysis. + # Enable strict mode will also include the errors caused by failing to parse the args. + # Default: false + strict: true + # Please refer to https://github.com/yeya24/promlinter#usage for detailed usage. + # Default: [] + disabled-linters: + - Help + - MetricUnits + - Counter + - HistogramSummaryReserved + - MetricTypeInName + - ReservedChars + - CamelCase + - UnitAbbreviations + + protogetter: + # Skip files generated by specified generators from the checking. + # Checks only the file's initial comment, which must follow the format: "// Code generated by ". + # Files generated by protoc-gen-go, protoc-gen-go-grpc, and protoc-gen-grpc-gateway are always excluded automatically. + # Default: [] + skip-generated-by: ["protoc-gen-go-my-own-generator"] + # Skip files matching the specified glob pattern from the checking. + # Default: [] + skip-files: + - "*.pb.go" + - "*/vendor/*" + - "/full/path/to/file.go" + # Skip any generated files from the checking. + # Default: false + skip-any-generated: true + # Skip first argument of append function. + # Default: false + replace-first-arg-in-append: true + + reassign: + # Patterns for global variable names that are checked for reassignment. + # See https://github.com/curioswitch/go-reassign#usage + # Default: ["EOF", "Err.*"] + patterns: + - ".*" + revive: - # see https://github.com/mgechev/revive#available-rules for details. + # Maximum number of open files at the same time. + # See https://github.com/mgechev/revive#command-line-flags + # Defaults to unlimited. + max-open-files: 2048 + + # When set to false, ignores files with "GENERATED" header, similar to golint. + # See https://github.com/mgechev/revive#available-rules for details. + # Default: false ignore-generated-header: true - severity: warning + + # Sets the default severity. + # See https://github.com/mgechev/revive#configuration + # Default: warning + severity: error + + # Enable all available rules. + # Default: false + enable-all-rules: true + + # Sets the default failure confidence. + # This means that linting errors with less than 0.8 confidence will be ignored. + # Default: 0.8 + confidence: 0.1 + rules: + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#add-constant + - name: add-constant + severity: warning + disabled: false + exclude: [""] + arguments: + - maxLitCount: "3" + allowStrs: '""' + allowInts: "0,1,2" + allowFloats: "0.0,0.,1.0,1.,2.0,2." + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#argument-limit + - name: argument-limit + severity: warning + disabled: false + exclude: [""] + arguments: [ 5 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#atomic + - name: atomic + severity: warning + exclude: [""] + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#banned-characters + - name: banned-characters + severity: warning + disabled: false + exclude: [""] + arguments: [ "Ω","Σ","σ", "7" ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bare-return + - name: bare-return + severity: warning + exclude: [""] + disabled: true + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#blank-imports + - name: blank-imports + severity: warning + exclude: [""] + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bool-literal-in-expr + - name: bool-literal-in-expr + severity: warning + exclude: [""] + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#call-to-gc + - name: call-to-gc + severity: warning + exclude: [""] + disabled: false + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cognitive-complexity + - name: cognitive-complexity + severity: warning + disabled: false + exclude: [""] + arguments: [ 30 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#comment-spacings + - name: comment-spacings + severity: warning + disabled: false + exclude: [""] + arguments: + - mypragma + - otherpragma + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#confusing-naming + - name: confusing-naming + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#confusing-results + - name: confusing-results + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#constant-logical-expr + - name: constant-logical-expr + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument + - name: context-as-argument + severity: warning + disabled: false + exclude: [""] + arguments: + - allowTypesBefore: "*testing.T,*github.com/user/repo/testing.Harness" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-keys-type + - name: context-keys-type + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cyclomatic + - name: cyclomatic + severity: warning + disabled: false + exclude: [""] + arguments: [ 15 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#datarace + - name: datarace + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#deep-exit + - name: deep-exit + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#defer + - name: defer + severity: warning + disabled: false + exclude: [""] + arguments: + - [ "call-chain", "loop" ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#dot-imports + - name: dot-imports + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#duplicated-imports + - name: duplicated-imports + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#early-return + - name: early-return + severity: warning + disabled: false + exclude: [""] + arguments: [] + # - "preserveScope" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block + - name: empty-block + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines + - name: empty-lines + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#enforce-map-style + - name: enforce-map-style + severity: warning + disabled: false + exclude: [""] + arguments: + - "make" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#enforce-repeated-arg-type-style + - name: enforce-repeated-arg-type-style + severity: warning + disabled: false + exclude: [""] + arguments: + - "any" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#enforce-slice-style + - name: enforce-slice-style + severity: warning + disabled: false + exclude: [""] + arguments: + - "make" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-naming + - name: error-naming + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-return + - name: error-return + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-strings + - name: error-strings + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#errorf + - name: errorf + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported + - name: exported + severity: warning + disabled: true + exclude: [""] + arguments: + # - "preserveScope" + - "checkPrivateReceivers" + - "sayRepetitiveInsteadOfStutters" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#file-header + - name: file-header + severity: warning + disabled: true + exclude: [""] + arguments: + - This is the text that must appear at the top of source files. + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#flag-parameter + - name: flag-parameter + severity: warning + disabled: true + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-result-limit + - name: function-result-limit + severity: warning + disabled: false + exclude: [""] + arguments: [ 2 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-length + - name: function-length + severity: warning + disabled: false + exclude: [""] + arguments: [ 40, 0 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#get-return + - name: get-return + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#identical-branches + - name: identical-branches + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#if-return + - name: if-return + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#increment-decrement + - name: increment-decrement + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#indent-error-flow - name: indent-error-flow severity: warning + disabled: false + exclude: [""] + arguments: [] + # - "preserveScope" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-alias-naming + - name: import-alias-naming + severity: warning + disabled: false + exclude: [""] + arguments: + - "^[a-z][a-zA-Z0-9]*$" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#imports-blocklist + - name: imports-blocklist + severity: warning + disabled: false + exclude: [""] + arguments: + - "crypto/md5" + - "crypto/sha1" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing + - name: import-shadowing + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#line-length-limit + - name: line-length-limit + severity: warning + disabled: false + exclude: [""] + arguments: [ 150 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#max-control-nesting + - name: max-control-nesting + severity: warning + disabled: false + exclude: [""] + arguments: [ 3 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#max-public-structs + - name: max-public-structs + severity: warning + disabled: false + exclude: [""] + arguments: [ 5 ] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#modifies-parameter + - name: modifies-parameter + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#modifies-value-receiver + - name: modifies-value-receiver + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#nested-structs + - name: nested-structs + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#optimize-operands-order + - name: optimize-operands-order + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#package-comments + - name: package-comments + severity: warning + disabled: true + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range + - name: range + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-in-closure + - name: range-val-in-closure + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-address + - name: range-val-address + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#receiver-naming + - name: receiver-naming + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redundant-import-alias + - name: redundant-import-alias + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redefines-builtin-id + - name: redefines-builtin-id + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-of-int + - name: string-of-int + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-format + - name: string-format + severity: warning + disabled: false + exclude: [""] + arguments: + - - 'core.WriteError[1].Message' + - '/^([^A-Z]|$)/' + - must not start with a capital letter + - - 'fmt.Errorf[0]' + - '/(^|[^\.!?])$/' + - must not end in punctuation + - - panic + - '/^[^\n]*$/' + - must not contain line breaks + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#struct-tag + - name: struct-tag + arguments: + - "json,inline" + - "bson,outline,gnu" + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#superfluous-else + - name: superfluous-else + severity: warning + disabled: false + exclude: [""] + arguments: [] + # - "preserveScope" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-equal + - name: time-equal + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-naming + - name: time-naming + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-naming + - name: var-naming + severity: warning + disabled: false + exclude: [""] + arguments: + - [ "ID" ] # AllowList + - [ "VM" ] # DenyList + - - upperCaseConst: true + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-declaration + - name: var-declaration + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unconditional-recursion + - name: unconditional-recursion + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-naming + - name: unexported-naming + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return + - name: unexported-return + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unhandled-error + - name: unhandled-error + severity: warning + disabled: false + exclude: [""] + arguments: + - "fmt.Printf" + - "fmt.Println" + - "fmt.Print" + - "strings.Builder.WriteRune" + - "strings.Builder.WriteByte" + - "strings.Builder.WriteString" + - "strings.Builder.Write" + - "myFunction" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unnecessary-stmt + - name: unnecessary-stmt + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unreachable-code + - name: unreachable-code + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter + - name: unused-parameter + severity: warning + disabled: false + exclude: [""] + arguments: + - allowRegex: "^_" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver + - name: unused-receiver + severity: warning + disabled: false + exclude: [""] + arguments: + - allowRegex: "^_" + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#useless-break + - name: useless-break + severity: warning + disabled: false + exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#waitgroup-by-value + - name: waitgroup-by-value + severity: warning + disabled: false + exclude: [""] + + rowserrcheck: + # database/sql is always checked + # Default: [] + packages: + - github.com/jmoiron/sqlx + + sloglint: + # Enforce not mixing key-value pairs and attributes. + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-mixed-arguments + # Default: true + no-mixed-args: false + # Enforce using key-value pairs only (overrides no-mixed-args, incompatible with attr-only). + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-value-pairs-only + # Default: false + kv-only: false + # Enforce using attributes only (overrides no-mixed-args, incompatible with kv-only). + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#attributes-only + # Default: false + attr-only: false + # Enforce not using global loggers. + # Values: + # - "": disabled + # - "all": report all global loggers + # - "default": report only the default slog logger + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global + # Default: "" + no-global: "all" + # Enforce using methods that accept a context. + # Values: + # - "": disabled + # - "all": report all contextless calls + # - "scope": report only if a context exists in the scope of the outermost function + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only + # Default: "" + context: "all" + # Enforce using static values for log messages. + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages + # Default: false + static-msg: true + # Enforce using constants instead of raw keys. + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-raw-keys + # Default: false + no-raw-keys: false + # Enforce a single key naming convention. + # Values: snake, kebab, camel, pascal + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention + # Default: "" + key-naming-case: snake + # Enforce not using specific keys. + # Default: [] + forbidden-keys: + - time + - level + - msg + - source + - foo + # Enforce putting arguments on separate lines. + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#forbidden-keys + # Default: false + args-on-sep-lines: true + + spancheck: + # Checks to enable. + # Options include: + # - `end`: check that `span.End()` is called + # - `record-error`: check that `span.RecordError(err)` is called when an error is returned + # - `set-status`: check that `span.SetStatus(codes.Error, msg)` is called when an error is returned + # Default: ["end"] + checks: + - end + - record-error + - set-status + # A list of regexes for function signatures that silence `record-error` and `set-status` reports + # if found in the call path to a returned error. + # https://github.com/jjti/go-spancheck#ignore-check-signatures + # Default: [] + ignore-check-signatures: + - "telemetry.RecordError" + # A list of regexes for additional function signatures that create spans. + # This is useful if you have a utility method to create spans. + # Each entry should be of the form `:`, where `telemetry-type` can be `opentelemetry` or `opencensus`. + # https://github.com/jjti/go-spancheck#extra-start-span-signatures + # Default: [] + extra-start-span-signatures: + - "github.com/user/repo/telemetry/trace.Start:opentelemetry" + staticcheck: + # SAxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: [ "all" ] + + stylecheck: + # STxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: [ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022" ] + # https://staticcheck.io/docs/configuration/options/#dot_import_whitelist + # Default: ["github.com/mmcloughlin/avo/build", "github.com/mmcloughlin/avo/operand", "github.com/mmcloughlin/avo/reg"] + dot-import-whitelist: + - fmt + # https://staticcheck.io/docs/configuration/options/#initialisms + # Default: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"] + initialisms: [ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS" ] + # https://staticcheck.io/docs/configuration/options/#http_status_code_whitelist + # Default: ["200", "400", "404", "500"] + http-status-code-whitelist: [ "200", "400", "404", "500" ] + + tagalign: + # Align and sort can be used together or separately. + # + # Whether enable align. If true, the struct tags will be aligned. + # e.g.: + # type FooBar struct { + # Bar string `json:"bar" validate:"required"` + # FooFoo int8 `json:"foo_foo" validate:"required"` + # } + # will be formatted to: + # type FooBar struct { + # Bar string `json:"bar" validate:"required"` + # FooFoo int8 `json:"foo_foo" validate:"required"` + # } + # Default: true. + align: false + # Whether enable tags sort. + # If true, the tags will be sorted by name in ascending order. + # e.g.: `xml:"bar" json:"bar" validate:"required"` -> `json:"bar" validate:"required" xml:"bar"` + # Default: true + sort: false + # Specify the order of tags, the other tags will be sorted by name. + # This option will be ignored if `sort` is false. + # Default: [] + order: + - json + - yaml + - yml + - toml + - mapstructure + - binding + - validate + # Whether enable strict style. + # In this style, the tags will be sorted and aligned in the dictionary order, + # and the tags with the same name will be aligned together. + # Note: This option will be ignored if 'align' or 'sort' is false. + # Default: false + strict: true + + tagliatelle: + # Check the struct tag name case. + case: + # Use the struct field name to check the name of the struct tag. + # Default: false + use-field-name: false + # `camel` is used for `json` and `yaml`, and `header` is used for `header` (can be overridden) + # Default: {} + rules: + # Any struct tag type can be used. + # Support string case: `camel`, `pascal`, `kebab`, `snake`, `upperSnake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`, `header` + json: snake + yaml: snake + xml: snake + toml: snake + bson: snake + avro: snake + mapstructure: kebab + env: upperSnake + envconfig: upperSnake + + tenv: + # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures. + # Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked. + # Default: false + all: false + + testifylint: + # Enable all checkers (https://github.com/Antonboom/testifylint#checkers). + # Default: false + enable-all: false + # Disable checkers by name + # (in addition to default + # suite-thelper + # ). + disable: [] + # - blank-import + # - bool-compare + # - compares + # - empty + # - error-is-as + # - error-nil + # - expected-actual + # - float-compare + # - go-require + # - len + # - negative-positive + # - nil-compare + # - require-error + # - suite-dont-use-pkg + # - suite-extra-assert-call + # - suite-thelper + # - useless-assert + + # Disable all checkers (https://github.com/Antonboom/testifylint#checkers). + # Default: false + disable-all: false + # Enable checkers by name + # (in addition to default + # blank-import, bool-compare, compares, empty, error-is-as, error-nil, expected-actual, go-require, float-compare, + # len, negative-positive, nil-compare, require-error, suite-dont-use-pkg, suite-extra-assert-call, useless-assert + # ). + enable: + - blank-import + - bool-compare + - compares + - empty + - error-is-as + - error-nil + - expected-actual + - float-compare + - go-require + - len + - negative-positive + - nil-compare + - require-error + - suite-dont-use-pkg + - suite-extra-assert-call + - suite-thelper + - useless-assert + + bool-compare: + # To ignore user defined types (over builtin bool). + # Default: false + ignore-custom-types: true + expected-actual: + # Regexp for expected variable name. + # Default: (^(exp(ected)?|want(ed)?)([A-Z]\w*)?$)|(^(\w*[a-z])?(Exp(ected)?|Want(ed)?)$) + pattern: ^expected + go-require: + # To ignore HTTP handlers (like http.HandlerFunc). + # Default: false + ignore-http-handlers: true + require-error: + # Regexp for assertions to analyze. If defined, then only matched error assertions will be reported. + # Default: "" + fn-pattern: ^(Errorf?|NoErrorf?)$ + suite-extra-assert-call: + # To require or remove extra Assert() call? + # Default: remove + mode: require + testpackage: - # regexp pattern to skip files + # Regexp pattern to skip files. + # Default: "(export|internal)_test\\.go" skip-regexp: (export|internal)_test\.go + # List of packages that don't end with _test that tests are allowed to be in. + # Default: "main" + allow-packages: + - example + - main + thelper: - # The following configurations enable all checks. It can be omitted because all checks are enabled by default. - # You can enable only required checks deleting unnecessary checks. test: + # Check *testing.T is first param (or after context.Context) of helper function. + # Default: true first: true + # Check *testing.T param has name t. + # Default: true name: true + # Check t.Helper() begins helper function. + # Default: true begin: true benchmark: + # Check *testing.B is first param (or after context.Context) of helper function. + # Default: true first: true + # Check *testing.B param has name b. + # Default: true name: true + # Check b.Helper() begins helper function. + # Default: true begin: true tb: + # Check *testing.TB is first param (or after context.Context) of helper function. + # Default: true first: true + # Check *testing.TB param has name tb. + # Default: true name: true + # Check tb.Helper() begins helper function. + # Default: true begin: true + fuzz: + # Check *testing.F is first param (or after context.Context) of helper function. + # Default: true + first: true + # Check *testing.F param has name f. + # Default: true + name: true + # Check f.Helper() begins helper function. + # Default: true + begin: true + + usestdlibvars: + # Suggest the use of http.MethodXX. + # Default: true + http-method: false + # Suggest the use of http.StatusXX. + # Default: true + http-status-code: false + # Suggest the use of time.Weekday.String(). + # Default: true + time-weekday: true + # Suggest the use of time.Month.String(). + # Default: false + time-month: true + # Suggest the use of time.Layout. + # Default: false + time-layout: true + # Suggest the use of crypto.Hash.String(). + # Default: false + crypto-hash: true + # Suggest the use of rpc.DefaultXXPath. + # Default: false + default-rpc-path: true + # Suggest the use of sql.LevelXX.String(). + # Default: false + sql-isolation-level: true + # Suggest the use of tls.SignatureScheme.String(). + # Default: false + tls-signature-scheme: true + # Suggest the use of constant.Kind.String(). + # Default: false + constant-kind: true + + unconvert: + # Remove conversions that force intermediate rounding. + # Default: false + fast-math: true + # Be more conservative (experimental). + # Default: false + safe: true + unparam: - # Inspect exported functions, default is false. Set to true if no external program/library imports your code. + # Inspect exported functions. + # + # Set to true if no external program/library imports your code. # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: # if it's called for subdir of a project it can't find external interfaces. All text editor integrations # with golangci-lint call it on a directory with the changed file. - check-exported: false + # + # Default: false + check-exported: true + unused: - # treat code as a program (not a library) and report unused exported identifiers; default is false. - # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find funcs usages. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false + # Mark all struct fields that have been written to as used. + # Default: true + field-writes-are-uses: false + # Treat IncDec statement (e.g. `i++` or `i--`) as both read and write operation instead of just write. + # Default: false + post-statements-are-reads: true + # Mark all exported identifiers as used. + # Default: true + exported-is-used: true + # Mark all exported fields as used. + # default: true + exported-fields-are-used: true + # Mark all function parameters as used. + # default: true + parameters-are-used: true + # Mark all local variables as used. + # default: true + local-variables-are-used: false + # Mark all identifiers inside generated files as used. + # Default: true + generated-is-used: false + + varnamelen: + # The longest distance, in source lines, that is being considered a "small scope". + # Variables used in at most this many lines will be ignored. + # Default: 5 + max-distance: 6 + # The minimum length of a variable's name that is considered "long". + # Variable names that are at least this long will be ignored. + # Default: 3 + min-name-length: 2 + # Check method receivers. + # Default: false + check-receiver: false + # Check named return values. + # Default: false + check-return: true + # Check type parameters. + # Default: false + check-type-param: true + # Ignore "ok" variables that hold the bool return value of a type assertion. + # Default: false + ignore-type-assert-ok: true + # Ignore "ok" variables that hold the bool return value of a map index. + # Default: false + ignore-map-index-ok: true + # Ignore "ok" variables that hold the bool return value of a channel receive. + # Default: false + ignore-chan-recv-ok: true + # Optional list of variable names that should be ignored completely. + # Default: [] + ignore-names: + - err + # Optional list of variable declarations that should be ignored completely. + # Entries must be in one of the following forms (see below for examples): + # - for variables, parameters, named return values, method receivers, or type parameters: + # ( can also be a pointer/slice/map/chan/...) + # - for constants: const + # + # Default: [] + ignore-decls: + - c echo.Context + - t testing.T + - f *foo.Bar + - e error + - i int + - const C + - T any + - m map[string]int + whitespace: - multi-if: false # Enforces newlines (or comments) after every multi-line if statement - multi-func: false # Enforces newlines (or comments) after every multi-line function signature + # Enforces newlines (or comments) after every multi-line if statement. + # Default: false + multi-if: false + # Enforces newlines (or comments) after every multi-line function signature. + # Default: false + multi-func: false + + wrapcheck: + # An array of strings that specify substrings of signatures to ignore. + # If this set, it will override the default set of ignored signatures. + # See https://github.com/tomarrell/wrapcheck#configuration for more information. + # Default: [".Errorf(", "errors.New(", "errors.Unwrap(", "errors.Join(", ".Wrap(", ".Wrapf(", ".WithMessage(", ".WithMessagef(", ".WithStack("] + ignoreSigs: + - .Errorf( + - errors.New( + - errors.Unwrap( + - errors.Join( + - .Wrap( + - .Wrapf( + - .WithMessage( + - .WithMessagef( + - .WithStack( + # An array of strings that specify regular expressions of signatures to ignore. + # Default: [] + ignoreSigRegexps: + - \.New.*Error\( + # An array of strings that specify globs of packages to ignore. + # Default: [] + ignorePackageGlobs: + - encoding/* + - github.com/pkg/* + # An array of strings that specify regular expressions of interfaces to ignore. + # Default: [] + ignoreInterfaceRegexps: + - ^(?i)c(?-i)ach(ing|e) + wsl: - # If true append is only allowed to be cuddled if appending value is - # matching variables, fields or types on line above. Default is true. + # See https://github.com/bombsimon/wsl/blob/master/doc/configuration.md for documentation of available settings. + # These are the defaults for `golangci-lint`. + + # Do strict checking when assigning from append (x = append(x, y)). If + # this is set to true - the append call must append either a variable + # assigned, called or used on the line above. strict-append: true - # Allow calls and assignments to be cuddled as long as the lines have any - # matching variables, fields or types. Default is true. + + # Allows assignments to be cuddled with variables used in calls on + # line above and calls to be cuddled with assignments of variables + # used in call on line above. allow-assign-and-call: true - # Allow assignments to be cuddled with anything. Default is false. + + # Allows assignments to be cuddled with anything. allow-assign-and-anything: true - # Allow multiline assignments to be cuddled. Default is true. + + # Allows cuddling to assignments even if they span over multiple lines. allow-multiline-assign: true - # Allow declarations (var) to be cuddled. - allow-cuddle-declarations: true - # Allow trailing comments in ending of blocks - allow-trailing-comment: false - # Force newlines in end of case at this limit (0 = never). + + # If the number of lines in a case block is equal to or lager than this + # number, the case *must* end white a newline. force-case-trailing-whitespace: 0 - # Force cuddling of err checks with err var assignment - force-err-cuddling: false - # Allow leading comments to be separated with empty liens + + # Allow blocks to end with comments. + allow-trailing-comment: false + + # Allow multiple comments in the beginning of a block separated with newline. allow-separated-leading-comment: false - gofumpt: - # Choose whether or not to use the extra rules that are disabled - # by default - extra-rules: false - errorlint: - # Report non-wrapping error creation using fmt.Errorf - errorf: true - makezero: - # Allow only slices initialized with a length of zero. Default is false. - always: false - forbidigo: - # Forbid the following identifiers - forbid: - - fmt.Errorf # consider errors.Errorf in github.com/pkg/errors - # - fmt.Print.* # too much log noise - - ginkgo\\.F.* # these are used just for local development - # Exclude godoc examples from forbidigo checks. Default is true. - exclude_godoc_examples: false - -# # The custom section can be used to define linter plugins to be loaded at runtime. See README doc -# # for more info. -# custom: -# # Each custom linter should have a unique name. + + # Allow multiple var/declaration statements to be cuddled. + allow-cuddle-declarations: false + + # A list of call idents that everything can be cuddled with. + # Defaults to calls looking like locks. + allow-cuddle-with-calls: [ "Lock", "RLock" ] + + # AllowCuddleWithRHS is a list of right hand side variables that is allowed + # to be cuddled with anything. Defaults to assignments or calls looking + # like unlocks. + allow-cuddle-with-rhs: [ "Unlock", "RUnlock" ] + + # Causes an error when an If statement that checks an error variable doesn't + # cuddle with the assignment of that variable. + force-err-cuddling: false + + # When force-err-cuddling is enabled this is a list of names + # used for error variables to check for in the conditional. + error-variable-names: [ "err" ] + + # Causes an error if a short declaration (:=) cuddles with anything other than + # another short declaration. + # This logic overrides force-err-cuddling among others. + force-short-decl-cuddling: false + + # The custom section can be used to define linter plugins to be loaded at runtime. + # See README documentation for more info. + custom: {} + # Each custom linter should have a unique name. # example: -# # The path to the plugin *.so. Can be absolute or local. Required for each custom linter +# # The plugin type. +# # It can be `goplugin` or `module`. +# # Default: goplugin +# type: module +# # The path to the plugin *.so. Can be absolute or local. +# # Required for each custom linter. # path: /path/to/example.so -# # The description of the linter. Optional, just for documentation purposes. +# # The description of the linter. +# # Optional. # description: This is an example usage of a plugin linter. -# # Intended to point to the repo location of the linter. Optional, just for documentation purposes. +# # Intended to point to the repo location of the linter. +# # Optional. # original-url: github.com/golangci/example-linter +# # Plugins settings/configuration. +# # Only work with plugin based on `linterdb.PluginConstructor`. +# # Optional. +# settings: +# foo: bar + linters: - disable-all: true + # Disable all linters. + # Default: false + disable-all: false + # Enable specific linter + # https://golangci-lint.run/usage/linters/#enabled-by-default enable: + - asasalint - asciicheck -# - depguard + - bidichk + - bodyclose + - canonicalheader + - containedctx + - contextcheck + - copyloopvar + - cyclop +# - decorder + - depguard - dogsled - dupl - - exhaustivestruct + - dupword + - durationcheck + - err113 + - errcheck + - errchkjson + - errname + - errorlint + # - execinquery #archived + - exhaustive + - exhaustruct +# - exportloopref # Deprecated + - fatcontext - forbidigo + - forcetypeassert - funlen - # - gochecknoglobals // private pkcg var not allow ... O_o strange.... + - gci + - ginkgolinter + - gocheckcompilerdirectives +# - gochecknoglobals - gochecknoinits - - goconst + - gochecksumtype + - gocognit +# - goconst - gocritic + - gocyclo - godot - godox - - goerr113 - - goheader - - golint - - gomnd + - gofmt + - gofumpt +# - goheader + - goimports + - gomoddirectives - gomodguard - goprintffuncname + - gosec - gosimple - - ifshort - # - interfacer // not really need + - gosmopolitan + - govet + - grouper + - importas + # - inamedparam # Unnamed params are used in interfaces + - ineffassign + - interfacebloat +# - intrange + - ireturn - lll + - loggercheck + - maintidx - makezero + - mirror - misspell + - mnd + - musttag + - nakedret + - nestif + - nilerr + - nilnil - nlreturn + - noctx +# - nolintlint + # - nonamedreturns # Named returns are usually required + - nosprintfhostport - paralleltest + - perfsprint + - prealloc - predeclared - - revive + - promlinter + - protogetter + - reassign +# - revive + - rowserrcheck + - sloglint + - spancheck + - sqlclosecheck + - staticcheck - stylecheck + - tagalign + - tagliatelle + - tenv + - testableexamples + - testifylint - testpackage - thelper - tparallel + - typecheck - unconvert + - unparam + - unused + - usestdlibvars +# - varnamelen + - wastedassign - whitespace -# - nolintlint // we used nolint when it's really needed # - wrapcheck + - wsl + - zerologlint + + # Enable all available linters. + # Default: false + enable-all: false + # Disable specific linter + # https://golangci-lint.run/usage/linters/#disabled-by-default + disable: + # - asasalint + # - asciicheck + # - bidichk + # - bodyclose + # - canonicalheader + # - containedctx + # - contextcheck + # - copyloopvar + # - cyclop + - decorder + # - depguard + # - dogsled + # - dupl + # - dupword + # - durationcheck + # - err113 + # - errcheck + # - errchkjson + # - errname + # - errorlint + - execinquery + # - exhaustive + # - exhaustruct + - exportloopref + # - fatcontext + # - forbidigo + # - forcetypeassert + # - funlen + # - gci + # - ginkgolinter + # - gocheckcompilerdirectives + - gochecknoglobals + # - gochecknoinits + # - gochecksumtype + # - gocognit + - goconst + # - gocritic + # - gocyclo + # - godot + # - godox + # - gofmt + # - gofumpt + - goheader + # - goimports + # - gomoddirectives + # - gomodguard + # - goprintffuncname + # - gosec + # - gosimple + # - gosmopolitan + # - govet + # - grouper + # - importas + - inamedparam + # - ineffassign + # - interfacebloat + - intrange + # - ireturn + # - lll + # - loggercheck + # - maintidx + # - makezero + # - mirror + # - misspell + # - mnd + # - musttag + # - nakedret + # - nestif + # - nilerr + # - nilnil + # - nlreturn + # - noctx + - nolintlint + - nonamedreturns + # - nosprintfhostport + # - paralleltest + # - perfsprint + # - prealloc + # - predeclared + # - promlinter + # - protogetter + # - reassign + - revive + # - rowserrcheck + # - sloglint + # - spancheck + # - sqlclosecheck + # - staticcheck + # - stylecheck + # - tagalign + # - tagliatelle + # - tenv + # - testableexamples + # - testifylint + # - testpackage + # - thelper + # - tparallel + # - typecheck + # - unconvert + # - unparam + # - unused + # - usestdlibvars + - varnamelen + # - wastedassign + # - whitespace + - wrapcheck + # - wsl + # - zerologlint + # - deadcode # Deprecated + # - exhaustivestruct # Deprecated + # - golint # Deprecated + # - ifshort # Deprecated + # - interfacer # Deprecated + # - maligned # Deprecated + # - gomnd # Deprecated + # - nosnakecase # Deprecated + # - scopelint # Deprecated + # - structcheck # Deprecated + # - varcheck # Deprecated + + # Enable presets. + # https://golangci-lint.run/usage/linters + # Default: [] presets: - bugs + - comment - complexity + - error - format + - import + - metalinter + - module - performance + - sql + - style + - test - unused - fast: false + + # Enable only fast linters from enabled linters set (first run won't be fast) + # Default: false + fast: true issues: - # List of regexps of issue texts to exclude, empty list by default. - # But independently from this option we use default exclude patterns, - # it can be disabled by `exclude-use-default: false`. To list all - # excluded by default patterns execute `golangci-lint run --help` - exclude: - - abcdef + # List of regexps of issue texts to exclude. + # + # But independently of this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. + # To list all excluded by default patterns execute `golangci-lint run --help` + # + # Default: https://golangci-lint.run/usage/false-positives/#default-exclusions + exclude: [] + # - abcdef # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: - - linters: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl - gosec - - stylecheck - text: "G404:|G108:|G401:|G501:|ST1000:" # выключена ругачка на pprof, md5, math.rand, stylecheck (ST1000: at least one file in a package should have a package comment (stylecheck) - - # exclude-rules: - # # Exclude some linters from running on tests files. - # - path: _test\.go - # linters: - # - gocyclo - # - errcheck - # - dupl - # - gosec + + # Run some linter only for test files by excluding its issues for everything else. + - path-except: _test\.go + linters: + - forbidigo # Exclude known linters from partially hard-vendored code, - # which is impossible to exclude via "nolint" comments. + # which is impossible to exclude via `nolint` comments. + # `/` will be replaced by current OS file path separator to properly work on Windows. - path: internal/hmac/ text: "weak cryptographic primitive" linters: - gosec - # Exclude some staticcheck messages + # Exclude some `staticcheck` messages. - linters: - staticcheck text: "SA9003:" - # Exclude lll issues for long lines with go:generate + # Exclude `lll` issues for long lines with `go:generate`. - linters: - lll source: "^//go:generate " - # Independently from option `exclude` we use default exclude patterns, - # it can be disabled by this option. To list all - # excluded by default patterns execute `golangci-lint run --help`. - # Default value for this option is true. + # Independently of option `exclude` we use default exclude patterns, + # it can be disabled by this option. + # To list all excluded by default patterns execute `golangci-lint run --help`. + # Default: true exclude-use-default: false - # The default value is false. If set to true exclude and exclude-rules - # regular expressions become case sensitive. + # If set to true, `exclude` and `exclude-rules` regular expressions become case-sensitive. + # Default: false exclude-case-sensitive: false - # The list of ids of default excludes to include or disable. By default it's empty. + # Which dirs to exclude: issues from them won't be reported. + # Can use regexp here: `generated.*`, regexp is applied on full path, + # including the path prefix if one is set. + # Default dirs are skipped independently of this option's value (see exclude-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work on Windows. + # Default: [] + exclude-dirs: + - src/external_libs + - autogenerated_by_my_lib + + # Enables exclude of directories: + # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + # Default: true + exclude-dirs-use-default: false + + # Which files to exclude: they will be analyzed, but issues from them won't be reported. + # There is no need to include all autogenerated files, + # we confidently recognize autogenerated files. + # If it's not, please let us know. + # "/" will be replaced by current OS file path separator to properly work on Windows. + # Default: [] + exclude-files: + - ".*\\.my\\.go$" + - lib/bad.go + + # Mode of the generated files analysis. + # + # - `strict`: sources are excluded by following strictly the Go generated file convention. + # Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\.$` + # This line must appear before the first non-comment, non-blank text in the file. + # https://go.dev/s/generatedcode + # - `lax`: sources are excluded if they contain lines `autogenerated file`, `code generated`, `do not edit`, etc. + # - `disable`: disable the generated files exclusion. + # + # Default: lax + exclude-generated: strict + + # The list of ids of default excludes to include or disable. + # https://golangci-lint.run/usage/false-positives/#default-exclusions + # Default: [] include: - - EXC0002 # disable excluding of issues about comments from golint + - EXC0001 + - EXC0002 + - EXC0003 + - EXC0004 + - EXC0005 + - EXC0006 + - EXC0007 + - EXC0008 + - EXC0009 + - EXC0010 + - EXC0011 + - EXC0012 + - EXC0013 + - EXC0014 + - EXC0015 - # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + # Maximum issues count per one linter. + # Set to 0 to disable. + # Default: 50 max-issues-per-linter: 0 - # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 max-same-issues: 0 # Show only new issues: if there are unstaged changes or untracked files, # only those changes are analyzed, else only changes in HEAD~ are analyzed. - # It's a super-useful option for integration of golangci-lint into existing - # large codebase. It's not practical to fix all existing issues at the moment - # of integration: much better don't allow issues in new code. - # Default is false. - new: false + # It's a super-useful option for integration of golangci-lint into existing large codebase. + # It's not practical to fix all existing issues at the moment of integration: + # much better don't allow issues in new code. + # + # Default: false + new: true - # Show only new issues created after git revision `REV` - new-from-rev: REV + # Show only new issues created after git revision `REV`. + # Default: "" + new-from-rev: HEAD # Show only new issues created in git patch with set file path. - # new-from-patch: path/to/patch/file + # Default: "" + new-from-patch: "" - # Fix found issues (if it's supported by the linter) + # Fix found issues (if it's supported by the linter). + # Default: false fix: true + # Show issues in any part of update files (requires new-from-rev or new-from-patch). + # Default: false + whole-files: true + severity: - # Default value is empty string. - # Set the default severity for issues. If severity rules are defined and the issues - # do not match or no severity is provided to the rule this will be the default - # severity applied. Severities should match the supported severity names of the - # selected out format. + # Set the default severity for issues. + # + # If severity rules are defined and the issues do not match or no severity is provided to the rule + # this will be the default severity applied. + # Severities should match the supported severity names of the selected out format. # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity - # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity - # - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#SeverityLevel + # - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + # - TeamCity: https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance + # + # `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...) + # + # Default: "" default-severity: error - # The default value is false. - # If set to true severity-rules regular expressions become case sensitive. - case-sensitive: false + # If set to true `severity-rules` regular expressions become case-sensitive. + # Default: false + case-sensitive: true - # Default value is empty list. - # When a list of severity rules are provided, severity information will be added to lint - # issues. Severity rules have the same filtering capability as exclude rules except you - # are allowed to specify one matcher per severity rule. + # When a list of severity rules are provided, severity information will be added to lint issues. + # Severity rules have the same filtering capability as exclude rules + # except you are allowed to specify one matcher per severity rule. + # + # `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...) + # # Only affects out formats that support setting severity information. + # + # Default: [] rules: - linters: - dupl diff --git a/logger/dev.go b/logger/dev.go index 7fbb475..9690635 100644 --- a/logger/dev.go +++ b/logger/dev.go @@ -1,4 +1,4 @@ -// +build enable_zap_logger +//go:build enable_zap_logger package logger diff --git a/logger/prod.go b/logger/prod.go index e8395d6..3512ada 100644 --- a/logger/prod.go +++ b/logger/prod.go @@ -1,4 +1,4 @@ -// +build !enable_zap_logger +//go:build !enable_zap_logger package logger @@ -8,5 +8,6 @@ type Logger = *zap.Logger var Log = func() Logger { l, _ := zap.NewProduction() + return l }() diff --git a/nats/client.go b/nats/client.go index 9f89b94..6c4a0c9 100644 --- a/nats/client.go +++ b/nats/client.go @@ -2,37 +2,39 @@ package nats import ( "context" + "errors" + "fmt" "strings" "time" - "github.com/imperiuse/advanced-nats-client/v1/logger" - "github.com/imperiuse/advanced-nats-client/v1/serializable" "github.com/nats-io/nats.go" - "github.com/pkg/errors" "go.uber.org/zap" + + "github.com/imperiuse/advanced-nats-client/v1/logger" + "github.com/imperiuse/advanced-nats-client/v1/serializable" ) const ( - // MaxReconnectDefault - max reconnect try cnt. - MaxReconnectDefault = -1 // infinity + // MaxReconnectDefault - max number of reconnect attempts. + MaxReconnectDefault = -1 // infinite - // ReconnectWaitDefault - reconnect w8 timeout default value. + // ReconnectWaitDefault - default reconnect wait timeout value. ReconnectWaitDefault = 5 * time.Second - // ReconnectJitterDefault - reconnect w8 jitter timeout default value. - ReconnectJitterDefault = time.Second * 1 + // ReconnectJitterDefault - default reconnect jitter wait timeout value. + ReconnectJitterDefault = 1 * time.Second - // ReconnectJitterTLSDefault - reconnect w8 jitter TLS timeout default value. - ReconnectJitterTLSDefault = time.Second * 2 + // ReconnectJitterTLSDefault - default reconnect jitter TLS wait timeout value. + ReconnectJitterTLSDefault = 2 * time.Second ) -// ErrEmptyMsg - empty msg. nats msg is nil. -var ErrEmptyMsg = errors.New("empty msg. nats msg is nil") +// ErrEmptyMsg - error returned when the NATS message is nil. +var ErrEmptyMsg = errors.New("empty message: NATS message is nil") -// DefaultDSN - default nats url and port. +// DefaultDSN - default NATS URL and port. var DefaultDSN = []URL{nats.DefaultURL} -// SimpleNatsClientI _ . +// SimpleNatsClientI - interface defining basic operations of a NATS client. type SimpleNatsClientI interface { UseCustomLogger(logger.Logger) Ping(context.Context, Subj) (bool, error) @@ -47,7 +49,7 @@ type SimpleNatsClientI interface { //go:generate mockery --name=PureNatsConnI type ( - // PureNatsConnI - pure nats conn interface. + // PureNatsConnI - interface for pure NATS connection. PureNatsConnI interface { RequestWithContext(ctx context.Context, subj string, data []byte) (*Msg, error) Subscribe(subj string, msgHandler MsgHandler) (*Subscription, error) @@ -61,32 +63,32 @@ type ( // QueueGroup - queue group name. QueueGroup string - // client - wrapper for pure nats.Conn, so it's own nats client library for reduce code. + // Client - wrapper around the pure nats.Conn, a custom NATS client to reduce repetitive code. client struct { log logger.Logger - dsn []URL + dsn []URL //nolint:unused conn PureNatsConnI - pureNC *Conn // pure nats connection, for some special stuff, doesn't matter in all + pureNC *Conn // pure NATS connection, used for special operations, generally not required } - // URL - url name. - URL = string // dsn url like this -> "nats://127.0.0.1:4222" + // URL - URL string. + URL = string // DSN URL, e.g., "nats://127.0.0.1:4222" - // Option - nats.Msg. + // Option - alias for nats.Option. Option = nats.Option - // MsgHandler - nats.MsgHandler. + // MsgHandler - alias for nats.MsgHandler. MsgHandler = nats.MsgHandler - // Msg - nats.Msg. + // Msg - alias for nats.Msg. Msg = nats.Msg - // Subscription - nats.Subscription. + // Subscription - alias for nats.Subscription. Subscription = nats.Subscription - // Conn - nats.Conn struct. + // Conn - alias for nats.Conn. Conn = nats.Conn - // Handler - pure NATS Msg, request reply. + // Handler - handler function to process pure NATS messages and reply. Handler = func(*Msg, Serializable) Serializable - // Serializable - serializable. + // Serializable - serializable interface. Serializable = serializable.Serializable ) @@ -95,19 +97,19 @@ const ( pongMsg = "pong" ) -// New - main "constructor" function. -// nolint golint +// New - main constructor function. +// nolint: golint func New(dsn []URL, options ...Option) (*client, error) { c := NewDefaultClient().addDSN(dsn) - // Default settings for internal NATS client + // Default settings for the internal NATS client if len(options) == 0 { options = c.defaultNatsOptions() } conn, err := createNatsConn(dsn, options...) if err != nil { - return nil, errors.Wrap(err, "can't create nats conn. nats unavailbale?") + return nil, fmt.Errorf("unable to create NATS connection: is NATS unavailable?: %w", err) } c.conn = conn @@ -116,22 +118,20 @@ func New(dsn []URL, options ...Option) (*client, error) { return c, nil } -func createNatsConn(dsn []URL, option ...Option) (*nats.Conn, error) { - // Normally, the library will return an error when trying to connect and - // there is no server running. The RetryOnFailedConnect option will set - // the connection in reconnecting state if it failed to connect right away. - conn, err := nats.Connect(strings.Join(dsn, ", "), option...) +func createNatsConn(dsn []URL, options ...Option) (*nats.Conn, error) { + // Normally, the library returns an error when attempting to connect if there is no server running. + // The RetryOnFailedConnect option sets the connection to a reconnecting state if the initial connection attempt fails. + conn, err := nats.Connect(strings.Join(dsn, ", "), options...) if err != nil { - // Should not return an error even if it can't connect, but you still - // need to check in case there are some configuration errors. - return nil, errors.Wrap(err, "create nats.Connect") + // Should not return an error even if it can't connect immediately, but still check for configuration errors. + return nil, fmt.Errorf("error creating nats.Connect: %w", err) } return conn, nil } -// NewDefaultClient empty default client. -// nolint golint +// NewDefaultClient creates an empty default client. +// nolint: golint func NewDefaultClient() *client { return &client{ dsn: DefaultDSN, @@ -153,59 +153,59 @@ func (c *client) defaultNatsOptions() []Option { nats.ReconnectJitter(ReconnectJitterDefault, ReconnectJitterTLSDefault), nats.ReconnectWait(ReconnectWaitDefault), nats.DisconnectErrHandler(func(nc *nats.Conn, err error) { - c.log.Warn("[DisconnectErrHandler] Disconnect", zap.Error(err)) + c.log.Warn("[DisconnectErrHandler] Disconnected", zap.Error(err)) }), nats.ReconnectHandler(func(nc *nats.Conn) { - c.log.Warn("[ReconnectHandler] Reconnect", zap.String("ConnUrl", nc.ConnectedUrl())) + c.log.Warn("[ReconnectHandler] Reconnected", zap.String("ConnUrl", nc.ConnectedUrl())) }), nats.ClosedHandler(func(nc *nats.Conn) { - c.log.Warn("[ClosedHandler] Close handler", zap.Error(nc.LastError())) + c.log.Warn("[ClosedHandler] Connection closed", zap.Error(nc.LastError())) }), nats.ErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, err error) { - c.log.Warn("[ErrorHandler]", zap.Error(err)) + c.log.Warn("[ErrorHandler] NATS error", zap.Error(err)) }), } } -// UseCustomLogger - register your own logger instance of zap.Logger. +// UseCustomLogger registers a custom logger instance. func (c *client) UseCustomLogger(log logger.Logger) { c.log = log } -// Ping - send synchronous request with ctx deadline or timeout -// e.g. ctx, _ := context.WithTimeout(context.Background(), time.Second). +// Ping sends a synchronous request with a context deadline or timeout. func (c *client) Ping(ctx context.Context, subj Subj) (bool, error) { c.log.Debug("Ping", zap.String("subj", string(subj))) msg, err := c.conn.RequestWithContext(ctx, string(subj), []byte(pingMsg)) if err != nil { - return false, errors.Wrap(err, "c.conn.RequestWithContext") + return false, fmt.Errorf("c.conn.RequestWithContext: %w", err) } if msg == nil { - return false, errors.Wrap(ErrEmptyMsg, "msg == nil") + return false, fmt.Errorf("msg is nil: %w", ErrEmptyMsg) } return string(msg.Data) == pongMsg, nil } -// PongHandler - register simple pong handler (use to peer-to-peer topics). +// PongHandler registers a simple pong handler (used for peer-to-peer topics). func (c *client) PongHandler(subj Subj) (*Subscription, error) { c.log.Debug("[PongHandler]", zap.String("subj", string(subj))) return c.conn.Subscribe(string(subj), func(msg *Msg) { if msg == nil { - c.log.Debug("Nil msg", zap.String("subj", string(subj))) + c.log.Debug("Received nil msg", zap.String("subj", string(subj))) return } + if string(msg.Data) == pingMsg { _ = msg.Respond([]byte(pongMsg)) } }) } -// PongQueueHandler - register pong handler with QueueGroup (use to 1 to Many). +// PongQueueHandler registers a pong handler with QueueGroup (used for 1-to-many communication). func (c *client) PongQueueHandler(subj Subj, queue QueueGroup) (*Subscription, error) { c.log.Debug("[PongQueueHandler]", zap.String("subj", string(subj)), zap.String("queue", string(queue))) @@ -213,46 +213,47 @@ func (c *client) PongQueueHandler(subj Subj, queue QueueGroup) (*Subscription, e if msg == nil { return } + if string(msg.Data) == pingMsg { _ = msg.Respond([]byte(pongMsg)) } }) } -// Request - send synchronous msg to topic subj, and wait reply from another topic (e.g. Request-Reply Nats pattern). -func (c *client) Request(ctx context.Context, subj Subj, request Serializable, reply Serializable) error { +// Request sends a synchronous message to a subject and waits for a reply (following the Request-Reply NATS pattern). +func (c *client) Request(ctx context.Context, subj Subj, request, reply Serializable) error { c.log.Debug("[Request]", zap.String("subj", string(subj)), zap.Any("data", request)) byteData, err := request.Marshal() if err != nil { - return errors.Wrap(err, "request.Marshal()") + return fmt.Errorf("request.Marshal(): %w", err) } msg, err := c.conn.RequestWithContext(ctx, string(subj), byteData) if err != nil { - return errors.Wrap(err, "c.conn.RequestWithContext") + return fmt.Errorf("c.conn.RequestWithContext: %w", err) } if msg == nil { - return errors.Wrap(ErrEmptyMsg, "Request") + return fmt.Errorf("*client.Request(): %w", ErrEmptyMsg) } return reply.Unmarshal(msg.Data) } -// ReplyHandler - register for asynchronous msgHandler func for process Nats Msg. +// ReplyHandler registers an asynchronous message handler for processing NATS messages. func (c *client) ReplyHandler(subj Subj, awaitData Serializable, msgHandler Handler) (*Subscription, error) { return c.conn.Subscribe(string(subj), func(msg *nats.Msg) { if msg == nil { - c.log.Warn("[ReplyHandler] Nil msg", zap.String("subj", string(subj))) + c.log.Warn("[ReplyHandler] Received nil message", zap.String("subj", string(subj))) return } - awaitData.Reset() // Important! For use clean struct + awaitData.Reset() // Important! Clean struct before use. if err := awaitData.Unmarshal(msg.Data); err != nil { - c.log.Error("[ReplyHandler] Unmarshal", + c.log.Error("[ReplyHandler] Unmarshal failed", zap.String("subj", string(subj)), zap.Any("msg", msg), zap.Error(err), @@ -265,7 +266,7 @@ func (c *client) ReplyHandler(subj Subj, awaitData Serializable, msgHandler Hand data, err := replyData.Marshal() if err != nil { - c.log.Error("[ReplyHandler] Marshall", + c.log.Error("[ReplyHandler] Marshal failed", zap.String("subj", string(subj)), zap.Any("data", replyData), zap.Error(err), @@ -275,29 +276,27 @@ func (c *client) ReplyHandler(subj Subj, awaitData Serializable, msgHandler Hand } if err = msg.Respond(data); err != nil { - c.log.Error("[ReplyHandler] Respond", + c.log.Error("[ReplyHandler] Response failed", zap.String("subj", string(subj)), zap.Error(err), ) - - return } }) } -// ReplyQueueHandler - register queue for asynchronous msgHandler func for process Nats Msg. +// ReplyQueueHandler registers a queue for asynchronous message processing with a handler. func (c *client) ReplyQueueHandler(subj Subj, qG QueueGroup, awaitData Serializable, h Handler) (*Subscription, error) { return c.conn.QueueSubscribe(string(subj), string(qG), func(msg *nats.Msg) { if msg == nil { - c.log.Warn("[ReplyQueueHandler] Nil msg", zap.String("subj", string(subj))) + c.log.Warn("[ReplyQueueHandler] Received nil message", zap.String("subj", string(subj))) return } - awaitData.Reset() // Important! For use clean struct + awaitData.Reset() // Important! Clean struct before use. if err := awaitData.Unmarshal(msg.Data); err != nil { - c.log.Error("[ReplyQueueHandler] Unmarshal", + c.log.Error("[ReplyQueueHandler] Unmarshal failed", zap.String("subj", string(subj)), zap.String("qGroup", string(qG)), zap.Any("msg", msg), @@ -311,7 +310,7 @@ func (c *client) ReplyQueueHandler(subj Subj, qG QueueGroup, awaitData Serializa data, err := replyData.Marshal() if err != nil { - c.log.Error("[ReplyQueueHandler] Marshall", + c.log.Error("[ReplyQueueHandler] Marshal failed", zap.String("subj", string(subj)), zap.String("qGroup", string(qG)), zap.Any("data", replyData), @@ -322,28 +321,26 @@ func (c *client) ReplyQueueHandler(subj Subj, qG QueueGroup, awaitData Serializa } if err = msg.Respond(data); err != nil { - c.log.Error("[ReplyQueueHandler] Respond", + c.log.Error("[ReplyQueueHandler] Response failed", zap.String("subj", string(subj)), zap.String("qGroup", string(qG)), zap.Error(err), ) - - return } }) } -// NatsConn - return pure Nats Conn (pointer to struct). +// NatsConn returns the pure NATS connection (pointer to the connection struct). func (c *client) NatsConn() *Conn { return c.pureNC } -// Close - Drain and Close workaround. +// Close drains and closes the NATS connection. func (c *client) Close() error { defer c.conn.Close() if err := c.conn.Drain(); err != nil { - return errors.Wrap(err, "c.conn.Drain") + return fmt.Errorf("c.conn.Drain: %w", err) } return nil diff --git a/nats/client_test.go b/nats/client_test.go index 8d32f34..84efbbc 100644 --- a/nats/client_test.go +++ b/nats/client_test.go @@ -18,7 +18,7 @@ import ( var testDSN = []URL{"nats://127.0.0.1:4223"} -type NatsClientTestSuit struct { +type NatsClientTestSuite struct { suite.Suite ctx context.Context ctxCancel context.CancelFunc @@ -27,67 +27,64 @@ type NatsClientTestSuit struct { mockNats *mocks.PureNatsConnI } -// The SetupSuite method will be run by testify once, at the very -// start of the testing suite, before any tests are run. -func (suite *NatsClientTestSuit) SetupSuite() { +// SetupSuite will be run by testify once at the very start of the test suite before any tests are executed. +func (suite *NatsClientTestSuite) SetupSuite() { c, err := New([]URL{"nats://1.2.3.4:5678"}) - assert.Nil(suite.T(), c, "must be nil!") - assert.NotNil(suite.T(), err, "must be error!") + assert.Nil(suite.T(), c, "client must be nil!") + assert.NotNil(suite.T(), err, "must return an error!") suite.natsClient, err = New(testDSN) assert.NotNil(suite.T(), suite.natsClient, "client must not be nil") - assert.Nil(suite.T(), err, "err must be nil") - assert.NotNil(suite.T(), suite.natsClient.NatsConn(), "pure nats conn must not be nil") + assert.Nil(suite.T(), err, "error must be nil") + assert.NotNil(suite.T(), suite.natsClient.NatsConn(), "NATS connection must not be nil") suite.natsClient.UseCustomLogger(zap.NewNop()) suite.badNatsClient, err = New(testDSN) suite.badNatsClient.UseCustomLogger(zap.NewNop()) assert.NotNil(suite.T(), suite.badNatsClient, "client must not be nil") - assert.Nil(suite.T(), err, "err must be nil") + assert.Nil(suite.T(), err, "error must be nil") mockNats := &mocks.PureNatsConnI{} suite.badNatsClient.conn = mockNats suite.mockNats = mockNats - // Mock configurations down + + // Mock configurations // NB: .Return(...) must return the same signature as the method being mocked. //mockNats.On("RequestWithContext", mock.AnythingOfType("context.Context"), mock.AnythingOfType("string"), mock.Anything, mock.AnythingOfType("time.Duration")).Return(nil, nil) // Request(subj string, data []byte, timeout time.Duration) (*Msg, error) //mockNats.On("Subscribe", mock.AnythingOfType("string"), mock.AnythingOfType("MsgHandler")).Return(nil, nil) // Subscribe(subj string, cb MsgHandler) (*Subscription, error) - //mockNats.On("QueueSubscribe", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("MsgHandler")).Return(nil, nil) // Subscribe(subj string, cb MsgHandler) (*Subscription, error) - //mockNats.On("Drain").Return(nil) // Drain()error + //mockNats.On("QueueSubscribe", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("MsgHandler")).Return(nil, nil) // QueueSubscribe(subj string, queueGroup string, cb MsgHandler) (*Subscription, error) + //mockNats.On("Drain").Return(nil) // Drain() error //mockNats.On("Close").Return() // Close() - } -// The TearDownSuite method will be run by testify once, at the very -// end of the testing suite, after all tests have been run. -func (suite *NatsClientTestSuit) TearDownSuite() { +// TearDownSuite will be run by testify once at the end of the test suite after all tests have been executed. +func (suite *NatsClientTestSuite) TearDownSuite() { err := suite.natsClient.Close() assert.Nil(suite.T(), err) - suite.mockNats.On("Drain").Return(nil) // Drain()error + suite.mockNats.On("Drain").Return(nil) // Drain() error suite.mockNats.On("Close").Return() // Close() err = suite.badNatsClient.Close() assert.Nil(suite.T(), err) } -// The SetupTest method will be run before every test in the suite. -func (suite *NatsClientTestSuit) SetupTest() { +// SetupTest will be run before each test in the suite. +func (suite *NatsClientTestSuite) SetupTest() { suite.ctx, suite.ctxCancel = context.WithCancel(context.Background()) } -// The TearDownTest method will be run after every test in the suite. -func (suite *NatsClientTestSuit) TearDownTest() { +// TearDownTest will be run after each test in the suite. +func (suite *NatsClientTestSuite) TearDownTest() { + suite.ctxCancel() } -// In order for 'go test' to run this suite, we need to create -// a normal test function and pass our suite to suite.Run +// TestExampleTestSuite runs the test suite. func TestExampleTestSuite(t *testing.T) { - suite.Run(t, new(NatsClientTestSuit)) + suite.Run(t, new(NatsClientTestSuite)) } -// All methods that begin with "Test" are run as tests within a -// suite. -func (suite *NatsClientTestSuit) Test_PingPong() { +// Test_PingPong tests ping-pong communication. +func (suite *NatsClientTestSuite) Test_PingPong() { const ( subj = "Test_PingPong" timeout1 = time.Millisecond @@ -98,30 +95,31 @@ func (suite *NatsClientTestSuit) Test_PingPong() { ctx, cancelFunc := context.WithTimeout(context.Background(), timeout1) defer cancelFunc() result, err := suite.natsClient.Ping(ctx, subj) - assert.NotNil(suite.T(), err, "Ping err") - assert.False(suite.T(), result, "Ping must be false") + assert.NotNil(suite.T(), err, "Ping should return an error") + assert.False(suite.T(), result, "Ping should return false") pongSubscription, err := suite.natsClient.PongHandler(subj) - assert.Nil(suite.T(), err, "PongHandler error") - assert.NotNil(suite.T(), pongSubscription, "pongSubscription must non nil") + assert.Nil(suite.T(), err, "PongHandler should not return an error") + assert.NotNil(suite.T(), pongSubscription, "pongSubscription should not be nil") ctx, cancelFunc2 := context.WithTimeout(context.Background(), timeout2) defer cancelFunc2() result, err = suite.natsClient.Ping(ctx, subj) - assert.Nil(suite.T(), err, "Ping err") - assert.True(suite.T(), result, "Ping be true") + assert.Nil(suite.T(), err, "Ping should not return an error") + assert.True(suite.T(), result, "Ping should return true") err = pongSubscription.Unsubscribe() - assert.Nil(suite.T(), err, "pongSubscription.Unsubscribe() err") + assert.Nil(suite.T(), err, "pongSubscription.Unsubscribe() should not return an error") ctx, cancelFunc3 := context.WithTimeout(context.Background(), timeout1) defer cancelFunc3() result, err = suite.natsClient.Ping(ctx, subj) - assert.NotNil(suite.T(), err, "Ping err") - assert.False(suite.T(), result, "Ping must be false") + assert.NotNil(suite.T(), err, "Ping should return an error") + assert.False(suite.T(), result, "Ping should return false") } -func (suite *NatsClientTestSuit) Test_PongQueueGroup() { +// Test_PongQueueGroup tests queue group pong handling. +func (suite *NatsClientTestSuite) Test_PongQueueGroup() { const ( subj = "Test_PongQueueGroup" queue = subj @@ -132,50 +130,51 @@ func (suite *NatsClientTestSuit) Test_PongQueueGroup() { ctx, cancelFunc := context.WithTimeout(context.Background(), timeout1) defer cancelFunc() result, err := suite.natsClient.Ping(ctx, subj) - assert.NotNil(suite.T(), err, "Ping err") - assert.False(suite.T(), result, "Ping must be false") + assert.NotNil(suite.T(), err, "Ping should return an error") + assert.False(suite.T(), result, "Ping should return false") pongSubscription, err := suite.natsClient.PongQueueHandler(subj, queue) - assert.Nil(suite.T(), err, "PongQueueHandler error") - assert.NotNil(suite.T(), pongSubscription, "pongSubscription must non nil") + assert.Nil(suite.T(), err, "PongQueueHandler should not return an error") + assert.NotNil(suite.T(), pongSubscription, "pongSubscription should not be nil") pongSubscription2, err := suite.natsClient.PongQueueHandler(subj, queue) - assert.Nil(suite.T(), err, "PongQueueHandler error") - assert.NotNil(suite.T(), pongSubscription2, "pongSubscription2 must non nil") + assert.Nil(suite.T(), err, "PongQueueHandler should not return an error") + assert.NotNil(suite.T(), pongSubscription2, "pongSubscription2 should not be nil") ctx, cancelFunc2 := context.WithTimeout(context.Background(), timeout2) defer cancelFunc2() result, err = suite.natsClient.Ping(ctx, subj) - assert.Nil(suite.T(), err, "Ping err") - assert.True(suite.T(), result, "Ping be true") + assert.Nil(suite.T(), err, "Ping should not return an error") + assert.True(suite.T(), result, "Ping should return true") err = pongSubscription.Unsubscribe() - assert.Nil(suite.T(), err, "pongSubscription.Unsubscribe() err") + assert.Nil(suite.T(), err, "pongSubscription.Unsubscribe() should not return an error") ctx, cancelFunc3 := context.WithTimeout(context.Background(), timeout2) defer cancelFunc3() result, err = suite.natsClient.Ping(ctx, subj) - assert.Nil(suite.T(), err, "Ping err") - assert.True(suite.T(), result, "Ping be true") + assert.Nil(suite.T(), err, "Ping should not return an error") + assert.True(suite.T(), result, "Ping should return true") err = pongSubscription2.Unsubscribe() - assert.Nil(suite.T(), err, "pongSubscription2.Unsubscribe() err") + assert.Nil(suite.T(), err, "pongSubscription2.Unsubscribe() should not return an error") ctx, cancelFunc4 := context.WithTimeout(context.Background(), timeout1) defer cancelFunc4() result, err = suite.natsClient.Ping(ctx, subj) - assert.NotNil(suite.T(), err, "Ping err") - assert.False(suite.T(), result, "Ping must be false") + assert.NotNil(suite.T(), err, "Ping should return an error") + assert.False(suite.T(), result, "Ping should return false") } -func (suite *NatsClientTestSuit) Test_RequestReply() { +// Test_RequestReply tests the request-reply pattern. +func (suite *NatsClientTestSuite) Test_RequestReply() { const ( cntMsg = 3 subj = "Test_RequestReply" timeoutNatsRequest = time.Millisecond * 500 timeoutTest = time.Millisecond * 1000 - requestData = "mock request requestData" - replyData = "mock reply requestData" + requestData = "mock request data" + replyData = "mock reply data" ) ctx, cancelFunc := context.WithTimeout(context.Background(), timeoutNatsRequest) @@ -192,7 +191,7 @@ func (suite *NatsClientTestSuit) Test_RequestReply() { respondersWG := sync.WaitGroup{} respondersWG.Add(1) - // here server side emulate send request to client + // Server-side: simulate sending a request to the client go func(sendChan <-chan m.DataMock) { respondersWG.Wait() @@ -200,12 +199,12 @@ func (suite *NatsClientTestSuit) Test_RequestReply() { for request := range sendChan { request := request err := suite.natsClient.Request(ctx, subj, &request, reply) - assert.Nil(suite.T(), err, "Request err") - assert.Equal(suite.T(), replyData, string(reply.Data)) + assert.Nil(suite.T(), err, "Request should not return an error") + assert.Equal(suite.T(), replyData, string(reply.Data), "Reply data mismatch") } }(sendChan) - // here client side reply to server + // Client-side: reply to the server go func() { routineWG := sync.WaitGroup{} routineWG.Add(cntMsg) @@ -214,14 +213,14 @@ func (suite *NatsClientTestSuit) Test_RequestReply() { _, err := suite.natsClient.ReplyHandler(subj, &m.DataMock{}, func(msg *Msg, request Serializable) Serializable { if example, ok := request.(*m.DataMock); ok { - assert.NotNil(suite.T(), example, "example must be non nil") - assert.Equal(suite.T(), requestData, string(example.Data), "wrong requestData received") + assert.NotNil(suite.T(), example, "Request data should not be nil") + assert.Equal(suite.T(), requestData, string(example.Data), "Incorrect request data received") } routineWG.Done() wg.Done() return &m.DataMock{Data: []byte(replyData)} }) - assert.Nil(suite.T(), err, "Reply handler err") + assert.Nil(suite.T(), err, "Reply handler should not return an error") routineWG.Wait() }() @@ -229,82 +228,83 @@ func (suite *NatsClientTestSuit) Test_RequestReply() { time.Sleep(timeoutTest) } -func (suite *NatsClientTestSuit) Test_RequestReplyQueue() { +func (suite *NatsClientTestSuite) Test_RequestReplyQueue() { const ( cntMsg = 3 subj = "Test_RequestReplyQueue" qGroup = "Test_RequestReplyQueue" timeoutNatsRequest = time.Millisecond * 500 - requestData = "mock request requestData" - replyData = "mock reply requestData" + requestData = "mock request data" + replyData = "mock reply data" timeoutTest = time.Millisecond * 1000 ) - var cnt atomic.Int32 // проверка что действительно только один из двух handler-ов обрабатывает request + var cnt atomic.Int32 // Ensure that only one of the two handlers processes each request cnt.Store(0) ctx, cancelFunc := context.WithTimeout(context.Background(), timeoutNatsRequest) defer cancelFunc() var wg sync.WaitGroup - sendChan := make(chan m.DataMock, cntMsg) + sendChan := make(chan m.DataMock) wg.Add(cntMsg) - for i := 0; i < cntMsg; i++ { - sendChan <- m.DataMock{Data: []byte(requestData)} - } - close(sendChan) - // here server side emulate send request to client + // Server-side: simulate sending a request to the client go func(sendChan <-chan m.DataMock) { reply := &m.DataMock{} for request := range sendChan { request := request err := suite.natsClient.Request(ctx, subj, &request, reply) - assert.Nil(suite.T(), err, "Request err") - assert.Equal(suite.T(), replyData, string(reply.Data)) + assert.Nil(suite.T(), err, "Request should not return an error") + assert.Equal(suite.T(), replyData, string(reply.Data), "Reply data mismatch") } }(sendChan) - // here client side reply to server + // Client-side: reply to the server go func() { routineWG := sync.WaitGroup{} routineWG.Add(cntMsg) s, err := suite.natsClient.ReplyQueueHandler(subj, qGroup, &m.DataMock{}, func(msg *Msg, request Serializable) Serializable { if example, ok := request.(*m.DataMock); ok { - assert.NotNil(suite.T(), example, "example must be non nil") - assert.Equal(suite.T(), requestData, string(example.Data), "wrong requestData received") + assert.NotNil(suite.T(), example, "Request data should not be nil") + assert.Equal(suite.T(), requestData, string(example.Data), "Incorrect request data received") } cnt.Inc() routineWG.Done() wg.Done() return &m.DataMock{Data: []byte(replyData)} }) - defer func() { assert.Nil(suite.T(), s.Unsubscribe(), "must be nil") }() - assert.Nil(suite.T(), err, "Reply handler err") + defer func() { assert.Nil(suite.T(), s.Unsubscribe(), "Unsubscribe should not return an error") }() + assert.Nil(suite.T(), err, "Reply handler should not return an error") s2, err := suite.natsClient.ReplyQueueHandler(subj, qGroup, &m.DataMock{}, func(msg *Msg, request Serializable) Serializable { if example, ok := request.(*m.DataMock); ok { - assert.NotNil(suite.T(), example, "example must be non nil") - assert.Equal(suite.T(), requestData, string(example.Data), "wrong requestData received") + assert.NotNil(suite.T(), example, "Request data should not be nil") + assert.Equal(suite.T(), requestData, string(example.Data), "Incorrect request data received") } cnt.Inc() routineWG.Done() wg.Done() return &m.DataMock{Data: []byte(replyData)} }) - defer func() { assert.Nil(suite.T(), s2.Unsubscribe(), "must be nil") }() - assert.Nil(suite.T(), err, "Reply handler err") + defer func() { assert.Nil(suite.T(), s2.Unsubscribe(), "Unsubscribe should not return an error") }() + assert.Nil(suite.T(), err, "Reply handler should not return an error") routineWG.Wait() }() + for i := 0; i < cntMsg; i++ { + sendChan <- m.DataMock{Data: []byte(requestData)} + } + close(sendChan) + wg.Wait() - assert.Equal(suite.T(), cntMsg, int(cnt.Load())) + assert.Equal(suite.T(), cntMsg, int(cnt.Load()), "Count mismatch") time.Sleep(timeoutTest) } -func (suite *NatsClientTestSuit) Test_BadRequestReply() { +func (suite *NatsClientTestSuite) Test_BadRequestReply() { const ( subj = "Test_BadRequestReply" timeoutNatsRequest = time.Second @@ -318,14 +318,14 @@ func (suite *NatsClientTestSuit) Test_BadRequestReply() { sendChan <- m.BadDataMock{} close(sendChan) - // here server side emulate send request to client + // Server-side: simulate sending a bad request to the client go func(sendChan <-chan m.BadDataMock, done chan<- struct{}) { reply := &m.DataMock{} for request := range sendChan { request := request err := suite.natsClient.Request(ctx, subj, &request, reply) - assert.NotNil(suite.T(), err, "Must be err") - assert.Equal(suite.T(), m.ErrBadDataMock, errors.Cause(err), "must be err errBadDataMock") + assert.NotNil(suite.T(), err, "Must return an error") + assert.ErrorIs(suite.T(), err, m.ErrBadDataMock, "Error should match ErrBadDataMock") } done <- struct{}{} }(sendChan, done) @@ -334,19 +334,19 @@ func (suite *NatsClientTestSuit) Test_BadRequestReply() { close(done) } -func (suite *NatsClientTestSuit) Test_BadSubscribe() { +func (suite *NatsClientTestSuite) Test_BadSubscribe() { errBad := errors.New("bad") suite.mockNats.On("Subscribe", mock.AnythingOfType("string"), mock.AnythingOfType("MsgHandler")).Return(nil, errBad) // Subscribe(subj string, cb MsgHandler) (*Subscription, error) s, err := suite.badNatsClient.ReplyHandler("testSubj", &m.DataMock{}, func(_ *Msg, _ Serializable) Serializable { return &m.DataMock{} }) - assert.Nil(suite.T(), s, "must be nil") - assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), errBad, errors.Cause(err), "must be equals") + assert.Nil(suite.T(), s, "Subscription should be nil") + assert.NotNil(suite.T(), err, "Must return an error") + assert.ErrorIs(suite.T(), err, errBad, "Error should match errBad") } -func (suite *NatsClientTestSuit) Test_BadRequest1() { +func (suite *NatsClientTestSuite) Test_BadRequest1() { const timeoutNatsRequest = time.Second ctx, cancelFunc := context.WithTimeout(context.Background(), timeoutNatsRequest) defer cancelFunc() @@ -355,22 +355,22 @@ func (suite *NatsClientTestSuit) Test_BadRequest1() { errBad := errors.New(errStrBad) suite.mockNats.On("RequestWithContext", mock.Anything, mock.AnythingOfType("string"), mock.Anything).Return(&Msg{}, errBad) err := suite.badNatsClient.Request(ctx, "testSubj", &m.DataMock{Data: []byte("mock data")}, &m.DataMock{}) - assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), errBad, errors.Cause(err), "must be equals") + assert.NotNil(suite.T(), err, "Must return an error") + assert.ErrorIs(suite.T(), err, errBad, "Error should match errBad") - // it's hack, because you can't change hook with On() function =( + // It's a workaround since you can't change the hook with On() function suite.mockNats = &mocks.PureNatsConnI{} suite.badNatsClient.conn = suite.mockNats suite.mockNats.On("RequestWithContext", mock.Anything, mock.AnythingOfType("string"), mock.Anything).Return(nil, nil) err = suite.badNatsClient.Request(ctx, "testSubj", &m.DataMock{Data: []byte("mock data")}, &m.DataMock{}) - assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), ErrEmptyMsg, errors.Cause(err), "must be equals") + assert.NotNil(suite.T(), err, "Must return an error") + assert.ErrorIs(suite.T(), err, ErrEmptyMsg, "Error should match ErrEmptyMsg") - // it's hack, because you can't change hook with On() function =( + // It's a workaround since you can't change the hook with On() function suite.mockNats = &mocks.PureNatsConnI{} suite.badNatsClient.conn = suite.mockNats suite.mockNats.On("RequestWithContext", mock.Anything, mock.AnythingOfType("string"), mock.Anything).Return(nil, errBad) err = suite.badNatsClient.Request(ctx, "testSubj", &m.DataMock{Data: []byte("mock data")}, &m.DataMock{}) - assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), errBad, errors.Cause(err), "must be equals") + assert.NotNil(suite.T(), err, "Must return an error") + assert.ErrorIs(suite.T(), err, errBad, "Error should match errBad") } diff --git a/streaming/client.go b/streaming/client.go index b1bb5b5..d9da526 100644 --- a/streaming/client.go +++ b/streaming/client.go @@ -2,23 +2,24 @@ package streaming import ( "context" - stderrors "errors" + "errors" + "fmt" "strings" "sync" "time" + "github.com/nats-io/nats.go" + "github.com/nats-io/stan.go" + "go.uber.org/zap" + "github.com/imperiuse/advanced-nats-client/v1/logger" nc "github.com/imperiuse/advanced-nats-client/v1/nats" "github.com/imperiuse/advanced-nats-client/v1/serializable" "github.com/imperiuse/advanced-nats-client/v1/uuid" - "github.com/nats-io/nats.go" - "github.com/nats-io/stan.go" - "github.com/pkg/errors" - "go.uber.org/zap" ) -// AdvanceNatsClient - advance nats / nats streaming client. -type AdvanceNatsClient interface { +// AdvancedNatsClient - advance nats / nats streaming client. +type AdvancedNatsClient interface { // NATS @see -> nc.SimpleNatsClientI Ping(context.Context, nc.Subj) (bool, error) PongHandler(nc.Subj) (*nc.Subscription, error) @@ -34,7 +35,7 @@ type AdvanceNatsClient interface { Subscribe(Subj, Serializable, Handler, ...SubscriptionOption) (Subscription, error) QueueSubscribe(Subj, QueueGroup, Serializable, Handler, ...SubscriptionOption) (Subscription, error) Reconnect(bool) error - RegisterAfterReconnectCallbackChan(chan interface{}) + RegisterAfterReconnectCallbackChan(chan any) DeregisterAfterReconnectCallbackChan() // General for both NATS and NATS Streaming @@ -55,7 +56,7 @@ type ( m sync.RWMutex sc PureNatsStunConnI // StunConnI equals stan.Conn - callbackChan chan interface{} + callbackChan chan any } // URL - url. @@ -95,7 +96,7 @@ type ( Serializable = serializable.Serializable - AfterReconnectFunc = func(anc AdvanceNatsClient) + AfterReconnectFunc = func(anc AdvancedNatsClient) ) // EmptyGUID "". @@ -121,7 +122,7 @@ var ( func New(clusterID string, clientID string, nc nc.SimpleNatsClientI, options ...Option) (*client, error) { if nc != nil { if nc.NatsConn() == nil { - return nil, errors.Wrap(ErrNilNatsConn, "[New]") + return nil, fmt.Errorf("[New]: %w", ErrNilNatsConn) } options = append(options, stan.NatsConn(nc.NatsConn())) @@ -129,7 +130,7 @@ func New(clusterID string, clientID string, nc nc.SimpleNatsClientI, options ... c, err := NewOnlyStreaming(clusterID, clientID, nil, options...) if err != nil || c == nil { - return nil, errors.Wrap(err, "[New] NewOnlyStreaming") + return nil, fmt.Errorf("[New] NewOnlyStreaming: %w", err) } c.nc = nc @@ -163,7 +164,7 @@ func NewOnlyStreaming(clusterID string, clientID string, dsn []URL, options ...O sc, err := stan.Connect(c.clusterID, c.clientID, c.options...) if err != nil { - return nil, errors.Wrap(err, "[NewOnlyStreaming] can't create nats-streaming conn") + return nil, fmt.Errorf("[NewOnlyStreaming] can't create nats-streaming conn: %w", err) } c.m.Lock() @@ -221,7 +222,7 @@ func (c *client) DefaultNatsStreamingOptions() []Option { // Ping - under the hood wrapper for nc.Ping. func (c *client) Ping(ctx context.Context, subj nc.Subj) (bool, error) { if c.nc == nil { - return false, errors.Wrap(ErrNilNatsClient, "[Ping]") + return false, fmt.Errorf("[Ping]: %w", ErrNilNatsClient) } return c.nc.Ping(ctx, subj) @@ -230,7 +231,7 @@ func (c *client) Ping(ctx context.Context, subj nc.Subj) (bool, error) { // PongHandler - under the hood wrapper for nc.PongHandler. func (c *client) PongHandler(subj nc.Subj) (*nc.Subscription, error) { if c.nc == nil { - return nil, errors.Wrap(ErrNilNatsClient, "[PongHandler]") + return nil, fmt.Errorf("[PongHandler]: %w", ErrNilNatsClient) } return c.nc.PongHandler(subj) @@ -239,16 +240,16 @@ func (c *client) PongHandler(subj nc.Subj) (*nc.Subscription, error) { // PongQueueHandler - under the hood wrapper for nc.PongQueueHandler. func (c *client) PongQueueHandler(subj nc.Subj, qgroup nc.QueueGroup) (*nc.Subscription, error) { if c.nc == nil { - return nil, errors.Wrap(ErrNilNatsClient, "[PongQueueHandler]") + return nil, fmt.Errorf("[PongQueueHandler]: %w", ErrNilNatsClient) } return c.nc.PongQueueHandler(subj, qgroup) } // Request under the hood used simple NATS connect and simple Request-Reply semantic with at most once guarantee. -func (c *client) Request(ctx context.Context, subj Subj, requestData Serializable, replyData Serializable) error { +func (c *client) Request(ctx context.Context, subj Subj, requestData, replyData Serializable) error { if c.nc == nil { - return errors.Wrap(ErrNilNatsClient, "[Request]") + return fmt.Errorf("[Request]: %w", ErrNilNatsClient) } return c.nc.Request(ctx, subj, requestData, replyData) @@ -257,7 +258,7 @@ func (c *client) Request(ctx context.Context, subj Subj, requestData Serializabl // ReplyHandler under the hood used simple Advance NATS client, Reply semantic with at most once. func (c *client) ReplyHandler(subj Subj, awaitData Serializable, msgHandler nc.Handler) (*nc.Subscription, error) { if c.nc == nil { - return nil, errors.Wrap(ErrNilNatsClient, "[ReplyHandler]") + return nil, fmt.Errorf("[ReplyHandler]: %w", ErrNilNatsClient) } return c.nc.ReplyHandler(subj, awaitData, msgHandler) @@ -266,7 +267,7 @@ func (c *client) ReplyHandler(subj Subj, awaitData Serializable, msgHandler nc.H // ReplyQueueHandler under the hood used simple Advance NATS client, Reply semantic with at most once. func (c *client) ReplyQueueHandler(subj Subj, qG QueueGroup, awD Serializable, h nc.Handler) (*nc.Subscription, error) { if c.nc == nil { - return nil, errors.Wrap(ErrNilNatsClient, "[ReplyQueueHandler]") + return nil, fmt.Errorf("[ReplyQueueHandler]: %w", ErrNilNatsClient) } return c.nc.ReplyQueueHandler(subj, qG, awD, h) @@ -292,7 +293,7 @@ func (c *client) PublishSync(subj Subj, data Serializable) error { zap.Error(err), ) - return errors.Wrap(err, "[PublishSync]") + return fmt.Errorf("[PublishSync]: %w", err) } c.m.RLock() @@ -320,7 +321,7 @@ func (c *client) PublishAsync(subj Subj, data Serializable, ah AckHandler) (GUID zap.String("subj", string(subj)), zap.Error(err)) - return EmptyGUID, errors.Wrap(err, "[PublishAsync]") + return EmptyGUID, fmt.Errorf("[PublishAsync]: %w", err) } if ah == nil { @@ -490,14 +491,14 @@ func (c *client) Reconnect(withNewClientID bool) error { sc, err := stan.Connect(c.clusterID, c.clientID, c.options...) if err != nil { - return errors.Wrap(err, "[Reconnect] can't create nats streaming connection. stan.Connect - error") + return fmt.Errorf("[Reconnect] can't create nats streaming connection. stan.Connect - error: %w", err) } c.sc = sc if c.callbackChan != nil { select { - case c.callbackChan <- new(interface{}): + case c.callbackChan <- new(any): default: c.log.Warn("[Reconnect] full callbackChan") } @@ -506,7 +507,7 @@ func (c *client) Reconnect(withNewClientID bool) error { return nil } -func (c *client) RegisterAfterReconnectCallbackChan(ch chan interface{}) { +func (c *client) RegisterAfterReconnectCallbackChan(ch chan any) { c.m.Lock() defer c.m.Unlock() @@ -527,7 +528,7 @@ func (c *client) Close() error { defer func() { if c.nc != nil { - err = stderrors.Join(err, errors.Wrap(c.nc.Close(), "c.nc.Close")) + err = errors.Join(err, fmt.Errorf("c.nc.Close: %w", c.nc.Close())) } }() @@ -537,7 +538,7 @@ func (c *client) Close() error { if c.sc != nil { err = c.sc.Close() if err != nil { - err = errors.Wrap(err, "c.sc.Close") + err = fmt.Errorf("c.sc.Close: %w", err) return err } diff --git a/streaming/client_test.go b/streaming/client_test.go index 3d432e2..8e19cf8 100644 --- a/streaming/client_test.go +++ b/streaming/client_test.go @@ -1,6 +1,6 @@ package streaming -// TODO INTEGRATION MUST DO TEST FOR TESTING RECONNECT BEHAVIOR +// TODO INTEGRATION: MUST CREATE TESTS FOR RECONNECT BEHAVIOR import ( "context" @@ -23,29 +23,28 @@ import ( var testDSN = []URL{"nats://127.0.0.1:4223"} -type NatsStreamingClientTestSuit struct { +type NatsStreamingClientTestSuite struct { suite.Suite ctx context.Context ctxCancel context.CancelFunc - streamingClient AdvanceNatsClient + streamingClient AdvancedNatsClient badStreamingClient *client mockStanConn *mocks.PureNatsStunConnI } -// The SetupSuite method will be run by testify once, at the very -// start of the testing suite, before any tests are run. -func (suite *NatsStreamingClientTestSuit) SetupSuite() { +// SetupSuite is called once, before any tests in the suite are run. +func (suite *NatsStreamingClientTestSuite) SetupSuite() { c, err := NewOnlyStreaming("bad_name_cluster", uuid.UUID4(), []URL{"1.2.3.4:1234"}) - assert.NotNil(suite.T(), err, "must be error!") + assert.NotNil(suite.T(), err, "must be an error!") assert.Nil(suite.T(), c, "must be nil!") c, err = NewOnlyStreaming("bad_name_cluster", uuid.UUID4(), testDSN) - assert.NotNil(suite.T(), err, "must be error!") + assert.NotNil(suite.T(), err, "must be an error!") assert.Nil(suite.T(), c, "must be nil!") c, err = NewOnlyStreaming(DefaultClusterID, uuid.UUID4(), testDSN) - assert.Nil(suite.T(), err, "err must be nil!") - assert.NotNil(suite.T(), c, "client be not nil!") + assert.Nil(suite.T(), err, "error must be nil!") + assert.NotNil(suite.T(), c, "client must not be nil!") assert.Nil(suite.T(), c.nc, "nc must be nil!") assert.Nil(suite.T(), c.NatsConn(), "NatsConn nc must be nil!") assert.Nil(suite.T(), c.Nats(), "Nats nc must be nil!") @@ -54,37 +53,31 @@ func (suite *NatsStreamingClientTestSuit) SetupSuite() { badNatsClient := nc.NewDefaultClient() c1, err := New(DefaultClusterID, uuid.UUID4(), badNatsClient) - assert.Equal(suite.T(), ErrNilNatsConn, errors.Cause(err)) + assert.ErrorIs(suite.T(), err, ErrNilNatsConn) assert.Nil(suite.T(), c1, "client must be nil!") natsClient, err := nc.New(testDSN) - assert.Nil(suite.T(), err, "err must be nil") - assert.NotNil(suite.T(), natsClient, "natsClient must be non nil") + assert.Nil(suite.T(), err, "error must be nil") + assert.NotNil(suite.T(), natsClient, "natsClient must not be nil") suite.streamingClient, err = New(DefaultClusterID, uuid.UUID4(), natsClient) - assert.Nil(suite.T(), err, "err must be nil!") - assert.NotNil(suite.T(), suite.streamingClient, "client be not nil!") + assert.Nil(suite.T(), err, "error must be nil!") + assert.NotNil(suite.T(), suite.streamingClient, "client must not be nil!") assert.NotNil(suite.T(), suite.streamingClient.NatsConn(), "NatsConn nc must not be nil!") assert.NotNil(suite.T(), suite.streamingClient.Nats(), "Nats nc must not be nil!") suite.streamingClient.UseCustomLogger(zap.NewNop()) suite.badStreamingClient, err = New(DefaultClusterID, uuid.UUID4(), natsClient) suite.badStreamingClient.UseCustomLogger(zap.NewNop()) - assert.NotNil(suite.T(), suite.badStreamingClient, "client must be non nil") - assert.Nil(suite.T(), err, "err must be nil") + assert.NotNil(suite.T(), suite.badStreamingClient, "client must not be nil") + assert.Nil(suite.T(), err, "error must be nil") mockStanConn := &mocks.PureNatsStunConnI{} suite.badStreamingClient.sc = mockStanConn suite.mockStanConn = mockStanConn - - // Mock configurations down - // NB: .Return(...) must return the same signature as the method being mocked. - //mockStanConn.On("Close").Return(nil) // Close()error - } -// The TearDownSuite method will be run by testify once, at the very -// end of the testing suite, after all tests have been run. -func (suite *NatsStreamingClientTestSuit) TearDownSuite() { +// TearDownSuite is called once, after all tests in the suite are run. +func (suite *NatsStreamingClientTestSuite) TearDownSuite() { err := suite.streamingClient.Close() assert.Nil(suite.T(), err) @@ -94,43 +87,44 @@ func (suite *NatsStreamingClientTestSuit) TearDownSuite() { assert.Nil(suite.T(), err) } -// The SetupTest method will be run before every test in the suite. -func (suite *NatsStreamingClientTestSuit) SetupTest() { +// SetupTest is called before each test. +func (suite *NatsStreamingClientTestSuite) SetupTest() { suite.ctx, suite.ctxCancel = context.WithCancel(context.Background()) } -// The TearDownTest method will be run after every test in the suite. -func (suite *NatsStreamingClientTestSuit) TearDownTest() { +// TearDownTest is called after each test. +func (suite *NatsStreamingClientTestSuite) TearDownTest() { } -// In order for 'go test' to run this suite, we need to create -// a normal test function and pass our suite to suite.Run +// TestExampleTestSuite runs the test suite. func TestExampleTestSuite(t *testing.T) { - suite.Run(t, new(NatsStreamingClientTestSuit)) + suite.Run(t, new(NatsStreamingClientTestSuite)) } -// All methods that begin with "Test" are run as tests within a suite. -func (suite *NatsStreamingClientTestSuit) Test_PublishSync() { +// Test_PublishSync checks synchronous publishing. +func (suite *NatsStreamingClientTestSuite) Test_PublishSync() { err := suite.streamingClient.PublishSync("Test_PublishSync", &mock.DataMock{Data: []byte("test_data")}) - assert.Nil(suite.T(), err, "PublishSync err") + assert.Nil(suite.T(), err, "PublishSync error") err = suite.streamingClient.PublishSync("Test_PublishSync", &mock.BadDataMock{}) - assert.NotNil(suite.T(), err, "PublishSync must return err") - assert.Equal(suite.T(), mock.ErrBadDataMock, errors.Cause(err)) + assert.NotNil(suite.T(), err, "PublishSync must return an error") + assert.ErrorIs(suite.T(), err, mock.ErrBadDataMock) } -func (suite *NatsStreamingClientTestSuit) Test_PublishAsync() { +// Test_PublishAsync checks asynchronous publishing. +func (suite *NatsStreamingClientTestSuite) Test_PublishAsync() { guid, err := suite.streamingClient.PublishAsync("Test_PublishAsync", &mock.DataMock{Data: []byte("test_data")}, nil) - assert.Nil(suite.T(), err, "PublishAsync err") + assert.Nil(suite.T(), err, "PublishAsync error") assert.NotEqual(suite.T(), EmptyGUID, guid, "GUID must not be empty") guid, err = suite.streamingClient.PublishAsync("Test_PublishAsync", &mock.BadDataMock{}, nil) - assert.NotNil(suite.T(), err, "PublishAsync must return err") - assert.Equal(suite.T(), mock.ErrBadDataMock, errors.Cause(err)) + assert.NotNil(suite.T(), err, "PublishAsync must return an error") + assert.ErrorIs(suite.T(), err, mock.ErrBadDataMock) assert.Equal(suite.T(), EmptyGUID, guid, "GUID must be empty") } -func (suite *NatsStreamingClientTestSuit) Test_Subscribe() { +// Test_Subscribe checks subscription functionality. +func (suite *NatsStreamingClientTestSuite) Test_Subscribe() { const ( cntMsg = 5 subj = "Test_Subscribe" @@ -145,52 +139,55 @@ func (suite *NatsStreamingClientTestSuit) Test_Subscribe() { if ok { assert.Equal(t, testData, string(v.Data)) } - assert.True(t, ok, "can't type cast") + assert.True(t, ok, "cannot type cast") wg.Done() } s, err := suite.streamingClient.Subscribe(subj, &mock.DataMock{}, handler) defer func() { _ = s.Close() }() - assert.Nil(t, err, "err must be nil") + assert.Nil(t, err, "error must be nil") wg.Add(cntMsg * 2) for i := 0; i < cntMsg; i++ { err := suite.streamingClient.PublishSync(subj, &mock.DataMock{Data: []byte(testData)}) - assert.Nil(t, err, "PublishSync err") + assert.Nil(t, err, "PublishSync error") guid, err := suite.streamingClient.PublishAsync(subj, &mock.DataMock{Data: []byte(testData)}, nil) - assert.Nil(t, err, "PublishAsync err") + assert.Nil(t, err, "PublishAsync error") assert.NotEqual(t, EmptyGUID, guid, "GUID must not be empty") } wg.Wait() } -func (suite *NatsStreamingClientTestSuit) Test_BadPublish() { +// Test_BadPublish tests publishing when there is an error. +func (suite *NatsStreamingClientTestSuite) Test_BadPublish() { errBad := errors.New("bad") suite.mockStanConn.On("Publish", mock2.AnythingOfType("string"), mock2.Anything).Return(errBad) suite.mockStanConn.On("PublishAsync", mock2.AnythingOfType("string"), mock2.Anything, mock2.Anything).Return(EmptyGUID, errBad) err := suite.badStreamingClient.PublishSync("testSubj", &mock.DataMock{Data: []byte("test_data")}) - assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), errBad, errors.Cause(err), "must be equals") + assert.NotNil(suite.T(), err, "must be an error") + assert.ErrorIs(suite.T(), err, errBad, "must be equal") guid, err := suite.badStreamingClient.PublishAsync("testSubj", &mock.DataMock{Data: []byte("test_data")}, suite.badStreamingClient.DefaultAckHandler()) - assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), errBad, err, "must be equals") - assert.Equal(suite.T(), EmptyGUID, guid, "must be equals") + assert.NotNil(suite.T(), err, "must be an error") + assert.Equal(suite.T(), errBad, err, "must be equal") + assert.Equal(suite.T(), EmptyGUID, guid, "must be equal") } -func (suite *NatsStreamingClientTestSuit) Test_BadSubscribe() { +// Test_BadSubscribe tests subscription with an error. +func (suite *NatsStreamingClientTestSuite) Test_BadSubscribe() { errBad := errors.New("bad") - suite.mockStanConn.On("Subscribe", mock2.AnythingOfType("string"), mock2.AnythingOfType("MsgHandler"), mock2.AnythingOfType("SubscriptionOption")).Return(nil, errBad) // Subscribe(subj string, cb MsgHandler) (*Subscription, error) + suite.mockStanConn.On("Subscribe", mock2.AnythingOfType("string"), mock2.AnythingOfType("MsgHandler"), mock2.AnythingOfType("SubscriptionOption")).Return(nil, errBad) s, err := suite.badStreamingClient.Subscribe("testSubj", &mock.DataMock{}, EmptyHandler) assert.Nil(suite.T(), s, "must be nil") - assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), errBad, errors.Cause(err), "must be equals") + assert.NotNil(suite.T(), err, "must be an error") + assert.Equal(suite.T(), err, errBad, "must be equal") } -func (suite *NatsStreamingClientTestSuit) Test_PingPongDummyTest() { +// Test_PingPongDummyTest tests ping-pong functionality. +func (suite *NatsStreamingClientTestSuite) Test_PingPongDummyTest() { const ( subj = "Test_PingPongDummyTest" queue = subj @@ -257,7 +254,7 @@ func (suite *NatsStreamingClientTestSuit) Test_PingPongDummyTest() { assert.False(suite.T(), result, "Ping must be false") } -func (suite *NatsStreamingClientTestSuit) Test_RequestDummyTest() { +func (suite *NatsStreamingClientTestSuite) Test_RequestDummyTest() { const ( timeout = time.Second subj = "Test_RequestDummyTest" @@ -286,7 +283,7 @@ func (suite *NatsStreamingClientTestSuit) Test_RequestDummyTest() { wg.Wait() } -func (suite *NatsStreamingClientTestSuit) Test_RequestQueueDummyTest() { +func (suite *NatsStreamingClientTestSuite) Test_RequestQueueDummyTest() { const ( timeout = time.Second subj = "Test_RequestQueueDummyTest" @@ -331,26 +328,26 @@ func (suite *NatsStreamingClientTestSuit) Test_RequestQueueDummyTest() { assert.Equal(suite.T(), 1, int(cnt.Load())) } -func (suite *NatsStreamingClientTestSuit) Test_CheckNilNatsClient() { +func (suite *NatsStreamingClientTestSuite) Test_CheckNilNatsClient() { c := client{} _, err := c.ReplyHandler("", &mock.DataMock{}, nil) - assert.Equal(suite.T(), ErrNilNatsClient, errors.Cause(err)) + assert.ErrorIs(suite.T(), err, ErrNilNatsClient) err = c.Request(context.Background(), "", &mock.DataMock{}, &mock.DataMock{}) - assert.Equal(suite.T(), ErrNilNatsClient, errors.Cause(err)) + assert.ErrorIs(suite.T(), err, ErrNilNatsClient) _, err = c.PongHandler("") - assert.Equal(suite.T(), ErrNilNatsClient, errors.Cause(err)) + assert.ErrorIs(suite.T(), err, ErrNilNatsClient) _, err = c.Ping(context.Background(), "") - assert.Equal(suite.T(), ErrNilNatsClient, errors.Cause(err)) + assert.ErrorIs(suite.T(), err, ErrNilNatsClient) _, err = c.PongQueueHandler("", "") - assert.Equal(suite.T(), ErrNilNatsClient, errors.Cause(err)) + assert.ErrorIs(suite.T(), err, ErrNilNatsClient) } -func (suite *NatsStreamingClientTestSuit) Test_QueueSubscribe() { +func (suite *NatsStreamingClientTestSuite) Test_QueueSubscribe() { const ( cntMsg = 5 data = "data" @@ -413,7 +410,7 @@ func (suite *NatsStreamingClientTestSuit) Test_QueueSubscribe() { wgQ3.Wait() } -func (suite *NatsStreamingClientTestSuit) Test_QueueSubscribeSerializable() { +func (suite *NatsStreamingClientTestSuite) Test_QueueSubscribeSerializable() { const ( cntMsg = 5 data = "data" @@ -449,12 +446,12 @@ func (suite *NatsStreamingClientTestSuit) Test_QueueSubscribeSerializable() { wg.Wait() } -func (suite *NatsStreamingClientTestSuit) Test_BadQueueSubscriber() { +func (suite *NatsStreamingClientTestSuite) Test_BadQueueSubscriber() { errBad := errors.New("bad") suite.mockStanConn.On("QueueSubscribe", mock2.AnythingOfType("string"), mock2.AnythingOfType("string"), mock2.Anything, mock2.Anything).Return(nil, errBad) // Subscribe(subj string, cb MsgHandler) (*Subscription, error) s, err := suite.badStreamingClient.QueueSubscribe("testSubj", "testQ", &mock.DataMock{}, EmptyHandler) assert.Nil(suite.T(), s, "must be nil") assert.NotNil(suite.T(), err, "must be err") - assert.Equal(suite.T(), errBad, errors.Cause(err), "must be equals") + assert.Equal(suite.T(), err, errBad, "must be equals") } diff --git a/uuid/uuid.go b/uuid/uuid.go index ee635a3..e3e5fe7 100644 --- a/uuid/uuid.go +++ b/uuid/uuid.go @@ -1,19 +1,18 @@ package uuid import ( - "fmt" - "github.com/gofrs/uuid" - "github.com/imperiuse/advanced-nats-client/v1/logger" "go.uber.org/zap" + + "github.com/imperiuse/advanced-nats-client/v1/logger" ) type ( - // UUID = uuid.UUID. + // UUID is an alias for uuid.UUID. UUID = uuid.UUID ) -// EmptyStringUUID = all zero. +// EmptyStringUUID is a UUID string with all zeroes. var ( EmptyStringUUID = "00000000-0000-0000-0000-000000000000" EmptyStringUUIDb = [16]byte{ @@ -21,33 +20,34 @@ var ( } ) -// MustUUID4 - YES it's panic, use in init or example case only! Please be carefully! +// MustUUID4 generates a UUID v4. It panics in case of an error. Use only in initialization or example cases. +// Please be cautious with this function! func MustUUID4() string { uid, err := uuid.NewV4() if err != nil { panic(err) } - return fmt.Sprint(uid) + return uid.String() } -// UUID4 - return string presentation of UUID ver4 use uuid.NewV4() under the hood. +// UUID4 returns a string representation of a UUID v4 using uuid.NewV4() under the hood. func UUID4() string { uid, err := uuid.NewV4() if err != nil { - logger.Log.Error("UUID V4 generate error", zap.Error(err)) + logger.Log.Error("UUID v4 generation error", zap.Error(err)) return EmptyStringUUID } - return fmt.Sprint(uid) + return uid.String() } -// UUID4b - return [16]byte presentation of UUID ver4 use uuid.NewV4() under the hood. +// UUID4b returns a [16]byte representation of a UUID v4 using uuid.NewV4() under the hood. func UUID4b() [16]byte { uid, err := uuid.NewV4() if err != nil { - logger.Log.Error("UUID V4 generate error", zap.Error(err)) + logger.Log.Error("UUID v4 generation error", zap.Error(err)) return EmptyStringUUIDb }