diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index be686a73c8c7..9bfa6efaef42 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,3 +8,12 @@ The updates happen at least automatically once a week (Sunday 11am UTC). No pull requests to update a linter will be accepted unless you are the author of the linter AND specific changes are required. --> + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 32b46fe168b1..1e4618407dd5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,6 +10,7 @@ updates: # Ignore forked linters because of their versioning issues. - dependency-name: "github.com/golangci/dupl" - dependency-name: "github.com/golangci/gofmt" + - dependency-name: "github.com/golangci/swaggoswag" - dependency-name: "github.com/golangci/unconvert" - package-ecosystem: github-actions directory: "/" @@ -37,6 +38,7 @@ updates: - "*" # Group all updates into a single larger pull request. - package-ecosystem: gomod directories: + - pkg/golinters/arangolint/testdata/ - pkg/golinters/ginkgolinter/testdata/ - pkg/golinters/loggercheck/testdata/ - pkg/golinters/protogetter/testdata/ diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index f3f967eb669d..f5c69841abef 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -27,21 +27,22 @@ jobs: git diff --exit-code go.mod git diff --exit-code go.sum + # This check is disabled because of GitHub API instability: 504 Gateway Timeout. # Checks: GitHub action assets - check-generated: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: actions/setup-go@v5 - with: - go-version: ${{ env.GO_VERSION }} - - name: Check generated files are up-to-date - run: make fast_check_generated - env: - # needed for github-action-config.json generation - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# check-generated: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 +# - uses: actions/setup-go@v5 +# with: +# go-version: ${{ env.GO_VERSION }} +# - name: Check generated files are up-to-date +# run: make fast_check_generated +# env: +# # needed for github-action-config.json generation +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} check-local-install-script: name: Installation script (local) @@ -88,7 +89,6 @@ jobs: - run: ./golangci-lint config - run: ./golangci-lint config path - run: ./golangci-lint config path --json - # TODO(ldez) after v2: golangci.next.jsonschema.json -> golangci.jsonschema.json - run: ./golangci-lint config verify --schema jsonschema/golangci.next.jsonschema.json - run: ./golangci-lint help diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 3393ae3bc1ee..5f5606e97835 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -40,11 +40,10 @@ jobs: # - 1.18beta1 -> 1.18.0-beta.1 # - 1.18rc1 -> 1.18.0-rc.1 go-version: ${{ env.GO_VERSION }} - # TODO(ldez): must add uncommented when golangci-lint-action@v7.0.0 (with golangci-lint v2 support) will be created. -# - name: lint -# uses: golangci/golangci-lint-action@v6.5.0 -# with: -# version: latest + - name: lint + uses: golangci/golangci-lint-action@v8.0.0 + with: + version: latest tests-on-windows: needs: golangci-lint # run after golangci-lint action to not produce duplicated errors diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e807c3aeaeb3..0a75cb50cfe3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,7 +69,7 @@ jobs: - name: Create release uses: goreleaser/goreleaser-action@v6 with: - version: latest + version: v2.8.1 args: release --clean --timeout=90m env: AUR_KEY: ${{ secrets.AUR_KEY }} diff --git a/.golangci.next.reference.yml b/.golangci.next.reference.yml index ff5b11d64865..3e7ac7eaca0d 100644 --- a/.golangci.next.reference.yml +++ b/.golangci.next.reference.yml @@ -4,17 +4,23 @@ # This file is not a configuration example, # it contains the exhaustive configuration with explanations of the options. +# Defines the configuration version. +# The only possible value is "2". version: "2" linters: # Default set of linters. - # The value can be: `standard`, `all`, `none`, or `fast`. + # The value can be: + # - `standard`: https://golangci-lint.run/usage/linters/#enabled-by-default + # - `all`: enables all linters by default. + # - `none`: disables all linters by default. + # - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`). # Default: standard default: all # Enable specific linter. - # https://golangci-lint.run/usage/linters/#enabled-by-default enable: + - arangolint - asasalint - asciicheck - bidichk @@ -30,6 +36,7 @@ linters: - dupl - dupword - durationcheck + - embeddedstructfieldcheck - err113 - errcheck - errchkjson @@ -41,8 +48,8 @@ linters: - fatcontext - forbidigo - forcetypeassert + - funcorder - funlen - - gci - ginkgolinter - gocheckcompilerdirectives - gochecknoglobals @@ -54,10 +61,7 @@ linters: - gocyclo - godot - godox - - gofmt - - gofumpt - goheader - - goimports - gomoddirectives - gomodguard - goprintffuncname @@ -87,6 +91,7 @@ linters: - nilnil - nlreturn - noctx + - noinlineerr - nolintlint - nonamedreturns - nosprintfhostport @@ -123,9 +128,9 @@ linters: - wsl - zerologlint - # Disable specific linter - # https://golangci-lint.run/usage/linters/#disabled-by-default + # Disable specific linters. disable: + - arangolint - asasalint - asciicheck - bidichk @@ -141,6 +146,7 @@ linters: - dupl - dupword - durationcheck + - embeddedstructfieldcheck - err113 - errcheck - errchkjson @@ -152,8 +158,8 @@ linters: - fatcontext - forbidigo - forcetypeassert + - funcorder - funlen - - gci - ginkgolinter - gocheckcompilerdirectives - gochecknoglobals @@ -165,10 +171,7 @@ linters: - gocyclo - godot - godox - - gofmt - - gofumpt - goheader - - goimports - gomoddirectives - gomodguard - goprintffuncname @@ -198,6 +201,7 @@ linters: - nilnil - nlreturn - noctx + - noinlineerr - nolintlint - nonamedreturns - nosprintfhostport @@ -272,7 +276,7 @@ linters: # Default: 10 max-complexity: 10 # The maximal average package complexity. - # If it's higher than 0.0 (float) the check is enabled + # If it's higher than 0.0 (float) the check is enabled. # Default: 0.0 package-average: 0.5 @@ -285,7 +289,7 @@ linters: - var - func - # If true, underscore vars (vars with "_" as the name) will be ignored at all checks + # 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 @@ -301,15 +305,15 @@ linters: # Default: true (disabled) disable-dec-num-check: false - # If true, type declarations will be ignored for dec num check + # 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 + # 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 + # If true, var declarations will be ignored for dec num check. # Default: false (var statements are not ignored) disable-var-dec-num-check: false @@ -341,6 +345,7 @@ linters: # List of file globs that will match this list of settings to compare against. # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. + # The placeholder '${config-path}' is substituted with a path relative to the configuration file. # Default: $all files: - "!**/*_a _file.go" @@ -384,6 +389,11 @@ linters: ignore: - "0C0C" + embeddedstructfieldcheck: + # Checks that sync.Mutex and sync.RWMutex are not used as embedded fields. + # Default: false + forbid-mutex: true + errcheck: # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. # Such cases aren't reported by default. @@ -407,6 +417,10 @@ linters: - io.Copy(*bytes.Buffer) - io.Copy(os.Stdout) + # Display function signature instead of selector. + # Default: false + verbose: true + errchkjson: # With check-error-free-encoding set to true, errchkjson does warn about errors # from json encoding functions that are safe to be ignored, @@ -415,11 +429,12 @@ linters: # 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 + # linters: + # settings: + # errcheck: + # exclude-functions: + # - encoding/json.Marshal + # - encoding/json.MarshalIndent # # Default: false check-error-free-encoding: true @@ -433,7 +448,7 @@ linters: # See the https://github.com/polyfloyd/go-errorlint for caveats. # Default: true errorf: false - # Permit more than 1 %w verb, valid per Go 1.20 (Requires 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. @@ -513,7 +528,7 @@ linters: # Optional message that gets included in error reports. - pattern: ^fmt\.Print.*$ msg: Do not commit print statements. - # Alternatively, put messages at the end of the regex, surrounded by `(# )?` + # Alternatively, put messages at the end of the regex, surrounded by `(# )?`. # Escape any special characters. Those messages get included in error reports. - pattern: 'fmt\.Print.*(# Do not commit print statements\.)?' # Forbid spew Dump, whether it is called as function or method. @@ -534,6 +549,17 @@ linters: # Default: false analyze-types: true + funcorder: + # Checks that constructors are placed after the structure declaration. + # Default: true + constructor: false + # Checks if the exported methods of a structure are placed before the non-exported ones. + # Default: true + struct-method: false + # Checks if the constructors and/or structure methods are sorted alphabetically. + # Default: false + alphabetical: true + funlen: # Checks the number of lines in a function. # If lower than 0, disable the check. @@ -568,11 +594,11 @@ linters: # Default: false suppress-async-assertion: true - # Suppress warning for comparing values from different types, like `int32` and `uint32` + # Suppress warning for comparing values from different types, like `int32` and `uint32`. # Default: false suppress-type-compare-assertion: true - # Trigger warning for ginkgo focus containers like `FDescribe`, `FContext`, `FWhen` or `FIt` + # Trigger warning for ginkgo focus containers like `FDescribe`, `FContext`, `FWhen` or `FIt`. # Default: false forbid-focus-container: true @@ -586,7 +612,7 @@ linters: force-expect-to: true # Best effort validation of async intervals (timeout and polling). - # Ignored the suppress-async-assertion is true. + # Ignored the `suppress-async-assertion` is true. # Default: false validate-async-intervals: true @@ -602,7 +628,7 @@ linters: # Presence of `default` case in switch statements satisfies exhaustiveness, if all members are not listed. # Default: true default-signifies-exhaustive: false - # Include shared interfaces in the exhaustiviness check. + # Include shared interfaces in the exhaustiveness check. # Default: false include-shared-interfaces: true @@ -624,10 +650,10 @@ linters: # Search also for duplicated numbers. # Default: false numbers: true - # Minimum value, only works with goconst.numbers + # Minimum value, only works with `goconst.numbers`. # Default: 3 min: 2 - # Maximum value, only works with goconst.numbers + # Maximum value, only works with `goconst.numbers`. # Default: 3 max: 2 # Ignore when constant is not used as function argument. @@ -635,7 +661,14 @@ linters: ignore-calls: false # Exclude strings matching the given regular expression. # Default: "" - ignore-strings: 'foo.+' + ignore-string-values: + - 'foo.+' + # Detects constants with identical values. + # Default: false + find-duplicates: true + # Evaluates of constant expressions like Prefix + "suffix". + # Default: false + eval-const-expressions: true gocritic: # Disable all checks. @@ -1100,7 +1133,7 @@ linters: # 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.com/overview. + # The list of supported checkers can be found at https://go-critic.com/overview. settings: # Must be valid enabled check name. captLocal: @@ -1166,6 +1199,7 @@ linters: # Comma-separated list of file paths containing ruleguard rules. # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. + # The placeholder '${config-path}' is substituted with a path relative to the configuration file. # Glob patterns such as 'rules-*.go' may be specified. # Default: "" rules: '${base-path}/ruleguard/rules-*.go,${base-path}/myrule1.go' @@ -1239,19 +1273,19 @@ linters: # for example: AUTHOR: .*@mycompany\.com # The template used for checking. - # Put here copyright header template for source code files + # Put here copyright header template for source code files. # Note: {{ YEAR }} is a builtin value that returns the year relative to the current machine time. # 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. @@ -1261,6 +1295,7 @@ linters: # Useful if you need to load the template from a specific file. # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. + # The placeholder '${config-path}' is substituted with a path relative to the configuration file. # Default: "" template-path: /path/to/my/template.tmpl @@ -1278,6 +1313,9 @@ linters: # Forbid the use of the `exclude` directives. # Default: false exclude-forbidden: true + # Forbid the use of the `ignore` directives (>= go1.25). + # Default: false + ignore-forbidden: true # Forbid the use of the `toolchain` directive. # Default: false toolchain-forbidden: true @@ -1344,7 +1382,6 @@ linters: - 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 - G115 # Potential integer overflow when converting between integer types - G201 # SQL query construction using format string @@ -1389,7 +1426,6 @@ linters: - 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 - G115 # Potential integer overflow when converting between integer types - G201 # SQL query construction using format string @@ -1499,13 +1535,13 @@ linters: # 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 + # Maximum allowed permissions mode for os.Mkdir and os.MkdirAll. # Default: "0750" G301: "0750" - # Maximum allowed permissions mode for os.OpenFile and os.Chmod + # Maximum allowed permissions mode for os.OpenFile and os.Chmod. # Default: "0600" G302: "0600" - # Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile + # Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile. # Default: "0600" G306: "0600" @@ -1541,7 +1577,7 @@ linters: # Default: false disable-all: true # Enable analyzers by name. - # (in addition to default: + # (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, @@ -1584,6 +1620,10 @@ linters: - findcall # Report assembly that clobbers the frame pointer before saving it. - framepointer + # Check format of addresses passed to net.Dial. + - hostport + # Report using Go 1.22 enhanced ServeMux patterns in older Go versions. + - httpmux # Check for mistakes using HTTP responses. - httpresponse # Detect impossible interface-to-interface type assertions. @@ -1641,7 +1681,7 @@ linters: # Default: false enable-all: true # Disable analyzers by name. - # (in addition to default + # (In addition to default # atomicalign, deepequalerrors, fieldalignment, findcall, nilness, reflectvaluecompare, shadow, sortslice, # timeformat, unusedwrite # ). @@ -1665,6 +1705,8 @@ linters: - fieldalignment - findcall - framepointer + - hostport + - httpmux - httpresponse - ifaceassert - loopclosure @@ -1708,16 +1750,16 @@ linters: # Default: false strict: true unusedresult: - # Comma-separated list of functions whose results must be used - # (in addition to default: + # 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: - pkg.MyFunc - # Comma-separated list of names of methods of type func() string whose results must be used - # (in addition to default Error,String) + # Comma-separated list of names of methods of type func() string whose results must be used. + # (In addition to default Error,String). # Default: [] stringmethods: - MyMethod @@ -1758,6 +1800,7 @@ linters: - identical # Identifies interfaces in the same package that have identical method sets. - unused # Identifies interfaces that are not used anywhere in the same package where the interface is defined. - opaque # Identifies functions that return interfaces, but the actual returned value is always a single concrete implementation. + - unexported # Identifies interfaces that are not exported but are used in exported functions or methods. settings: unused: # List of packages path to exclude from the check. @@ -1783,7 +1826,7 @@ linters: 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 + # See https://github.com/julz/importas#use-regular-expression for details. - pkg: knative.dev/serving/pkg/apis/(\w+)/(v[\w\d]+) alias: $1$2 # An explicit empty alias can be used to ensure no aliases are used for a package. @@ -1922,14 +1965,14 @@ linters: - 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" + # 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` + # Values always ignored: `.+_test.go`. # Default: [] ignored-files: - 'magic1_.+\.go$' @@ -1984,7 +2027,7 @@ linters: - unsafeptr nlreturn: - # Size of the block (including return statement that is still "OK") + # Size of the block (including return statement that is still "OK"), # so no return split required. # Default: 1 block-size: 2 @@ -2174,10 +2217,10 @@ linters: disabled: false exclude: [""] arguments: - - maxLitCount: "3" - allowStrs: '""' - allowInts: "0,1,2" - allowFloats: "0.0,0.,1.0,1.,2.0,2." + - max-lit-count: "3" + allow-strs: '""' + allow-ints: "0,1,2" + allow-floats: "0.0,0.,1.0,1.,2.0,2." # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#argument-limit - name: argument-limit severity: warning @@ -2256,7 +2299,7 @@ linters: disabled: false exclude: [""] arguments: - - allowTypesBefore: "*testing.T,*github.com/user/repo/testing.Harness" + - allow-types-before: "*testing.T,*github.com/user/repo/testing.Harness" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#context-keys-type - name: context-keys-type severity: warning @@ -2296,7 +2339,7 @@ linters: disabled: false exclude: [""] arguments: - - allowedPackages: ["github.com/onsi/ginkgo/v2", "github.com/onsi/gomega"] + - allowed-packages: ["github.com/onsi/ginkgo/v2", "github.com/onsi/gomega"] # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#duplicated-imports - name: duplicated-imports severity: warning @@ -2308,8 +2351,8 @@ linters: disabled: false exclude: [""] arguments: - - "preserveScope" - - "allowJump" + - "preserve-scope" + - "allow-jump" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#empty-block - name: empty-block severity: warning @@ -2335,8 +2378,8 @@ linters: arguments: - "short" # Or this parameter: - - funcArgStyle: "full" - funcRetValStyle: "short" + - func-arg-style: "full" + func-ret-val-style: "short" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#enforce-slice-style - name: enforce-slice-style severity: warning @@ -2372,15 +2415,15 @@ linters: disabled: false exclude: [""] arguments: - - "checkPrivateReceivers" - - "disableStutteringCheck" - - "sayRepetitiveInsteadOfStutters" - - "checkPublicInterface" - - "disableChecksOnConstants" - - "disableChecksOnFunctions" - - "disableChecksOnMethods" - - "disableChecksOnTypes" - - "disableChecksOnVariables" + - "check-private-receivers" + - "disable-stuttering-check" + - "say-repetitive-instead-of-stutters" + - "check-public-interface" + - "disable-checks-on-constants" + - "disable-checks-on-functions" + - "disable-checks-on-methods" + - "disable-checks-on-types" + - "disable-checks-on-variables" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#file-header - name: file-header severity: warning @@ -2395,8 +2438,8 @@ linters: exclude: [""] arguments: - max: 100 - skipComments: true - skipBlankLines: true + skip-comments: true + skip-blank-lines: true # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#filename-format - name: filename-format severity: warning @@ -2444,8 +2487,8 @@ linters: arguments: - "^[a-z][a-z0-9]{0,}$" # Or this parameter: - - allowRegex: "^[a-z][a-z0-9]{0,}$" - denyRegex: '^v\d+$' + - allow-regex: "^[a-z][a-z0-9]{0,}$" + deny-regex: '^v\d+$' # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#import-shadowing - name: import-shadowing severity: warning @@ -2470,7 +2513,7 @@ linters: disabled: false exclude: [""] arguments: - - "preserveScope" + - "preserve-scope" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#line-length-limit - name: line-length-limit severity: warning @@ -2535,7 +2578,7 @@ linters: disabled: false exclude: [""] arguments: - - maxLength: 2 + - max-length: 2 # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#redefines-builtin-id - name: redefines-builtin-id severity: warning @@ -2551,6 +2594,11 @@ linters: severity: warning disabled: false exclude: [""] + # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#redundant-test-main-exit + - name: redundant-test-main-exit + severity: warning + disabled: false + exclude: [""] # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#string-format - name: string-format severity: warning @@ -2585,7 +2633,12 @@ linters: disabled: false exclude: [""] arguments: - - "preserveScope" + - "preserve-scope" + # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#time-date + - name: time-date + severity: warning + disabled: false + exclude: [""] # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#time-equal - name: time-equal severity: warning @@ -2602,7 +2655,7 @@ linters: disabled: false exclude: [""] arguments: - - acceptIgnoredAssertionResult: true + - accept-ignored-assertion-result: true # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#unconditional-recursion - name: unconditional-recursion severity: warning @@ -2626,6 +2679,11 @@ linters: arguments: - "fmt.Printf" - "myFunction" + # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#unnecessary-format + - name: unnecessary-format + severity: warning + disabled: false + exclude: [""] # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#unnecessary-stmt - name: unnecessary-stmt severity: warning @@ -2642,14 +2700,14 @@ linters: disabled: false exclude: [""] arguments: - - allowRegex: "^_" + - allow-regex: "^_" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#unused-receiver - name: unused-receiver severity: warning disabled: false exclude: [""] arguments: - - allowRegex: "^_" + - allow-regex: "^_" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#use-any - name: use-any severity: warning @@ -2660,6 +2718,11 @@ linters: severity: warning disabled: false exclude: [""] + # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#use-fmt-print + - name: use-fmt-print + severity: warning + disabled: false + exclude: [""] # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#useless-break - name: useless-break severity: warning @@ -2678,7 +2741,7 @@ linters: arguments: - [ "ID" ] # AllowList - [ "VM" ] # DenyList - - - upperCaseConst: true # Extra parameter (upperCaseConst|skipPackageNameChecks) + - - upper-case-const: true # Extra parameter (upper-case-const|skip-package-name-checks) # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#waitgroup-by-value - name: waitgroup-by-value severity: warning @@ -2686,7 +2749,7 @@ linters: exclude: [""] rowserrcheck: - # database/sql is always checked + # database/sql is always checked. # Default: [] packages: - github.com/jmoiron/sqlx @@ -2724,11 +2787,16 @@ linters: # https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages # Default: false static-msg: true + # Enforce message style. + # Values: lowercased, capitalized + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#message-style + # Default: "" + msg-style: capitalized # 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: true - # Enforce a single key naming convention. + # Enforce key naming convention. # Values: snake, kebab, camel, pascal # https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention # Default: "" @@ -2785,6 +2853,7 @@ linters: http-status-code-whitelist: [ "200", "400", "404", "500" ] # SAxxxx checks in https://staticcheck.dev/docs/configuration/options/#checks # Example (to disable some checks): [ "all", "-SA1000", "-SA1001"] + # Run `GL_DEBUG=staticcheck golangci-lint run --enable=staticcheck` to see all available checks and enabled by config checks. # Default: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"] checks: # Invalid regular expression. @@ -3272,7 +3341,7 @@ linters: # Align and sort can be used together or separately. # # Whether enable align. If true, the struct tags will be aligned. - # e.g.: + # E.g.: # type FooBar struct { # Bar string `json:"bar" validate:"required"` # FooFoo int8 `json:"foo_foo" validate:"required"` @@ -3286,7 +3355,7 @@ linters: 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"` + # 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. @@ -3400,12 +3469,6 @@ linters: # Default: false ignore: true - 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 @@ -3574,6 +3637,9 @@ linters: # Suggest the use of http.StatusXX. # Default: true http-status-code: false + # Suggest the use of time.Month in time.Date. + # Default: false + time-date-month: true # Suggest the use of time.Weekday.String(). # Default: true time-weekday: true @@ -3763,6 +3829,9 @@ linters: # Default: [] ignore-interface-regexps: - ^(?i)c(?-i)ach(ing|e) + # Determines whether wrapcheck should report errors returned from inside the package. + # Default: false + report-internal-errors: true wsl: # Do strict checking when assigning from append (x = append(x, y)). @@ -3879,8 +3948,8 @@ linters: # - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc. # - `disable`: disable the generated files exclusion. # - # Default: lax - generated: strict + # Default: strict + generated: lax # Log a warning if an exclusion rule is unused. # Default: false warn-unused: true @@ -3946,13 +4015,14 @@ formatters: - gofumpt - goimports - golines + - swaggo # Formatters settings. settings: gci: # 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`, + # 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: @@ -4027,6 +4097,9 @@ formatters: chain-split-dots: false exclusions: + # Log a warning if an exclusion path is unused. + # Default: false + warn-unused: true # Mode of the generated files analysis. # # - `strict`: sources are excluded by strictly following the Go generated file convention. @@ -4039,6 +4112,7 @@ formatters: # Default: lax generated: strict # Which file paths to exclude. + # This option is ignored when using `--stdin` as the path is unknown. # Default: [] paths: - ".*\\.my\\.go$" @@ -4160,9 +4234,16 @@ output: path: ./path/to/output.json # Add a prefix to the output file references. + # This option is ignored when using `output.path-mode: abs` mode. # Default: "" path-prefix: "" + # By default, the report are related to the path obtained by `run.relative-path-mode`. + # The mode `abs` allows to show absolute file paths instead of relative file paths. + # The option `output.path-prefix` is ignored when using `abs` mode. + # Default: "" + path-mode: "abs" + # Order to use when sorting results. # Possible values: `file`, `linter`, and `severity`. # diff --git a/.golangci.reference.yml b/.golangci.reference.yml index ff5b11d64865..38b1d26ed729 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -4,16 +4,21 @@ # This file is not a configuration example, # it contains the exhaustive configuration with explanations of the options. +# Defines the configuration version. +# The only possible value is "2". version: "2" linters: # Default set of linters. - # The value can be: `standard`, `all`, `none`, or `fast`. + # The value can be: + # - `standard`: https://golangci-lint.run/usage/linters/#enabled-by-default + # - `all`: enables all linters by default. + # - `none`: disables all linters by default. + # - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`). # Default: standard default: all # Enable specific linter. - # https://golangci-lint.run/usage/linters/#enabled-by-default enable: - asasalint - asciicheck @@ -41,8 +46,8 @@ linters: - fatcontext - forbidigo - forcetypeassert + - funcorder - funlen - - gci - ginkgolinter - gocheckcompilerdirectives - gochecknoglobals @@ -54,10 +59,7 @@ linters: - gocyclo - godot - godox - - gofmt - - gofumpt - goheader - - goimports - gomoddirectives - gomodguard - goprintffuncname @@ -123,8 +125,7 @@ linters: - wsl - zerologlint - # Disable specific linter - # https://golangci-lint.run/usage/linters/#disabled-by-default + # Disable specific linter. disable: - asasalint - asciicheck @@ -152,8 +153,8 @@ linters: - fatcontext - forbidigo - forcetypeassert + - funcorder - funlen - - gci - ginkgolinter - gocheckcompilerdirectives - gochecknoglobals @@ -165,10 +166,7 @@ linters: - gocyclo - godot - godox - - gofmt - - gofumpt - goheader - - goimports - gomoddirectives - gomodguard - goprintffuncname @@ -272,7 +270,7 @@ linters: # Default: 10 max-complexity: 10 # The maximal average package complexity. - # If it's higher than 0.0 (float) the check is enabled + # If it's higher than 0.0 (float) the check is enabled. # Default: 0.0 package-average: 0.5 @@ -285,7 +283,7 @@ linters: - var - func - # If true, underscore vars (vars with "_" as the name) will be ignored at all checks + # 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 @@ -301,15 +299,15 @@ linters: # Default: true (disabled) disable-dec-num-check: false - # If true, type declarations will be ignored for dec num check + # 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 + # 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 + # If true, var declarations will be ignored for dec num check. # Default: false (var statements are not ignored) disable-var-dec-num-check: false @@ -341,6 +339,7 @@ linters: # List of file globs that will match this list of settings to compare against. # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. + # The placeholder '${config-path}' is substituted with a path relative to the configuration file. # Default: $all files: - "!**/*_a _file.go" @@ -415,11 +414,12 @@ linters: # 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 + # linters: + # settings: + # errcheck: + # exclude-functions: + # - encoding/json.Marshal + # - encoding/json.MarshalIndent # # Default: false check-error-free-encoding: true @@ -433,7 +433,7 @@ linters: # See the https://github.com/polyfloyd/go-errorlint for caveats. # Default: true errorf: false - # Permit more than 1 %w verb, valid per Go 1.20 (Requires 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. @@ -513,7 +513,7 @@ linters: # Optional message that gets included in error reports. - pattern: ^fmt\.Print.*$ msg: Do not commit print statements. - # Alternatively, put messages at the end of the regex, surrounded by `(# )?` + # Alternatively, put messages at the end of the regex, surrounded by `(# )?`. # Escape any special characters. Those messages get included in error reports. - pattern: 'fmt\.Print.*(# Do not commit print statements\.)?' # Forbid spew Dump, whether it is called as function or method. @@ -534,6 +534,14 @@ linters: # Default: false analyze-types: true + funcorder: + # Checks that constructors are placed after the structure declaration. + # Default: true + constructor: false + # Checks if the exported methods of a structure are placed before the non-exported ones. + # Default: true + struct-method: false + funlen: # Checks the number of lines in a function. # If lower than 0, disable the check. @@ -568,11 +576,11 @@ linters: # Default: false suppress-async-assertion: true - # Suppress warning for comparing values from different types, like `int32` and `uint32` + # Suppress warning for comparing values from different types, like `int32` and `uint32`. # Default: false suppress-type-compare-assertion: true - # Trigger warning for ginkgo focus containers like `FDescribe`, `FContext`, `FWhen` or `FIt` + # Trigger warning for ginkgo focus containers like `FDescribe`, `FContext`, `FWhen` or `FIt`. # Default: false forbid-focus-container: true @@ -586,7 +594,7 @@ linters: force-expect-to: true # Best effort validation of async intervals (timeout and polling). - # Ignored the suppress-async-assertion is true. + # Ignored the `suppress-async-assertion` is true. # Default: false validate-async-intervals: true @@ -602,7 +610,7 @@ linters: # Presence of `default` case in switch statements satisfies exhaustiveness, if all members are not listed. # Default: true default-signifies-exhaustive: false - # Include shared interfaces in the exhaustiviness check. + # Include shared interfaces in the exhaustiveness check. # Default: false include-shared-interfaces: true @@ -624,10 +632,10 @@ linters: # Search also for duplicated numbers. # Default: false numbers: true - # Minimum value, only works with goconst.numbers + # Minimum value, only works with `goconst.numbers`. # Default: 3 min: 2 - # Maximum value, only works with goconst.numbers + # Maximum value, only works with `goconst.numbers`. # Default: 3 max: 2 # Ignore when constant is not used as function argument. @@ -635,7 +643,14 @@ linters: ignore-calls: false # Exclude strings matching the given regular expression. # Default: "" - ignore-strings: 'foo.+' + ignore-string-values: + - 'foo.+' + # Detects constants with identical values. + # Default: false + find-duplicates: true + # Evaluates of constant expressions like Prefix + "suffix". + # Default: false + eval-const-expressions: true gocritic: # Disable all checks. @@ -1100,7 +1115,7 @@ linters: # 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.com/overview. + # The list of supported checkers can be found at https://go-critic.com/overview. settings: # Must be valid enabled check name. captLocal: @@ -1166,6 +1181,7 @@ linters: # Comma-separated list of file paths containing ruleguard rules. # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. + # The placeholder '${config-path}' is substituted with a path relative to the configuration file. # Glob patterns such as 'rules-*.go' may be specified. # Default: "" rules: '${base-path}/ruleguard/rules-*.go,${base-path}/myrule1.go' @@ -1239,19 +1255,19 @@ linters: # for example: AUTHOR: .*@mycompany\.com # The template used for checking. - # Put here copyright header template for source code files + # Put here copyright header template for source code files. # Note: {{ YEAR }} is a builtin value that returns the year relative to the current machine time. # 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. @@ -1261,6 +1277,7 @@ linters: # Useful if you need to load the template from a specific file. # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. + # The placeholder '${config-path}' is substituted with a path relative to the configuration file. # Default: "" template-path: /path/to/my/template.tmpl @@ -1344,7 +1361,6 @@ linters: - 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 - G115 # Potential integer overflow when converting between integer types - G201 # SQL query construction using format string @@ -1389,7 +1405,6 @@ linters: - 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 - G115 # Potential integer overflow when converting between integer types - G201 # SQL query construction using format string @@ -1499,13 +1514,13 @@ linters: # 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 + # Maximum allowed permissions mode for os.Mkdir and os.MkdirAll. # Default: "0750" G301: "0750" - # Maximum allowed permissions mode for os.OpenFile and os.Chmod + # Maximum allowed permissions mode for os.OpenFile and os.Chmod. # Default: "0600" G302: "0600" - # Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile + # Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile. # Default: "0600" G306: "0600" @@ -1541,7 +1556,7 @@ linters: # Default: false disable-all: true # Enable analyzers by name. - # (in addition to default: + # (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, @@ -1584,6 +1599,8 @@ linters: - findcall # Report assembly that clobbers the frame pointer before saving it. - framepointer + # Report using Go 1.22 enhanced ServeMux patterns in older Go versions. + - httpmux # Check for mistakes using HTTP responses. - httpresponse # Detect impossible interface-to-interface type assertions. @@ -1641,7 +1658,7 @@ linters: # Default: false enable-all: true # Disable analyzers by name. - # (in addition to default + # (In addition to default # atomicalign, deepequalerrors, fieldalignment, findcall, nilness, reflectvaluecompare, shadow, sortslice, # timeformat, unusedwrite # ). @@ -1665,6 +1682,7 @@ linters: - fieldalignment - findcall - framepointer + - httpmux - httpresponse - ifaceassert - loopclosure @@ -1708,16 +1726,16 @@ linters: # Default: false strict: true unusedresult: - # Comma-separated list of functions whose results must be used - # (in addition to default: + # 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: - pkg.MyFunc - # Comma-separated list of names of methods of type func() string whose results must be used - # (in addition to default Error,String) + # Comma-separated list of names of methods of type func() string whose results must be used. + # (In addition to default Error,String). # Default: [] stringmethods: - MyMethod @@ -1783,7 +1801,7 @@ linters: 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 + # See https://github.com/julz/importas#use-regular-expression for details. - pkg: knative.dev/serving/pkg/apis/(\w+)/(v[\w\d]+) alias: $1$2 # An explicit empty alias can be used to ensure no aliases are used for a package. @@ -1922,14 +1940,14 @@ linters: - 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" + # 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` + # Values always ignored: `.+_test.go`. # Default: [] ignored-files: - 'magic1_.+\.go$' @@ -1984,7 +2002,7 @@ linters: - unsafeptr nlreturn: - # Size of the block (including return statement that is still "OK") + # Size of the block (including return statement that is still "OK"), # so no return split required. # Default: 1 block-size: 2 @@ -2174,10 +2192,10 @@ linters: disabled: false exclude: [""] arguments: - - maxLitCount: "3" - allowStrs: '""' - allowInts: "0,1,2" - allowFloats: "0.0,0.,1.0,1.,2.0,2." + - max-lit-count: "3" + allow-strs: '""' + allow-ints: "0,1,2" + allow-floats: "0.0,0.,1.0,1.,2.0,2." # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#argument-limit - name: argument-limit severity: warning @@ -2256,7 +2274,7 @@ linters: disabled: false exclude: [""] arguments: - - allowTypesBefore: "*testing.T,*github.com/user/repo/testing.Harness" + - allow-types-before: "*testing.T,*github.com/user/repo/testing.Harness" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#context-keys-type - name: context-keys-type severity: warning @@ -2284,19 +2302,18 @@ linters: disabled: false exclude: [""] arguments: - - "call-chain" - - "loop" - - "method-call" - - "recover" - - "immediate-recover" - - "return" + - - "call-chain" + - "loop" + - "method-call" + - "recover" + - "return" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#dot-imports - name: dot-imports severity: warning disabled: false exclude: [""] arguments: - - allowedPackages: ["github.com/onsi/ginkgo/v2", "github.com/onsi/gomega"] + - allowed-packages: ["github.com/onsi/ginkgo/v2", "github.com/onsi/gomega"] # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#duplicated-imports - name: duplicated-imports severity: warning @@ -2308,8 +2325,8 @@ linters: disabled: false exclude: [""] arguments: - - "preserveScope" - - "allowJump" + - "preserve-scope" + - "allow-jump" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#empty-block - name: empty-block severity: warning @@ -2335,8 +2352,8 @@ linters: arguments: - "short" # Or this parameter: - - funcArgStyle: "full" - funcRetValStyle: "short" + - func-arg-style: "full" + func-ret-val-style: "short" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#enforce-slice-style - name: enforce-slice-style severity: warning @@ -2372,15 +2389,15 @@ linters: disabled: false exclude: [""] arguments: - - "checkPrivateReceivers" - - "disableStutteringCheck" - - "sayRepetitiveInsteadOfStutters" - - "checkPublicInterface" - - "disableChecksOnConstants" - - "disableChecksOnFunctions" - - "disableChecksOnMethods" - - "disableChecksOnTypes" - - "disableChecksOnVariables" + - "check-private-receivers" + - "disable-stuttering-check" + - "say-repetitive-instead-of-stutters" + - "check-public-interface" + - "disable-checks-on-constants" + - "disable-checks-on-functions" + - "disable-checks-on-methods" + - "disable-checks-on-types" + - "disable-checks-on-variables" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#file-header - name: file-header severity: warning @@ -2395,8 +2412,8 @@ linters: exclude: [""] arguments: - max: 100 - skipComments: true - skipBlankLines: true + skip-comments: true + skip-blank-lines: true # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#filename-format - name: filename-format severity: warning @@ -2444,8 +2461,8 @@ linters: arguments: - "^[a-z][a-z0-9]{0,}$" # Or this parameter: - - allowRegex: "^[a-z][a-z0-9]{0,}$" - denyRegex: '^v\d+$' + - allow-regex: "^[a-z][a-z0-9]{0,}$" + deny-regex: '^v\d+$' # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#import-shadowing - name: import-shadowing severity: warning @@ -2470,7 +2487,7 @@ linters: disabled: false exclude: [""] arguments: - - "preserveScope" + - "preserve-scope" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#line-length-limit - name: line-length-limit severity: warning @@ -2535,7 +2552,7 @@ linters: disabled: false exclude: [""] arguments: - - maxLength: 2 + - max-length: 2 # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#redefines-builtin-id - name: redefines-builtin-id severity: warning @@ -2551,6 +2568,11 @@ linters: severity: warning disabled: false exclude: [""] + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redundant-test-main-exit + - name: redundant-test-main-exit + severity: warning + disabled: false + exclude: [""] # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#string-format - name: string-format severity: warning @@ -2585,7 +2607,7 @@ linters: disabled: false exclude: [""] arguments: - - "preserveScope" + - "preserve-scope" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#time-equal - name: time-equal severity: warning @@ -2602,7 +2624,7 @@ linters: disabled: false exclude: [""] arguments: - - acceptIgnoredAssertionResult: true + - accept-ignored-assertion-result: true # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#unconditional-recursion - name: unconditional-recursion severity: warning @@ -2642,14 +2664,14 @@ linters: disabled: false exclude: [""] arguments: - - allowRegex: "^_" + - allow-regex: "^_" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#unused-receiver - name: unused-receiver severity: warning disabled: false exclude: [""] arguments: - - allowRegex: "^_" + - allow-regex: "^_" # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#use-any - name: use-any severity: warning @@ -2678,7 +2700,7 @@ linters: arguments: - [ "ID" ] # AllowList - [ "VM" ] # DenyList - - - upperCaseConst: true # Extra parameter (upperCaseConst|skipPackageNameChecks) + - - upper-case-const: true # Extra parameter (upper-case-const|skip-package-name-checks) # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#waitgroup-by-value - name: waitgroup-by-value severity: warning @@ -2686,7 +2708,7 @@ linters: exclude: [""] rowserrcheck: - # database/sql is always checked + # database/sql is always checked. # Default: [] packages: - github.com/jmoiron/sqlx @@ -2724,11 +2746,16 @@ linters: # https://github.com/go-simpler/sloglint?tab=readme-ov-file#static-messages # Default: false static-msg: true + # Enforce message style. + # Values: lowercased, capitalized + # https://github.com/go-simpler/sloglint?tab=readme-ov-file#message-style + # Default: "" + msg-style: capitalized # 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: true - # Enforce a single key naming convention. + # Enforce key naming convention. # Values: snake, kebab, camel, pascal # https://github.com/go-simpler/sloglint?tab=readme-ov-file#key-naming-convention # Default: "" @@ -3272,7 +3299,7 @@ linters: # Align and sort can be used together or separately. # # Whether enable align. If true, the struct tags will be aligned. - # e.g.: + # E.g.: # type FooBar struct { # Bar string `json:"bar" validate:"required"` # FooFoo int8 `json:"foo_foo" validate:"required"` @@ -3286,7 +3313,7 @@ linters: 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"` + # 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. @@ -3400,12 +3427,6 @@ linters: # Default: false ignore: true - 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 @@ -3763,6 +3784,9 @@ linters: # Default: [] ignore-interface-regexps: - ^(?i)c(?-i)ach(ing|e) + # Determines whether wrapcheck should report errors returned from inside the package. + # Default: false + report-internal-errors: true wsl: # Do strict checking when assigning from append (x = append(x, y)). @@ -3879,8 +3903,8 @@ linters: # - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc. # - `disable`: disable the generated files exclusion. # - # Default: lax - generated: strict + # Default: strict + generated: lax # Log a warning if an exclusion rule is unused. # Default: false warn-unused: true @@ -3952,7 +3976,7 @@ formatters: gci: # 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`, + # 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: @@ -4027,6 +4051,9 @@ formatters: chain-split-dots: false exclusions: + # Log a warning if an exclusion path is unused. + # Default: false + warn-unused: true # Mode of the generated files analysis. # # - `strict`: sources are excluded by strictly following the Go generated file convention. @@ -4160,9 +4187,16 @@ output: path: ./path/to/output.json # Add a prefix to the output file references. + # This option is ignored when using `output.path-mode: abs` mode. # Default: "" path-prefix: "" + # By default, the report are related to the path obtained by `run.relative-path-mode`. + # The mode `abs` allows to show absolute file paths instead of relative file paths. + # The option `output.path-prefix` is ignored when using `abs` mode. + # Default: "" + path-mode: "abs" + # Order to use when sorting results. # Possible values: `file`, `linter`, and `severity`. # diff --git a/.goreleaser.yml b/.goreleaser.yml index 98346da5f7fd..d40fb1a4a034 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -172,46 +172,6 @@ aurs: ./golangci-lint completion zsh | install -Dm644 /dev/stdin "${pkgdir}/usr/share/zsh/site-functions/_golangci-lint" ./golangci-lint completion fish | install -Dm644 /dev/stdin "${pkgdir}/usr/share/fish/vendor_completions.d/golangci-lint.fish" -aur_sources: - - description: Fast linters runner for Go. - skip_upload: false - homepage: https://golangci.com - provides: - - "golangci-lint" - maintainers: - - "Fernandez Ludovic " - license: GPL-3.0 - private_key: "{{ .Env.AUR_KEY }}" - git_url: "ssh://aur@aur.archlinux.org/golangci-lint.git" - commit_author: - name: golangci-releaser - email: 65486276+golangci-releaser@users.noreply.github.com - build: |- - local _commit _flags - _commit=$(bsdcat "${pkgname}_${pkgver}.tar.gz" | git get-tar-commit-id) - _flags=( - -X=main.version="$pkgver" - -X=main.commit="${_commit::7}" - -X=main.date="$(date -u -d "@${SOURCE_DATE_EPOCH}" +'%FT%TZ')" - -linkmode=external - ) - export CGO_ENABLED=1 - export CGO_CFLAGS="${CFLAGS}" - export CGO_CPPFLAGS="$CPPFLAGS" - export CGO_CXXFLAGS="$CXXFLAGS" - export CGO_LDFLAGS="${LDFLAGS}" - export GOFLAGS='-buildmode=pie -trimpath -modcacherw' - - go build -o "$pkgname" -ldflags="${_flags[*]}" ./cmd/"$pkgname" - ./"$pkgname" completion bash > completion.bash - ./"$pkgname" completion zsh > completion.zsh - ./"$pkgname" completion fish > completion.fish - package: |- - install -Dm755 "$pkgname" -t "$pkgdir"/usr/bin - install -Dm644 completion.bash "$pkgdir"/usr/share/bash-completion/completions/"$pkgname" - install -Dm644 completion.zsh "$pkgdir"/usr/share/zsh/site-functions/_"$pkgname" - install -Dm644 completion.fish "$pkgdir"/usr/share/fish/vendor_completions.d/"$pkgname".fish - snapcrafts: - summary: Fast linters runner for Go. description: | diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index dea4b598a090..9738d4b25755 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -8,12 +8,20 @@ pass_filenames: false - id: golangci-lint-full name: golangci-lint-full - description: Fast linters runner for Go. Runs on all files in the repo. Use this hook if you use pre-commit in CI. + description: Fast linters runner for Go. Runs on all files in the module. Use this hook if you use pre-commit in CI. entry: golangci-lint run --fix types: [go] language: golang require_serial: true pass_filenames: false +- id: golangci-lint-fmt + name: golangci-lint-fmt + description: Fast linters runner for Go. Formats all files in the repo. + entry: golangci-lint fmt + types: [go] + language: golang + require_serial: true + pass_filenames: false - id: golangci-lint-config-verify name: golangci-lint-config-verify description: Verifies the configuration file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a962e56a276..403a833fcb27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,97 @@ If you value it, consider supporting us, we appreciate it! ❤️ [![Open Collective backers and sponsors](https://img.shields.io/badge/OpenCollective-Donate-blue?logo=opencollective&style=for-the-badge)](https://opencollective.com/golangci-lint) [![GitHub Sponsors](https://img.shields.io/badge/GitHub-Donate-blue?logo=github&style=for-the-badge)](https://github.com/sponsors/golangci) +### v2.1.6 + +1. Linters bug fixes + * `godot`: from 1.5.0 to 1.5.1 + * `musttag`: from 0.13.0 to 0.13.1 +2. Documentation + * Add note about golangci-lint v2 integration in VS Code + +### v2.1.5 + +Due to an error related to Snapcraft, some artifacts of the v2.1.4 release have not been published. + +This release contains the same things as v2.1.3. + +### v2.1.4 + +Due to an error related to Snapcraft, some artifacts of the v2.1.3 release have not been published. + +This release contains the same things as v2.1.3. + +### v2.1.3 + +1. Linters bug fixes + * `fatcontext`: from 0.7.2 to 0.8.0 +2. Misc. + * migration: fix `nakedret.max-func-lines: 0` + * migration: fix order of `staticcheck` settings + * fix: add `go.mod` hash to the cache salt + * fix: use diagnostic position for related information position + +### v2.1.2 + +1. Linters bug fixes + * `exptostd`: from 0.4.2 to 0.4.3 + * `gofumpt`: from 0.7.0 to 0.8.0 + * `protogetter`: from 0.3.13 to 0.3.15 + * `usetesting`: from 0.4.2 to 0.4.3 + +### v2.1.1 + +The release process of v2.1.0 failed due to a regression inside goreleaser. + +The binaries of v2.1.0 have been published, but not the other artifacts (AUR, Docker, etc.). + +### v2.1.0 + +1. Enhancements + * Add an option to display absolute paths (`--path-mode=abs`) + * Add configuration path placeholder (`${config-path}`) + * Add `warn-unused` option for `fmt` command + * Colored diff for `fmt` command (`golangci-lint fmt --diff-colored`) +2. New linters + * Add `funcorder` linter https://github.com/manuelarte/funcorder +3. Linters new features or changes + * `go-errorlint`: from 1.7.1 to 1.8.0 (automatic error comparison and type assertion fixes) + * ⚠️ `goconst`: `ignore-strings` is deprecated and replaced by `ignore-string-values` + * `goconst`: from 1.7.1 to 1.8.1 (new options: `find-duplicates`, `eval-const-expressions`) + * `govet`: add `httpmux` analyzer + * `nilnesserr`: from 0.1.2 to 0.2.0 (detect more cases) + * `paralleltest`: from 1.0.10 to 1.0.14 (checks only `_test.go` files) + * `revive`: from 1.7.0 to 1.9.0 (support kebab case for setting names) + * `sloglint`: from 0.9.0 to 0.11.0 (autofix, new option `msg-style`, suggest `slog.DiscardHandler`) + * `wrapcheck`: from 2.10.0 to 2.11.0 (new option `report-internal-errors`) + * `wsl`: from 4.6.0 to 4.7.0 (cgo files are always excluded) +4. Linters bug fixes + * `fatcontext`: from 0.7.1 to 0.7.2 + * `gocritic`: fix `importshadow` checker + * `gosec`: from 2.22.2 to 2.22.3 + * `ireturn`: from 0.3.1 to 0.4.0 + * `loggercheck`: from 0.10.1 to 0.11.0 + * `nakedret`: from 2.0.5 to 2.0.6 + * `nonamedreturns`: from 1.0.5 to 1.0.6 + * `protogetter`: from 0.3.12 to 0.3.13 + * `testifylint`: from 1.6.0 to 1.6.1 + * `unconvert`: update to HEAD +5. Misc. + * Fixes memory leaks when using go1.(N) with golangci-lint built with go1.(N-X) + * Adds `golangci-lint-fmt` pre-commit hook +6. Documentation + * Improvements + * Updates section about vscode integration + +### v2.0.2 + +1. Misc. + * Fixes flags parsing for formatters + * Fixes the filepath used by the exclusion `source` option +2. Documentation + * Adds a section about flags migration + * Cleaning pages with v1 options + ### v2.0.1 1. Linters/formatters bug fixes diff --git a/README.md b/README.md index 3b3a0c3b1562..232d50d12fc1 100644 --- a/README.md +++ b/README.md @@ -68,4 +68,4 @@ This project exists thanks to all the people who contribute. [How to contribute] ## Stargazers over time -[![Stargazers over time](https://starchart.cc/golangci/golangci-lint.svg)](https://starchart.cc/golangci/golangci-lint) +[![Stargazers over time](https://starchart.cc/golangci/golangci-lint.svg?variant=adaptive)](https://starchart.cc/golangci/golangci-lint) diff --git a/assets/cli-help.json b/assets/cli-help.json index 64c4581bf757..407240d603e0 100644 --- a/assets/cli-help.json +++ b/assets/cli-help.json @@ -1,5 +1,5 @@ { "enable": "Enabled by default linters:\nerrcheck: Errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases.\ngovet: Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes. [auto-fix]\nineffassign: Detects when assignments to existing variables are not used. [fast]\nstaticcheck: It's the set of rules from staticcheck. [auto-fix]\nunused: Checks Go code for unused constants, variables, functions and types.", - "help": "Usage:\n golangci-lint run [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n --default string Default set of linters to enable (default \"standard\")\n -D, --disable strings Disable specific linter\n -E, --enable strings Enable specific linter\n --enable-only strings Override linters configuration section to only run the specific linter(s)\n --fast-only Filter enabled linters to run only fast linters\n -j, --concurrency int Number of CPUs to use (Default: Automatically set to match Linux container CPU quota and fall back to the number of logical CPUs in the machine)\n --modules-download-mode string Modules download mode. If not empty, passed as -mod=\u003cmode\u003e to go tools\n --issues-exit-code int Exit code when issues were found (default 1)\n --build-tags strings Build tags\n --timeout duration Timeout for total work. Disabled by default\n --tests Analyze tests (*_test.go) (default true)\n --allow-parallel-runners Allow multiple parallel golangci-lint instances running.\n If false (default) - golangci-lint acquires file lock on start.\n --allow-serial-runners Allow multiple golangci-lint instances running, but serialize them around a lock.\n If false (default) - golangci-lint exits with an error if it fails to acquire file lock on start.\n --path-prefix string Path prefix to add to output\n --show-stats Show statistics per linter (default true)\n --output.text.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.text.print-linter-name Print linter name in the end of issue text. (default true)\n --output.text.print-issued-lines Print lines of code with issue. (default true)\n --output.text.colors Use colors. (default true)\n --output.json.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.print-linter-name Print linter name in the end of issue text. (default true)\n --output.tab.colors Use colors. (default true)\n --output.html.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.checkstyle.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.code-climate.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.extended Support extra JUnit XML fields.\n --output.teamcity.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.sarif.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --max-issues-per-linter int Maximum issues count per one linter. Set to 0 to disable (default 50)\n --max-same-issues int Maximum count of issues with the same text. Set to 0 to disable (default 3)\n --uniq-by-line Make issues output unique by line (default true)\n -n, --new Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.\n It's a super-useful option for integration of golangci-lint into existing large codebase.\n It's not practical to fix all existing issues at the moment of integration: much better to not allow issues in new code.\n For CI setups, prefer --new-from-rev=HEAD~, as --new can skip linting the current patch if any scripts generate unstaged files before golangci-lint runs.\n --new-from-rev REV Show only new issues created after git revision REV\n --new-from-patch PATH Show only new issues created in git patch with file path PATH\n --new-from-merge-base string Show only new issues created after the best common ancestor (merge-base against HEAD)\n --whole-files Show issues in any part of update files (requires new-from-rev or new-from-patch)\n --fix Fix found issues (if it's supported by the linter)\n --cpu-profile-path string Path to CPU profile output file\n --mem-profile-path string Path to memory profile output file\n --print-resources-usage Print avg and max memory usage of golangci-lint and total time\n --trace-path string Path to trace output file\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n", - "fmtHelp": "Usage:\n golangci-lint fmt [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n -E, --enable strings Enable specific formatter\n -d, --diff Display diffs instead of rewriting files\n --stdin Use standard input for piping source files\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n" + "help": "Usage:\n golangci-lint run [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n --default string Default set of linters to enable (default \"standard\")\n -D, --disable strings Disable specific linter\n -E, --enable strings Enable specific linter\n --enable-only strings Override linters configuration section to only run the specific linter(s)\n --fast-only Filter enabled linters to run only fast linters\n -j, --concurrency int Number of CPUs to use (Default: Automatically set to match Linux container CPU quota and fall back to the number of logical CPUs in the machine)\n --modules-download-mode string Modules download mode. If not empty, passed as -mod=\u003cmode\u003e to go tools\n --issues-exit-code int Exit code when issues were found (default 1)\n --build-tags strings Build tags\n --timeout duration Timeout for total work. Disabled by default\n --tests Analyze tests (*_test.go) (default true)\n --allow-parallel-runners Allow multiple parallel golangci-lint instances running.\n If false (default) - golangci-lint acquires file lock on start.\n --allow-serial-runners Allow multiple golangci-lint instances running, but serialize them around a lock.\n If false (default) - golangci-lint exits with an error if it fails to acquire file lock on start.\n --path-prefix string Path prefix to add to output\n --path-mode string Path mode to use (empty, or 'abs')\n --show-stats Show statistics per linter (default true)\n --output.text.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.text.print-linter-name Print linter name in the end of issue text. (default true)\n --output.text.print-issued-lines Print lines of code with issue. (default true)\n --output.text.colors Use colors. (default true)\n --output.json.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.print-linter-name Print linter name in the end of issue text. (default true)\n --output.tab.colors Use colors. (default true)\n --output.html.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.checkstyle.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.code-climate.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.extended Support extra JUnit XML fields.\n --output.teamcity.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.sarif.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --max-issues-per-linter int Maximum issues count per one linter. Set to 0 to disable (default 50)\n --max-same-issues int Maximum count of issues with the same text. Set to 0 to disable (default 3)\n --uniq-by-line Make issues output unique by line (default true)\n -n, --new Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.\n It's a super-useful option for integration of golangci-lint into existing large codebase.\n It's not practical to fix all existing issues at the moment of integration: much better to not allow issues in new code.\n For CI setups, prefer --new-from-rev=HEAD~, as --new can skip linting the current patch if any scripts generate unstaged files before golangci-lint runs.\n --new-from-rev REV Show only new issues created after git revision REV\n --new-from-patch PATH Show only new issues created in git patch with file path PATH\n --new-from-merge-base string Show only new issues created after the best common ancestor (merge-base against HEAD)\n --whole-files Show issues in any part of update files (requires new-from-rev or new-from-patch)\n --fix Fix found issues (if it's supported by the linter)\n --cpu-profile-path string Path to CPU profile output file\n --mem-profile-path string Path to memory profile output file\n --print-resources-usage Print avg and max memory usage of golangci-lint and total time\n --trace-path string Path to trace output file\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n", + "fmtHelp": "Usage:\n golangci-lint fmt [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n -E, --enable strings Enable specific formatter\n -d, --diff Display diffs instead of rewriting files\n --diff-colored Display diffs instead of rewriting files (with colors)\n --stdin Use standard input for piping source files\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n" } diff --git a/assets/github-action-config-v1.json b/assets/github-action-config-v1.json index 596dfd69ba75..28c21d7b0786 100644 --- a/assets/github-action-config-v1.json +++ b/assets/github-action-config-v1.json @@ -191,6 +191,9 @@ }, "v2.0": { "Error": "golangci-lint version 'v2.0' isn't supported: only v1 versions are supported" + }, + "v2.1": { + "Error": "golangci-lint version 'v2.1' isn't supported: only v1 versions are supported" } } } diff --git a/assets/github-action-config-v2.json b/assets/github-action-config-v2.json index bbcfdfbc30b9..2a099a8ff534 100644 --- a/assets/github-action-config-v2.json +++ b/assets/github-action-config-v2.json @@ -1,7 +1,7 @@ { "MinorVersionToConfig": { "latest": { - "TargetVersion": "v2.0.0" + "TargetVersion": "v2.1.6" }, "v1.10": { "Error": "golangci-lint version 'v1.10' isn't supported: we support only v2.0.0 and later versions" @@ -190,7 +190,10 @@ "Error": "golangci-lint version 'v1.9' isn't supported: we support only v2.0.0 and later versions" }, "v2.0": { - "TargetVersion": "v2.0.0" + "TargetVersion": "v2.0.2" + }, + "v2.1": { + "TargetVersion": "v2.1.6" } } } diff --git a/assets/github-action-config.json b/assets/github-action-config.json index 596dfd69ba75..28c21d7b0786 100644 --- a/assets/github-action-config.json +++ b/assets/github-action-config.json @@ -191,6 +191,9 @@ }, "v2.0": { "Error": "golangci-lint version 'v2.0' isn't supported: only v1 versions are supported" + }, + "v2.1": { + "Error": "golangci-lint version 'v2.1' isn't supported: only v1 versions are supported" } } } diff --git a/assets/linters-info.json b/assets/linters-info.json index 8711ae5270e4..99ffd81b0865 100644 --- a/assets/linters-info.json +++ b/assets/linters-info.json @@ -246,6 +246,16 @@ "isSlow": true, "since": "v1.38.0" }, + { + "name": "funcorder", + "desc": "checks the order of functions, methods, and constructors", + "Groups": null, + "loadMode": 8199, + "originalURL": "https://github.com/manuelarte/funcorder", + "internal": false, + "isSlow": false, + "since": "v2.1.0" + }, { "name": "fatcontext", "desc": "detects nested contexts in loops and function literals", @@ -331,10 +341,10 @@ "name": "goconst", "desc": "Finds repeated strings that could be replaced by a constant", "Groups": null, - "loadMode": 8199, + "loadMode": 8767, "originalURL": "https://github.com/jgautheron/goconst", "internal": false, - "isSlow": false, + "isSlow": true, "since": "v1.0.0" }, { @@ -570,7 +580,7 @@ }, { "name": "loggercheck", - "desc": "Checks key value pairs for common logger libraries (kitlog,klog,logr,zap).", + "desc": "Checks key value pairs for common logger libraries (kitlog,klog,logr,slog,zap).", "Groups": null, "loadMode": 8767, "originalURL": "https://github.com/timonwong/loggercheck", @@ -614,7 +624,7 @@ "desc": "Finds commonly misspelled English words", "Groups": null, "loadMode": 8199, - "originalURL": "https://github.com/client9/misspell", + "originalURL": "https://github.com/golangci/misspell", "internal": false, "canAutoFix": true, "isSlow": false, @@ -832,6 +842,7 @@ "loadMode": 8767, "originalURL": "https://github.com/go-simpler/sloglint", "internal": false, + "canAutoFix": true, "isSlow": true, "since": "v1.55.0" }, diff --git a/cmd/golangci-lint/main.go b/cmd/golangci-lint/main.go index f7f3091dc653..acb09cd8c0be 100644 --- a/cmd/golangci-lint/main.go +++ b/cmd/golangci-lint/main.go @@ -4,7 +4,9 @@ import ( "cmp" "fmt" "os" + "regexp" "runtime/debug" + "strings" "github.com/golangci/golangci-lint/v2/pkg/commands" "github.com/golangci/golangci-lint/v2/pkg/exitcodes" @@ -23,7 +25,7 @@ func main() { info := createBuildInfo() if err := commands.Execute(info); err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Failed executing command with error: %v\n", err) + _, _ = fmt.Fprintf(os.Stderr, "The command is terminated due to an error: %v\n", err) os.Exit(exitcodes.Failure) } } @@ -49,6 +51,11 @@ func createBuildInfo() commands.BuildInfo { info.Version = buildInfo.Main.Version + matched, _ := regexp.MatchString(`v\d+\.\d+\.\d+`, buildInfo.Main.Version) + if matched { + info.Version = strings.TrimPrefix(buildInfo.Main.Version, "v") + } + var revision string var modified string for _, setting := range buildInfo.Settings { diff --git a/docs/package-lock.json b/docs/package-lock.json index 5d1ab9e51dab..ccf2b1809d7f 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -40,7 +40,7 @@ "postcss": "^8.4.31", "prism-react-renderer": "^1.3.5", "prop-types": "^15.8.1", - "puppeteer": "^13.7.0", + "puppeteer": "^24.4.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-headroom": "^3.2.1", @@ -4206,6 +4206,187 @@ "@parcel/core": "^2.6.2" } }, + "node_modules/@puppeteer/browsers": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.8.0.tgz", + "integrity": "sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.1", + "tar-fs": "^3.0.8", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@puppeteer/browsers/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@puppeteer/browsers/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/@puppeteer/browsers/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@puppeteer/browsers/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-fs": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@puppeteer/browsers/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/@sideway/address": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", @@ -4320,6 +4501,12 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -4600,9 +4787,10 @@ } }, "node_modules/@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" @@ -5020,14 +5208,12 @@ } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ajv": { @@ -5268,11 +5454,29 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=" }, + "node_modules/ast-types/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -5359,6 +5563,34 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, "node_modules/babel-loader": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", @@ -5580,10 +5812,83 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "node_modules/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.2.tgz", + "integrity": "sha512-S5mmkMesiduMqnz51Bfh0Et9EX0aTCJxhsI4bvzFFLs8Z1AV8RDHadfY5CyLwdoLHgXbNBEN1gQcbEtGwuvixw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", + "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", + "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, "node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.0.1" } @@ -5601,6 +5906,15 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/better-opn": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", @@ -5899,7 +6213,8 @@ "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", "engines": { "node": "*" } @@ -6583,6 +6898,25 @@ "node": ">=6.0" } }, + "node_modules/chromium-bidi": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-2.1.2.tgz", + "integrity": "sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw==", + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/chromium-bidi/node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, "node_modules/ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -8192,6 +8526,15 @@ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/dataloader": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", @@ -8337,6 +8680,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/delaunator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", @@ -8530,9 +8887,10 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.981744", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", - "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==" + "version": "0.0.1413902", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1413902.tgz", + "integrity": "sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ==", + "license": "BSD-3-Clause" }, "node_modules/dir-glob": { "version": "3.0.1", @@ -8762,6 +9120,15 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -8954,6 +9321,37 @@ "node": ">=0.8.0" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eslint": { "version": "7.32.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", @@ -10098,6 +10496,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -10117,11 +10516,15 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", "dependencies": { "pump": "^3.0.0" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/fast-deep-equal": { @@ -10129,6 +10532,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -10210,7 +10619,8 @@ "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", "dependencies": { "pend": "~1.2.0" } @@ -13441,6 +13851,20 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "node_modules/gatsby/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gatsby/node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -13591,6 +14015,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-uri": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/git-up": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", @@ -14358,6 +14796,19 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/http2-wrapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", @@ -14382,15 +14833,16 @@ } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", "dependencies": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/human-signals": { @@ -14457,15 +14909,19 @@ } }, "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/import-from": { @@ -14668,6 +15124,25 @@ "loose-envify": "^1.0.0" } }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -15290,6 +15765,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -15311,11 +15792,6 @@ "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==" }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -17095,6 +17571,15 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -17697,6 +18182,38 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/package-json": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", @@ -17808,17 +18325,21 @@ } }, "node_modules/parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", + "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/parse-latin": { @@ -18002,7 +18523,8 @@ "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" }, "node_modules/performance-now": { "version": "2.1.0", @@ -18374,10 +18896,39 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/pseudomap": { "version": "1.0.2", @@ -18413,46 +18964,77 @@ } }, "node_modules/puppeteer": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-13.7.0.tgz", - "integrity": "sha512-U1uufzBjz3+PkpCxFrWzh4OrMIdIb2ztzCu0YEPfRHjHswcSwHZswnK+WdsOQJsRV8WeTg3jLhJR4D867+fjsA==", + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.4.0.tgz", + "integrity": "sha512-E4JhJzjS8AAI+6N/b+Utwarhz6zWl3+MR725fal+s3UlOlX2eWdsvYYU+Q5bXMjs9eZEGkNQroLkn7j11s2k1Q==", "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.981744", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "pkg-dir": "4.2.0", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.5.0" + "@puppeteer/browsers": "2.8.0", + "chromium-bidi": "2.1.2", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1413902", + "puppeteer-core": "24.4.0", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" }, "engines": { - "node": ">=10.18.1" + "node": ">=18" } }, - "node_modules/puppeteer/node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "node_modules/puppeteer-core": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.4.0.tgz", + "integrity": "sha512-eFw66gCnWo0X8Hyf9KxxJtms7a61NJVMiSaWfItsFPzFBsjsWdmcNlBdsA1WVwln6neoHhsG+uTVesKmTREn/g==", + "license": "Apache-2.0", "dependencies": { - "node-fetch": "2.6.7" + "@puppeteer/browsers": "2.8.0", + "chromium-bidi": "2.1.2", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1413902", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.1" + }, + "engines": { + "node": ">=18" } }, - "node_modules/puppeteer/node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "node_modules/puppeteer-core/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/puppeteer-core/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -18463,6 +19045,50 @@ } } }, + "node_modules/puppeteer/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/puppeteer/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -20590,6 +21216,16 @@ "node": ">=8.0.0" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/snake-case": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", @@ -20645,6 +21281,34 @@ "node": ">=10.0.0" } }, + "node_modules/socks": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -20861,6 +21525,19 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", + "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -21421,9 +22098,10 @@ } }, "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "license": "MIT", "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -21591,6 +22269,15 @@ "node": ">=0.4.0" } }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -21844,6 +22531,12 @@ "resolved": "https://registry.npmjs.org/type-of/-/type-of-2.0.1.tgz", "integrity": "sha1-5yoXQYllaOn2KDeNgW1pEvfyOXI=" }, + "node_modules/typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "license": "MIT" + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -21857,6 +22550,20 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/ua-parser-js": { "version": "0.7.33", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", @@ -21889,15 +22596,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -23258,7 +23956,8 @@ "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -23317,6 +24016,15 @@ "node": ">=6" } }, + "node_modules/zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", @@ -25102,7 +25810,8 @@ "@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==" + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "requires": {} }, "@emotion/utils": { "version": "1.2.1", @@ -26336,6 +27045,126 @@ "nullthrows": "^1.1.1" } }, + "@puppeteer/browsers": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.8.0.tgz", + "integrity": "sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ==", + "requires": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.1", + "tar-fs": "^3.0.8", + "yargs": "^17.7.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" + }, + "tar-fs": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "requires": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "requires": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + } + } + }, "@sideway/address": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", @@ -26431,6 +27260,11 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, + "@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" + }, "@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -26705,9 +27539,9 @@ } }, "@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "optional": true, "requires": { "@types/node": "*" @@ -26989,7 +27823,8 @@ "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} }, "acorn-loose": { "version": "8.3.0", @@ -27017,12 +27852,9 @@ "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" }, "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==" }, "ajv": { "version": "6.12.6", @@ -27190,6 +28022,21 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + } + } + }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -27262,6 +28109,25 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" }, + "b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "peer": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + } + }, "babel-loader": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", @@ -27453,10 +28319,51 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "optional": true + }, + "bare-fs": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.2.tgz", + "integrity": "sha512-S5mmkMesiduMqnz51Bfh0Et9EX0aTCJxhsI4bvzFFLs8Z1AV8RDHadfY5CyLwdoLHgXbNBEN1gQcbEtGwuvixw==", + "optional": true, + "requires": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4" + } + }, + "bare-os": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", + "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", + "optional": true + }, + "bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "optional": true, + "requires": { + "bare-os": "^3.0.1" + } + }, + "bare-stream": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", + "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "optional": true, + "requires": { + "streamx": "^2.21.0" + } + }, "base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", "requires": { "safe-buffer": "^5.0.1" } @@ -27471,6 +28378,11 @@ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, + "basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==" + }, "better-opn": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", @@ -27688,7 +28600,7 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" }, "buffer-from": { "version": "1.1.1", @@ -28274,6 +29186,22 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, + "chromium-bidi": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-2.1.2.tgz", + "integrity": "sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw==", + "requires": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "dependencies": { + "mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + } + } + }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -28711,7 +29639,8 @@ "icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==" + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} }, "loader-utils": { "version": "2.0.2", @@ -28726,7 +29655,8 @@ "postcss-modules-extract-imports": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==" + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -28845,7 +29775,8 @@ "cssnano-utils": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.1.tgz", - "integrity": "sha512-VNCHL364lh++/ono+S3j9NlUK+d97KNkxI77NlqZU2W3xd2/qmyN61dsa47pTpb55zuU4G4lI7qFjAXZJH1OAQ==" + "integrity": "sha512-VNCHL364lh++/ono+S3j9NlUK+d97KNkxI77NlqZU2W3xd2/qmyN61dsa47pTpb55zuU4G4lI7qFjAXZJH1OAQ==", + "requires": {} }, "p-limit": { "version": "3.1.0", @@ -28886,22 +29817,26 @@ "postcss-discard-comments": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.2.tgz", - "integrity": "sha512-6VQ3pYTsJHEsN2Bic88Aa7J/Brn4Bv8j/rqaFQZkH+pcVkKYwxCIvoMQkykEW7fBjmofdTnQgcivt5CCBJhtrg==" + "integrity": "sha512-6VQ3pYTsJHEsN2Bic88Aa7J/Brn4Bv8j/rqaFQZkH+pcVkKYwxCIvoMQkykEW7fBjmofdTnQgcivt5CCBJhtrg==", + "requires": {} }, "postcss-discard-duplicates": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.2.tgz", - "integrity": "sha512-LKY81YjUjc78p6rbXIsnppsaFo8XzCoMZkXVILJU//sK0DgPkPSpuq/cZvHss3EtdKvWNYgWzQL+wiJFtEET4g==" + "integrity": "sha512-LKY81YjUjc78p6rbXIsnppsaFo8XzCoMZkXVILJU//sK0DgPkPSpuq/cZvHss3EtdKvWNYgWzQL+wiJFtEET4g==", + "requires": {} }, "postcss-discard-empty": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.2.tgz", - "integrity": "sha512-SxBsbTjlsKUvZLL+dMrdWauuNZU8TBq5IOL/DHa6jBUSXFEwmDqeXRfTIK/FQpPTa8MJMxEHjSV3UbiuyLARPQ==" + "integrity": "sha512-SxBsbTjlsKUvZLL+dMrdWauuNZU8TBq5IOL/DHa6jBUSXFEwmDqeXRfTIK/FQpPTa8MJMxEHjSV3UbiuyLARPQ==", + "requires": {} }, "postcss-discard-overridden": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.3.tgz", - "integrity": "sha512-yRTXknIZA4k8Yo4FiF1xbsLj/VBxfXEWxJNIrtIy6HC9KQ4xJxcPtoaaskh6QptCGrrcGnhKsTsENTRPZOBu4g==" + "integrity": "sha512-yRTXknIZA4k8Yo4FiF1xbsLj/VBxfXEWxJNIrtIy6HC9KQ4xJxcPtoaaskh6QptCGrrcGnhKsTsENTRPZOBu4g==", + "requires": {} }, "postcss-merge-longhand": { "version": "5.0.5", @@ -28962,7 +29897,8 @@ "postcss-normalize-charset": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.2.tgz", - "integrity": "sha512-fEMhYXzO8My+gC009qDc/3bgnFP8Fv1Ic8uw4ec4YTlhIOw63tGPk1YFd7fk9bZUf1DAbkhiL/QPWs9JLqdF2g==" + "integrity": "sha512-fEMhYXzO8My+gC009qDc/3bgnFP8Fv1Ic8uw4ec4YTlhIOw63tGPk1YFd7fk9bZUf1DAbkhiL/QPWs9JLqdF2g==", + "requires": {} }, "postcss-normalize-display-values": { "version": "5.0.2", @@ -29470,6 +30406,11 @@ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" }, + "data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==" + }, "dataloader": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", @@ -29566,6 +30507,16 @@ "object-keys": "^1.1.1" } }, + "degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "requires": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + } + }, "delaunator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", @@ -29726,9 +30677,9 @@ } }, "devtools-protocol": { - "version": "0.0.981744", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", - "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==" + "version": "0.0.1413902", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1413902.tgz", + "integrity": "sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ==" }, "dir-glob": { "version": "3.0.1", @@ -29929,6 +30880,11 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + }, "envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -30087,6 +31043,25 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, "eslint": { "version": "7.32.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", @@ -30503,7 +31478,8 @@ "eslint-plugin-react-hooks": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==" + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "requires": {} }, "eslint-scope": { "version": "5.1.1", @@ -30941,6 +31917,11 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -31021,7 +32002,7 @@ "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "requires": { "pend": "~1.2.0" } @@ -31763,7 +32744,8 @@ "postcss-flexbugs-fixes": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==" + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "requires": {} }, "resolve-from": { "version": "5.0.0", @@ -31806,6 +32788,13 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "optional": true, + "peer": true + }, "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -33001,7 +33990,8 @@ "gatsby-script": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/gatsby-script/-/gatsby-script-1.10.0.tgz", - "integrity": "sha512-8jAtQR0mw3G8sCy6i2D1jfGvUF5d9AIboEQuo9ZEChT4Ep5f+PSRxiWZqSjhKvintAOIeS4QXCJP5Rtp3xZKLg==" + "integrity": "sha512-8jAtQR0mw3G8sCy6i2D1jfGvUF5d9AIboEQuo9ZEChT4Ep5f+PSRxiWZqSjhKvintAOIeS4QXCJP5Rtp3xZKLg==", + "requires": {} }, "gatsby-sharp": { "version": "0.19.0", @@ -33477,6 +34467,16 @@ "get-intrinsic": "^1.1.1" } }, + "get-uri": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "requires": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + } + }, "git-up": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", @@ -33755,7 +34755,8 @@ "graphql-type-json": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz", - "integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==" + "integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==", + "requires": {} }, "gray-matter": { "version": "4.0.3", @@ -34074,6 +35075,15 @@ } } }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, "http2-wrapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", @@ -34091,11 +35101,11 @@ } }, "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "requires": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" } }, @@ -34133,9 +35143,9 @@ "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==" }, "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -34286,6 +35296,22 @@ "loose-envify": "^1.0.0" } }, + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + } + } + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -34742,6 +35768,11 @@ "esprima": "^4.0.0" } }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -34757,11 +35788,6 @@ "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==" }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -36156,6 +37182,11 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" + }, "next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -36580,6 +37611,30 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "requires": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + } + }, + "pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "requires": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + } + }, "package-json": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", @@ -36675,13 +37730,13 @@ } }, "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", + "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, @@ -36840,7 +37895,7 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "performance-now": { "version": "2.1.0", @@ -37037,7 +38092,8 @@ "prism-react-renderer": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", - "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==" + "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", + "requires": {} }, "probe-image-size": { "version": "7.2.3", @@ -37118,6 +38174,28 @@ "ipaddr.js": "1.9.1" } }, + "proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "requires": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + } + } + }, "proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -37151,36 +38229,75 @@ } }, "puppeteer": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-13.7.0.tgz", - "integrity": "sha512-U1uufzBjz3+PkpCxFrWzh4OrMIdIb2ztzCu0YEPfRHjHswcSwHZswnK+WdsOQJsRV8WeTg3jLhJR4D867+fjsA==", - "requires": { - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.981744", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "pkg-dir": "4.2.0", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.5.0" + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.4.0.tgz", + "integrity": "sha512-E4JhJzjS8AAI+6N/b+Utwarhz6zWl3+MR725fal+s3UlOlX2eWdsvYYU+Q5bXMjs9eZEGkNQroLkn7j11s2k1Q==", + "requires": { + "@puppeteer/browsers": "2.8.0", + "chromium-bidi": "2.1.2", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1413902", + "puppeteer-core": "24.4.0", + "typed-query-selector": "^2.12.0" }, "dependencies": { - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "requires": { - "node-fetch": "2.6.7" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "puppeteer-core": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.4.0.tgz", + "integrity": "sha512-eFw66gCnWo0X8Hyf9KxxJtms7a61NJVMiSaWfItsFPzFBsjsWdmcNlBdsA1WVwln6neoHhsG+uTVesKmTREn/g==", + "requires": { + "@puppeteer/browsers": "2.8.0", + "chromium-bidi": "2.1.2", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1413902", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.1" + }, + "dependencies": { + "debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "requires": { + "ms": "^2.1.3" } }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==" + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "requires": {} } } }, @@ -37527,7 +38644,8 @@ "react-icons": { "version": "4.7.1", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.7.1.tgz", - "integrity": "sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==" + "integrity": "sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==", + "requires": {} }, "react-is": { "version": "16.13.1", @@ -37654,7 +38772,8 @@ "redux-thunk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==" + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "requires": {} }, "regenerate": { "version": "1.4.0", @@ -38818,6 +39937,11 @@ "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.5.tgz", "integrity": "sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ==" }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, "snake-case": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", @@ -38864,6 +39988,25 @@ "debug": "~4.3.1" } }, + "socks": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "requires": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "requires": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + } + }, "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -39064,6 +40207,16 @@ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" }, + "streamx": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", + "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", + "requires": { + "bare-events": "^2.2.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -39479,9 +40632,9 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", "requires": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -39591,6 +40744,14 @@ } } }, + "text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "requires": { + "b4a": "^1.6.4" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -39797,6 +40958,11 @@ "resolved": "https://registry.npmjs.org/type-of/-/type-of-2.0.1.tgz", "integrity": "sha1-5yoXQYllaOn2KDeNgW1pEvfyOXI=" }, + "typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -39810,6 +40976,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "peer": true + }, "ua-parser-js": { "version": "0.7.33", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", @@ -39826,15 +40998,6 @@ "which-boxed-primitive": "^1.0.2" } }, - "unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -40359,7 +41522,8 @@ "use-editable": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/use-editable/-/use-editable-2.3.3.tgz", - "integrity": "sha512-7wVD2JbfAFJ3DK0vITvXBdpd9JAz5BcKAAolsnLBuBn6UDDwBGuCIAGvR3yA2BNKm578vAMVHFCWaOcA+BhhiA==" + "integrity": "sha512-7wVD2JbfAFJ3DK0vITvXBdpd9JAz5BcKAAolsnLBuBn6UDDwBGuCIAGvR3yA2BNKm578vAMVHFCWaOcA+BhhiA==", + "requires": {} }, "util-deprecate": { "version": "1.0.2", @@ -40503,7 +41667,8 @@ "acorn-import-attributes": { "version": "1.9.5", "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==" + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "requires": {} }, "schema-utils": { "version": "3.3.0", @@ -40787,7 +41952,8 @@ "ws": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} }, "x-is-string": { "version": "0.1.0", @@ -40900,7 +42066,7 @@ "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -40946,6 +42112,11 @@ } } }, + "zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==" + }, "zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", diff --git a/docs/package.json b/docs/package.json index 21766c5f5406..cfd2de97c49e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -37,7 +37,7 @@ "postcss": "^8.4.31", "prism-react-renderer": "^1.3.5", "prop-types": "^15.8.1", - "puppeteer": "^13.7.0", + "puppeteer": "^24.4.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-headroom": "^3.2.1", diff --git a/docs/src/@rocketseat/gatsby-theme-docs/src/styles/global.js b/docs/src/@rocketseat/gatsby-theme-docs/src/styles/global.js index f1a5617fe722..6b6a61d464f9 100644 --- a/docs/src/@rocketseat/gatsby-theme-docs/src/styles/global.js +++ b/docs/src/@rocketseat/gatsby-theme-docs/src/styles/global.js @@ -66,6 +66,7 @@ export default function GlobalStyle() { font-weight: 400; } + span.inline-code, code.inline-code { display: inline-block; vertical-align: middle; diff --git a/docs/src/docs/contributing/architecture.mdx b/docs/src/docs/contributing/architecture.mdx index e9df647556da..e398db57e4e8 100644 --- a/docs/src/docs/contributing/architecture.mdx +++ b/docs/src/docs/contributing/architecture.mdx @@ -222,7 +222,7 @@ The abstraction is simple: ```go title=pkg/result/processors/processor.go type Processor interface { - Process(issues []result.Issue) ([]result.Issue, error) + Process(issues []*result.Issue) ([]*result.Issue, error) Name() string Finish() } diff --git a/docs/src/docs/contributing/new-linters.mdx b/docs/src/docs/contributing/new-linters.mdx index 8f90dd746fcf..57654e887f89 100644 --- a/docs/src/docs/contributing/new-linters.mdx +++ b/docs/src/docs/contributing/new-linters.mdx @@ -33,7 +33,7 @@ After that: 5. Take a look at the example of [pull requests with new linter support](https://github.com/golangci/golangci-lint/pulls?q=is%3Apr+is%3Amerged+label%3A%22linter%3A+new%22). 6. Run the tests: ```bash - go run ./cmd/golangci-lint/ run --no-config --disable-all --enable={yourlintername} ./pkg/golinters/{yourlintername}/testdata/{yourlintername}.go + go run ./cmd/golangci-lint/ run --no-config --default=none --enable={yourlintername} ./pkg/golinters/{yourlintername}/testdata/{yourlintername}.go ``` ## How to add a private linter to `golangci-lint` @@ -43,5 +43,5 @@ Typically, these linters can't be open-sourced or too specific. Such linters can be added through 2 plugin systems: -1. [Module Plugin System](/plugins/module-plugins) +1. [Module Plugin System](/plugins/module-plugins) (Recommended) 2. [Go Plugin System](/plugins/go-plugins) diff --git a/docs/src/docs/plugins/go-plugins.mdx b/docs/src/docs/plugins/go-plugins.mdx index a5df6b9b5b00..bf05d1fc92b4 100644 --- a/docs/src/docs/plugins/go-plugins.mdx +++ b/docs/src/docs/plugins/go-plugins.mdx @@ -2,6 +2,10 @@ title: Go Plugin System --- +**We recommend using [Module Plugin System](/plugins/module-plugins) instead of the Go Plugin System.** + +--- + Private linters can be added through [Go's plugin system](https://pkg.go.dev/plugin). For a private linter (which acts as a plugin) to work properly, @@ -48,29 +52,32 @@ An example linter can be found at [here](https://github.com/golangci/example-plu If you're looking for instructions on how to configure your own custom linter, they can be found further down. 1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/HEAD/.golangci.yml) to the root directory. -2. Adjust the YAML to appropriate `linters-settings.custom` entries as so: +2. Adjust the YAML to appropriate `linters.settings.custom` entries as so: ```yaml title=.golangci.yml - linters-settings: - custom: - example: - path: /example.so - description: The description of the linter - original-url: github.com/golangci/example-linter - settings: # Settings are optional. - one: Foo - two: - - name: Bar - three: - name: Bar + version: "2" + + linters: + settings: + custom: + example: + path: /example.so + description: The description of the linter + original-url: github.com/golangci/example-linter + settings: # Settings are optional. + one: Foo + two: + - name: Bar + three: + name: Bar ``` That is all the configuration that is required to run a custom linter in your project. Custom linters are enabled by default, but abide by the same rules as other linters. -If the disable all option is specified either on command line or in `.golang.yml` files `linters.disable-all: true`, custom linters will be disabled; +If the disable all option is specified either on command line or in `.golangci.yml` files `linters.default: none`, custom linters will be disabled; they can be re-enabled by adding them to the `linters.enable` list, or providing the enabled option on the command line, `golangci-lint run -Eexample`. -The configuration inside the `settings` field of linter have some limitations (there are NOT related to the plugin system itself): +The configuration inside the `linters.settings` field of linter have some limitations (there are NOT related to the plugin system itself): we use Viper to handle the configuration but Viper put all the keys in lowercase, and `.` cannot be used inside a key. diff --git a/docs/src/docs/plugins/module-plugins.mdx b/docs/src/docs/plugins/module-plugins.mdx index 44f3b40502e8..f6e4ad77d2c1 100644 --- a/docs/src/docs/plugins/module-plugins.mdx +++ b/docs/src/docs/plugins/module-plugins.mdx @@ -8,8 +8,8 @@ An example linter can be found at [here](https://github.com/golangci/example-plu - Define your building configuration into `.custom-gcl.yml`. - Run the command `golangci-lint custom` (or `golangci-lint custom -v` to have logs). -- Define the plugin inside the `linters-settings.custom` section with the type `module`. -- Run your custom version of golangci-lint. +- Define the plugin inside the `linters.settings.custom` section with the type `module`. +- Run the resulting custom binary of golangci-lint (`./custom-gcl` by default). Requirements: - Go @@ -31,18 +31,19 @@ plugins: ``` ```yaml title=.golangci.yml -linters-settings: - custom: - foo: - type: "module" - description: This is an example usage of a plugin linter. - settings: - message: hello +version: "2" linters: - disable-all: true + default: none enable: - foo + settings: + custom: + foo: + type: "module" + description: This is an example usage of a plugin linter. + settings: + message: hello ``` ## The Manual Way @@ -50,24 +51,25 @@ linters: - Add a blank-import of your module inside `cmd/golangci-lint/plugins.go`. - Run `go mod tidy` (the module containing the plugin will be imported). - Run `make build`. -- Define the plugin inside the configuration `linters-settings.custom` section with the type `module`. +- Define the plugin inside the `linters.settings.custom` section with the type `module`. - Run your custom version of golangci-lint. ### Configuration Example ```yaml title=.golangci.yml -linters-settings: - custom: - foo: - type: "module" - description: This is an example usage of a plugin linter. - settings: - message: hello +version: "2" linters: - disable-all: true + default: none enable: - foo + settings: + custom: + foo: + type: "module" + description: This is an example usage of a plugin linter. + settings: + message: hello ``` ## Reference diff --git a/docs/src/docs/product/migration-guide.mdx b/docs/src/docs/product/migration-guide.mdx index 963e1dd724fd..ac3da4cf6d2c 100644 --- a/docs/src/docs/product/migration-guide.mdx +++ b/docs/src/docs/product/migration-guide.mdx @@ -43,6 +43,8 @@ The `migrate` command enforces the following default values: Other fields explicitly defined in the configuration file are migrated even if the value is the same as the default value. +The `migrate` command automatically migrates `linters.presets` in individual linters to `linters.enable`. + ```txt Migrate configuration file from v1 to v2 @@ -189,7 +191,9 @@ There are 2 new options (they are not strictly equivalent to the previous option #### `linters.presets` -This property have been removed. +This property has been removed. + +The `migrate` command automatically migrates `linters.presets` in individual linters to `linters.enable`.
v1 @@ -2046,3 +2050,104 @@ version: "2" ```
+ +### Command Line Flags + +The following flags have been removed: + +- `--disable-all` +- `--enable-all` +- `-p, --presets` +- `--fast` +- `-e, --exclude` +- `--exclude-case-sensitive` +- `--exclude-dirs-use-default` +- `--exclude-dirs` +- `--exclude-files` +- `--exclude-generated` +- `--exclude-use-default` +- `--go string` +- `--sort-order` +- `--sort-results` +- `--out-format` + +#### `--out-format` + +`--out-format` has been replaced with the following flags: + +```bash +# Previously 'colored-line-number' and 'line-number' +--output.text.path +--output.text.print-linter-name +--output.text.print-issued-lines +--output.text.colors +``` + +```bash +# Previously 'json' +--output.json.path +``` + +```bash +# Previously 'colored-tab' and 'tab' +--output.tab.path +--output.tab.print-linter-name +--output.tab.colors +``` + +```bash +# Previously 'html' +--output.html.path +``` + +```bash +# Previously 'checkstyle' +--output.checkstyle.path +``` + +```bash +# Previously 'code-climate' +--output.code-climate.path +``` + +```bash +# Previously 'junit-xml' and 'junit-xml-extended' +--output.junit-xml.path +--output.junit-xml.extended +``` + +```bash +# Previously 'teamcity' +--output.teamcity.path +``` + +```bash +# Previously 'sarif' +--output.sarif.path +``` + +#### `--disable-all` and `--enable-all` + +`--disable-all` has been replaced with `--default=none`. + +`--enable-all` has been replaced with `--default=all`. + +#### Example + +
+ v1 + +```bash +golangci-lint run --disable-all --enable=govet --out-format=json --sort-order=linter --sort-results +``` + +
+ +
+ v2 + +```bash +golangci-lint run --default=none --enable=govet --output.json.path=stdout +``` + +
diff --git a/docs/src/docs/product/roadmap.mdx b/docs/src/docs/product/roadmap.mdx index e1b1b15a3836..91a5fc413cbf 100644 --- a/docs/src/docs/product/roadmap.mdx +++ b/docs/src/docs/product/roadmap.mdx @@ -50,7 +50,7 @@ The deprecation of a linter will follow 3 phases: but it's recommended to remove it from your configuration. 2. **Display of an error message**: At this point, you should remove the linter. The original implementation is replaced by a placeholder that does nothing. - The linter is NOT enabled when using `enable-all` and should be removed from the `disable` option. + The linter is NOT enabled when using `default: all` and should be removed from the `disable` option. 3. **Removal of the linter** from golangci-lint. Each phase corresponds to a minor version: diff --git a/docs/src/docs/product/thanks.mdx b/docs/src/docs/product/thanks.mdx index 3c1531c1b75c..2fb14b7d4f8c 100644 --- a/docs/src/docs/product/thanks.mdx +++ b/docs/src/docs/product/thanks.mdx @@ -12,3 +12,5 @@ Thanks to developers and authors of used linters: Thanks to [alecthomas/gometalinter](https://github.com/alecthomas/gometalinter) for inspiration and amazing work. Thanks to [bradleyfalzon/revgrep](https://github.com/bradleyfalzon/revgrep) for cool diff tool. + +The golangci-lint logo is inspired by the Go gopher designed by Renee French [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/). diff --git a/docs/src/docs/usage/configuration.mdx b/docs/src/docs/usage/configuration.mdx index fbc4b889b704..276480ad7d7c 100644 --- a/docs/src/docs/usage/configuration.mdx +++ b/docs/src/docs/usage/configuration.mdx @@ -42,14 +42,6 @@ The configuration file can be validated with the JSON Schema: https://golangci-l { .ConfigurationExample } -### `version` configuration - -```yaml -# Defines the configuration version. -# The only possible value is "2". -version: "2" -``` - ## Command-Line Options ### run diff --git a/docs/src/docs/usage/false-positives.mdx b/docs/src/docs/usage/false-positives.mdx index d01cdc9a13b2..bf542a9a406f 100644 --- a/docs/src/docs/usage/false-positives.mdx +++ b/docs/src/docs/usage/false-positives.mdx @@ -3,7 +3,6 @@ title: False Positives --- False positives are inevitable, but we did our best to reduce their count. -For example, we have a default enabled set of [exclude patterns](/usage/configuration#command-line-options). If a false positive occurred, you have the several choices. @@ -17,106 +16,98 @@ Otherwise, some linters have dedicated configuration to exclude or disable rules An example with `staticcheck`: ```yaml -linters-settings: - staticcheck: - checks: - - all - - '-SA1000' # disable the rule SA1000 - - '-SA1004' # disable the rule SA1004 +linters: + settings: + staticcheck: + checks: + - all + - '-SA1000' # disable the rule SA1000 + - '-SA1004' # disable the rule SA1004 ``` -## Exclude or Skip +## Exclude ### Exclude Issue by Text -Exclude issue by text using command-line option `-e` or config option `issues.exclude`. -It's helpful when you decided to ignore all issues of this type. -Also, you can use `issues.exclude-rules` config option for per-path or per-linter configuration. - -In the following example, all the reports that contains the sentences defined in `exclude` are excluded: - -```yaml -issues: - exclude: - - "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked" - - "exported (type|method|function) (.+) should have comment or be unexported" - - "ST1000: at least one file in a package should have a package comment" -``` +You can use `linters.exclusions.rules` config option for per-path or per-linter configuration. In the following example, all the reports from the linters (`linters`) that contains the text (`text`) are excluded: ```yaml -issues: - exclude-rules: - - linters: - - mnd - text: "Magic number: 9" +linters: + exclusions: + rules: + - linters: + - mnd + text: "Magic number: 9" ``` In the following example, all the reports from the linters (`linters`) that originated from the source (`source`) are excluded: ```yaml -issues: - exclude-rules: - - linters: - - lll - source: "^//go:generate " +linters: + exclusions: + rules: + - linters: + - lll + source: "^//go:generate " ``` In the following example, all the reports that contains the text (`text`) in the path (`path`) are excluded: ```yaml -issues: - exclude-rules: - - path: path/to/a/file.go - text: "string `example` has (\\d+) occurrences, make it a constant" +linters: + exclusions: + rules: + - path: path/to/a/file.go + text: "string `example` has (\\d+) occurrences, make it a constant" ``` ### Exclude Issues by Path -Exclude issues in path by `issues.exclude-dirs`, `issues.exclude-files` or `issues.exclude-rules` config options. - -Beware that the paths that get matched here are relative to the current working directory. -When the configuration contains path patterns that check for specific directories, -the `--path-prefix` parameter can be used to extend the paths before matching. +Exclude issues in path by `linters.exclusions.paths` or `linters.exclusions.rules` config options. In the following example, all the reports from the linters (`linters`) that concerns the path (`path`) are excluded: ```yaml -issues: - exclude-rules: - - path: '(.+)_test\.go' - linters: - - funlen - - goconst +linters: + exclusions: + rules: + - path: '(.+)_test\.go' + linters: + - funlen + - goconst ``` The opposite, excluding reports **except** for specific paths, is also possible. In the following example, only test files get checked: ```yaml -issues: - exclude-rules: - - path-except: '(.+)_test\.go' - linters: - - funlen - - goconst +linters: + exclusions: + rules: + - path-except: '(.+)_test\.go' + linters: + - funlen + - goconst ``` -In the following example, all the reports related to the files (`exclude-files`) are excluded: +In the following example, all the reports related to the files (`paths`) are excluded: ```yaml -issues: - exclude-files: - - path/to/a/file.go +linters: + exclusions: + paths: + - path/to/a/file.go ``` -In the following example, all the reports related to the directories (`exclude-dirs`) are excluded: +In the following example, all the reports related to the directories (`paths`) are excluded: ```yaml -issues: - exclude-dirs: - - path/to/a/dir/ +linters: + exclusions: + paths: + - path/to/a/dir/ ``` ## Nolint Directive @@ -131,7 +122,7 @@ var bad_name int //nolint:all To exclude issues from specific linters only: ```go -var bad_name int //nolint:golint,unused +var bad_name int //nolint:wsl,unused ``` To exclude issues for the block of code use this directive on the beginning of a line: diff --git a/docs/src/docs/welcome/faq.mdx b/docs/src/docs/welcome/faq.mdx index 46e57aacdbaa..62109ac5afb7 100644 --- a/docs/src/docs/welcome/faq.mdx +++ b/docs/src/docs/welcome/faq.mdx @@ -33,7 +33,7 @@ it's just a way to identify, parse, and display compiling errors (produced by th It cannot be disabled because of that. -Of course, this is just as good as the compiler itself and a lot of compilation issues will not properly show where in the code your error lies. +Of course, this is just as good as the compiler itself, and a lot of compilation issues will not properly show where in the code your error lies. As a consequence, the code to analyze should compile. It means that if you try to run an analysis on a single file or a group of files or a package or a group of packages, @@ -45,10 +45,11 @@ If there are `typecheck` errors, golangci-lint will not be able to produce other How to troubleshoot: - [ ] Ensure the version of golangci-lint is built with a compatible version of Go. -- [ ] Ensure dependencies are up-to-date with `go mod tidy`. +- [ ] Ensure dependencies are up to date with `go mod tidy`. - [ ] Ensure building works with `go run ./...`/`go build ./...` - whole package. - [ ] Ensure you are not running an analysis on code that depends on files/packages outside the scope of the analyzed elements. - [ ] If using CGO, ensure all require system libraries are installed. +- [ ] If you are using private repositories/dependencies, ensure the [Go proxy](https://go.dev/ref/mod#module-proxy) (`GOPROXY`) and [checksum database](https://go.dev/ref/mod#checksum-database) (`GOSUMDB`) are right and/or your git configuration. ## Why is it not possible to skip/ignore `typecheck` errors? diff --git a/docs/src/docs/welcome/install.mdx b/docs/src/docs/welcome/install.mdx index 335443a92403..c67c1dbf971a 100644 --- a/docs/src/docs/welcome/install.mdx +++ b/docs/src/docs/welcome/install.mdx @@ -203,7 +203,7 @@ go tool -modfile=golangci-lint.mod golangci-lint run ```sh # Update golangci-lint -go get -tool -modfile=golangci-lint.mod github.com/golangci/v2/golangci-lint/cmd/golangci-lint@latest +go get -tool -modfile=golangci-lint.mod github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest ``` **Method 2: dedicated module** diff --git a/docs/src/docs/welcome/integrations.mdx b/docs/src/docs/welcome/integrations.mdx index ba7c372fb2e9..03e6d7e8d57e 100644 --- a/docs/src/docs/welcome/integrations.mdx +++ b/docs/src/docs/welcome/integrations.mdx @@ -6,18 +6,24 @@ title: Integrations ### GoLand -Install [plugin](https://plugins.jetbrains.com/plugin/12496-go-linter). +Starting from version 2025.1, GoLand has built-in support of golangci-lint. +For IntelliJ IDEA with the Go plugin, please install the [plugin](https://plugins.jetbrains.com/plugin/12496-go-linter). + +Both v1 and v2 versions are supported. ### Visual Studio Code Install the [extension](https://marketplace.visualstudio.com/items?itemName=golang.Go). +**Note:** To use golangci-lint v2, you may need to switch to the pre-release version of the extension: [vscode-go#3732](https://github.com/golang/vscode-go/issues/3732#issuecomment-2805974456). +
-Recommended settings +Recommended settings for those who installed golangci-lint manually ```json "go.lintTool": "golangci-lint", "go.lintFlags": [ + "--path-mode=abs", "--fast-only" ], "go.formatTool": "custom", @@ -31,7 +37,35 @@ Install the [extension](https://marketplace.visualstudio.com/items?itemName=gola ``` Using it in an editor without `--fast-only` can freeze your editor. -Golangci-lint automatically discovers `.golangci.yml` config for edited file: you don't need to configure it in VS Code settings. +Golangci-lint automatically discovers the `.golangci.yml` config for the edited file, so you don't need to configure it in VS Code settings. + +
+ +
+Recommended settings for those who installed golangci-lint via extension + +Install `golangci-lint-v2` via the `Go: Install/Update Tools` command after setting these configs. +This will enable golangci-lint v1 to co-exist with v2. +And use the following settings: + +```json +"go.lintTool": "golangci-lint-v2", +"go.lintFlags": [ + "--path-mode=abs", + "--fast-only" +], +"go.formatTool": "custom", +"go.alternateTools": { + "customFormatter": "golangci-lint-v2" +}, +"go.formatFlags": [ + "fmt", + "--stdin" +] +``` + +Using it in an editor without `--fast-only` can freeze your editor. +Golangci-lint automatically discovers the `.golangci.yml` config for the edited file, so you don't need to configure it in VS Code settings.
diff --git a/docs/src/docs/welcome/quick-start.mdx b/docs/src/docs/welcome/quick-start.mdx index cf59865450d4..cf2f04045cf9 100644 --- a/docs/src/docs/welcome/quick-start.mdx +++ b/docs/src/docs/welcome/quick-start.mdx @@ -37,7 +37,7 @@ $ golangci-lint help linters Pass `-E/--enable` to enable linter and `-D/--disable` to disable: ```bash -golangci-lint run --disable-all -E errcheck +golangci-lint run --default=none -E errcheck ``` More information about available linters can be found in the [linters page](/usage/linters/). diff --git a/docs/static/demo.gif b/docs/static/demo.gif index 8a255c90e834..d9fccbf5921c 100644 Binary files a/docs/static/demo.gif and b/docs/static/demo.gif differ diff --git a/go.mod b/go.mod index 33e81653d8a7..72dd9208d831 100644 --- a/go.mod +++ b/go.mod @@ -6,28 +6,29 @@ require ( 4d63.com/gocheckcompilerdirectives v1.3.0 4d63.com/gochecknoglobals v0.2.2 github.com/4meepo/tagalign v1.4.2 - github.com/Abirdcfly/dupword v0.1.3 + github.com/Abirdcfly/dupword v0.1.6 + github.com/AlwxSin/noinlineerr v1.0.3 github.com/Antonboom/errname v1.1.0 github.com/Antonboom/nilnil v1.1.0 - github.com/Antonboom/testifylint v1.6.0 + github.com/Antonboom/testifylint v1.6.1 github.com/BurntSushi/toml v1.5.0 - github.com/Crocmagnon/fatcontext v0.7.1 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 github.com/OpenPeeDeeP/depguard/v2 v2.2.1 + github.com/alecthomas/chroma/v2 v2.18.0 github.com/alecthomas/go-check-sumtype v0.3.1 - github.com/alexkohler/nakedret/v2 v2.0.5 + github.com/alexkohler/nakedret/v2 v2.0.6 github.com/alexkohler/prealloc v1.0.0 github.com/alingse/asasalint v0.0.11 - github.com/alingse/nilnesserr v0.1.2 - github.com/ashanbrown/forbidigo v1.6.0 - github.com/ashanbrown/makezero v1.2.0 + github.com/alingse/nilnesserr v0.2.0 + github.com/ashanbrown/forbidigo/v2 v2.1.0 + github.com/ashanbrown/makezero/v2 v2.0.1 github.com/bkielbasa/cyclop v1.2.3 github.com/blizzy78/varnamelen v0.8.0 - github.com/bombsimon/wsl/v4 v4.6.0 + github.com/bombsimon/wsl/v4 v4.7.0 github.com/breml/bidichk v0.3.3 github.com/breml/errchkjson v0.4.1 - github.com/butuzov/ireturn v0.3.1 + github.com/butuzov/ireturn v0.4.0 github.com/butuzov/mirror v1.3.0 github.com/catenacyber/perfsprint v0.9.1 github.com/charithe/durationcheck v0.0.10 @@ -37,9 +38,9 @@ require ( github.com/daixiang0/gci v0.13.6 github.com/denis-tingaikin/go-header v0.5.0 github.com/fatih/color v1.18.0 - github.com/firefart/nonamedreturns v1.0.5 + github.com/firefart/nonamedreturns v1.0.6 github.com/fzipp/gocyclo v0.6.0 - github.com/ghostiam/protogetter v0.3.12 + github.com/ghostiam/protogetter v0.3.15 github.com/go-critic/go-critic v0.13.0 github.com/go-viper/mapstructure/v2 v2.2.1 github.com/go-xmlfmt/xmlfmt v1.1.3 @@ -48,58 +49,61 @@ require ( github.com/golangci/go-printf-func-name v0.1.0 github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 - github.com/golangci/misspell v0.6.0 - github.com/golangci/plugin-module-register v0.1.1 + github.com/golangci/misspell v0.7.0 + github.com/golangci/plugin-module-register v0.1.2 github.com/golangci/revgrep v0.8.0 - github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed + github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e + github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e github.com/gordonklaus/ineffassign v0.1.0 github.com/gostaticanalysis/forcetypeassert v0.2.0 github.com/gostaticanalysis/nilerr v0.1.1 github.com/hashicorp/go-version v1.7.0 - github.com/jgautheron/goconst v1.7.1 + github.com/jgautheron/goconst v1.8.2 github.com/jingyugao/rowserrcheck v1.1.1 - github.com/jjti/go-spancheck v0.6.4 + github.com/jjti/go-spancheck v0.6.5 github.com/julz/importas v0.2.0 github.com/karamaru-alpha/copyloopvar v1.2.1 github.com/kisielk/errcheck v1.9.0 github.com/kkHAIKE/contextcheck v1.1.6 github.com/kulti/thelper v0.6.3 - github.com/kunwardeep/paralleltest v1.0.10 + github.com/kunwardeep/paralleltest v1.0.14 github.com/lasiar/canonicalheader v1.1.2 - github.com/ldez/exptostd v0.4.2 - github.com/ldez/gomoddirectives v0.6.1 + github.com/ldez/exptostd v0.4.3 + github.com/ldez/gomoddirectives v0.7.0 github.com/ldez/grignotin v0.9.0 github.com/ldez/tagliatelle v0.7.1 - github.com/ldez/usetesting v0.4.2 + github.com/ldez/usetesting v0.4.3 github.com/leonklingele/grouper v1.1.2 github.com/macabu/inamedparam v0.2.0 + github.com/manuelarte/embeddedstructfieldcheck v0.3.0 + github.com/manuelarte/funcorder v0.5.0 github.com/maratori/testableexamples v1.0.0 github.com/maratori/testpackage v1.1.1 github.com/matoous/godox v1.1.0 github.com/mattn/go-colorable v0.1.14 - github.com/mgechev/revive v1.7.0 + github.com/mgechev/revive v1.10.0 github.com/mitchellh/go-homedir v1.1.0 github.com/moricho/tparallel v0.3.2 github.com/nakabonne/nestif v0.3.1 github.com/nishanths/exhaustive v0.12.0 github.com/nishanths/predeclared v0.2.2 github.com/nunnatsa/ginkgolinter v0.19.1 - github.com/pelletier/go-toml/v2 v2.2.3 - github.com/polyfloyd/go-errorlint v1.7.1 + github.com/pelletier/go-toml/v2 v2.2.4 + github.com/polyfloyd/go-errorlint v1.8.0 github.com/quasilyte/go-ruleguard/dsl v0.3.22 github.com/raeperd/recvcheck v0.2.0 github.com/rogpeppe/go-internal v1.14.1 github.com/ryancurrah/gomodguard v1.4.1 github.com/ryanrolds/sqlclosecheck v0.5.1 github.com/sanposhiho/wastedassign/v2 v2.1.0 - github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 github.com/sashamelentyev/interfacebloat v1.1.0 - github.com/sashamelentyev/usestdlibvars v1.28.0 - github.com/securego/gosec/v2 v2.22.2 - github.com/shirou/gopsutil/v4 v4.25.2 + github.com/sashamelentyev/usestdlibvars v1.29.0 + github.com/securego/gosec/v2 v2.22.4 + github.com/shirou/gopsutil/v4 v4.25.5 github.com/sirupsen/logrus v1.9.3 github.com/sivchari/containedctx v1.0.3 - github.com/sonatard/noctx v0.1.0 + github.com/sonatard/noctx v0.3.3 github.com/sourcegraph/go-diff v0.7.0 github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.6 @@ -108,47 +112,50 @@ require ( github.com/stbenjam/no-sprintf-host-port v0.2.0 github.com/stretchr/testify v1.10.0 github.com/tdakkota/asciicheck v0.4.1 - github.com/tetafro/godot v1.5.0 + github.com/tetafro/godot v1.5.1 github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 - github.com/timonwong/loggercheck v0.10.1 - github.com/tomarrell/wrapcheck/v2 v2.10.0 + github.com/timonwong/loggercheck v0.11.0 + github.com/tomarrell/wrapcheck/v2 v2.11.0 github.com/tommy-muehle/go-mnd/v2 v2.5.1 github.com/ultraware/funlen v0.2.0 github.com/ultraware/whitespace v0.2.0 github.com/uudashr/gocognit v1.2.0 - github.com/uudashr/iface v1.3.1 + github.com/uudashr/iface v1.4.0 github.com/valyala/quicktemplate v1.8.0 github.com/xen0n/gosmopolitan v1.3.0 github.com/yagipy/maintidx v1.0.0 github.com/yeya24/promlinter v0.3.0 github.com/ykadowak/zerologlint v0.1.5 gitlab.com/bosi/decorder v0.4.2 - go-simpler.org/musttag v0.13.0 - go-simpler.org/sloglint v0.9.0 + go-simpler.org/musttag v0.13.1 + go-simpler.org/sloglint v0.11.0 + go.augendre.info/arangolint v0.2.0 + go.augendre.info/fatcontext v0.8.0 go.uber.org/automaxprocs v1.6.0 - golang.org/x/mod v0.24.0 - golang.org/x/sys v0.31.0 - golang.org/x/tools v0.31.0 + golang.org/x/mod v0.25.0 + golang.org/x/sys v0.33.0 + golang.org/x/tools v0.34.0 gopkg.in/yaml.v3 v3.0.1 honnef.co/go/tools v0.6.1 - mvdan.cc/gofumpt v0.7.0 + mvdan.cc/gofumpt v0.8.0 mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 ) require ( + codeberg.org/chavacava/garif v0.2.0 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/ccojocar/zxcvbn-go v1.0.2 // indirect + github.com/ccojocar/zxcvbn-go v1.0.4 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/term v0.2.1 // indirect - github.com/chavacava/garif v0.1.0 // indirect github.com/dave/dst v0.27.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/ebitengine/purego v0.8.2 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -178,7 +185,6 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/muesli/termenv v0.16.0 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect @@ -191,7 +197,7 @@ require ( github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/afero v1.14.0 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/stretchr/objx v0.5.2 // indirect @@ -206,9 +212,9 @@ require ( go.uber.org/zap v1.24.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/text v0.23.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 9662b6c7db46..8cde5e69bf0e 100644 --- a/go.sum +++ b/go.sum @@ -34,23 +34,25 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= +codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/4meepo/tagalign v1.4.2 h1:0hcLHPGMjDyM1gHG58cS73aQF8J4TdVR96TZViorO9E= github.com/4meepo/tagalign v1.4.2/go.mod h1:+p4aMyFM+ra7nb41CnFG6aSDXqRxU/w1VQqScKqDARI= -github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE= -github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw= +github.com/Abirdcfly/dupword v0.1.6 h1:qeL6u0442RPRe3mcaLcbaCi2/Y/hOcdtw6DE9odjz9c= +github.com/Abirdcfly/dupword v0.1.6/go.mod h1:s+BFMuL/I4YSiFv29snqyjwzDp4b65W2Kvy+PKzZ6cw= +github.com/AlwxSin/noinlineerr v1.0.3 h1:9b5edChzzwX30BuBci13LHVZHF5q7hW9qtrs+wJdDog= +github.com/AlwxSin/noinlineerr v1.0.3/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= github.com/Antonboom/errname v1.1.0 h1:A+ucvdpMwlo/myWrkHEUEBWc/xuXdud23S8tmTb/oAE= github.com/Antonboom/errname v1.1.0/go.mod h1:O1NMrzgUcVBGIfi3xlVuvX8Q/VP/73sseCaAppfjqZw= github.com/Antonboom/nilnil v1.1.0 h1:jGxJxjgYS3VUUtOTNk8Z1icwT5ESpLH/426fjmQG+ng= github.com/Antonboom/nilnil v1.1.0/go.mod h1:b7sAlogQjFa1wV8jUW3o4PMzDVFLbTux+xnQdvzdcIE= -github.com/Antonboom/testifylint v1.6.0 h1:6rdILVPt4+rqcvhid8w9wJNynKLUgqHNpFyM67UeXyc= -github.com/Antonboom/testifylint v1.6.0/go.mod h1:k+nEkathI2NFjKO6HvwmSrbzUcQ6FAnbZV+ZRrnXPLI= +github.com/Antonboom/testifylint v1.6.1 h1:6ZSytkFWatT8mwZlmRCHkWz1gPi+q6UBSbieji2Gj/o= +github.com/Antonboom/testifylint v1.6.1/go.mod h1:k+nEkathI2NFjKO6HvwmSrbzUcQ6FAnbZV+ZRrnXPLI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Crocmagnon/fatcontext v0.7.1 h1:SC/VIbRRZQeQWj/TcQBS6JmrXcfA+BU4OGSVUt54PjM= -github.com/Crocmagnon/fatcontext v0.7.1/go.mod h1:1wMvv3NXEBJucFGfwOJBxSVWcoIO6emV215SMkW9MFU= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 h1:Sz1JIXEcSfhz7fUi7xHnhpIE0thVASYjvosApmHuD2k= @@ -61,6 +63,8 @@ github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsu github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4= +github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -70,18 +74,18 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU= -github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= +github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= +github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= -github.com/alingse/nilnesserr v0.1.2 h1:Yf8Iwm3z2hUUrP4muWfW83DF4nE3r1xZ26fGWUKCZlo= -github.com/alingse/nilnesserr v0.1.2/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= -github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= -github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= -github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU= -github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4= +github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= +github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= +github.com/ashanbrown/forbidigo/v2 v2.1.0 h1:NAxZrWqNUQiDz19FKScQ/xvwzmij6BiOw3S0+QUQ+Hs= +github.com/ashanbrown/forbidigo/v2 v2.1.0/go.mod h1:0zZfdNAuZIL7rSComLGthgc/9/n2FqspBOH90xlCHdA= +github.com/ashanbrown/makezero/v2 v2.0.1 h1:r8GtKetWOgoJ4sLyUx97UTwyt2dO7WkGFHizn/Lo8TY= +github.com/ashanbrown/makezero/v2 v2.0.1/go.mod h1:kKU4IMxmYW1M4fiEHMb2vc5SFoPzXvgbMR9gIp5pjSw= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= @@ -94,20 +98,20 @@ github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5 github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v4 v4.6.0 h1:ew2R/N42su553DKTYqt3HSxaQN+uHQPv4xZ2MBmwaW4= -github.com/bombsimon/wsl/v4 v4.6.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= +github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= +github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= -github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY= -github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M= +github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E= +github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70= github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= github.com/catenacyber/perfsprint v0.9.1 h1:5LlTp4RwTooQjJCvGEFV6XksZvWE7wCOUvjD2z0vls0= github.com/catenacyber/perfsprint v0.9.1/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM= -github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= -github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= +github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= +github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -125,8 +129,6 @@ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0G github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= -github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= -github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -148,10 +150,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= -github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -162,16 +164,16 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= -github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= +github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= +github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghostiam/protogetter v0.3.12 h1:xTPjH97iKph27vXRRKV0OCke5sAMoHPbVeVstdzmCLE= -github.com/ghostiam/protogetter v0.3.12/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= +github.com/ghostiam/protogetter v0.3.15 h1:1KF5sXel0HE48zh1/vn0Loiw25A9ApyseLzQuif1mLY= +github.com/ghostiam/protogetter v0.3.15/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= github.com/go-critic/go-critic v0.13.0 h1:kJzM7wzltQasSUXtYyTl6UaPVySO6GkaR1thFnJ6afY= github.com/go-critic/go-critic v0.13.0/go.mod h1:M/YeuJ3vOCQDnP2SU+ZhjgRzwzcBW87JqLpMJLrZDLI= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -257,14 +259,16 @@ github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0a github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 h1:AkK+w9FZBXlU/xUmBtSJN1+tAI4FIvy5WtnUnY8e4p8= github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95/go.mod h1:k9mmcyWKSTMcPPvQUCfRWWQ9VHJ1U9Dc0R7kaXAgtnQ= -github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= -github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= -github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= -github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= +github.com/golangci/misspell v0.7.0 h1:4GOHr/T1lTW0hhR4tgaaV1WS/lJ+ncvYCoFKmqJsj0c= +github.com/golangci/misspell v0.7.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg= +github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg= +github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= +github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM= +github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= +github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM= +github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -291,8 +295,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -329,12 +333,12 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= -github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4= +github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc= -github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk= +github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= +github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -365,20 +369,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= -github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= -github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kunwardeep/paralleltest v1.0.14 h1:wAkMoMeGX/kGfhQBPODT/BL8XhK23ol/nuQ3SwFaUw8= +github.com/kunwardeep/paralleltest v1.0.14/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= -github.com/ldez/exptostd v0.4.2 h1:l5pOzHBz8mFOlbcifTxzfyYbgEmoUqjxLFHZkjlbHXs= -github.com/ldez/exptostd v0.4.2/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ= -github.com/ldez/gomoddirectives v0.6.1 h1:Z+PxGAY+217f/bSGjNZr/b2KTXcyYLgiWI6geMBN2Qc= -github.com/ldez/gomoddirectives v0.6.1/go.mod h1:cVBiu3AHR9V31em9u2kwfMKD43ayN5/XDgr+cdaFaKs= +github.com/ldez/exptostd v0.4.3 h1:Ag1aGiq2epGePuRJhez2mzOpZ8sI9Gimcb4Sb3+pk9Y= +github.com/ldez/exptostd v0.4.3/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ= +github.com/ldez/gomoddirectives v0.7.0 h1:EOx8Dd56BZYSez11LVgdj025lKwlP0/E5OLSl9HDwsY= +github.com/ldez/gomoddirectives v0.7.0/go.mod h1:wR4v8MN9J8kcwvrkzrx6sC9xe9Cp68gWYCsda5xvyGc= github.com/ldez/grignotin v0.9.0 h1:MgOEmjZIVNn6p5wPaGp/0OKWyvq42KnzAt/DAb8O4Ow= github.com/ldez/grignotin v0.9.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk= github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk= github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I= -github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA= -github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ= +github.com/ldez/usetesting v0.4.3 h1:pJpN0x3fMupdTf/IapYjnkhiY1nSTN+pox1/GyBRw3k= +github.com/ldez/usetesting v0.4.3/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -389,6 +393,10 @@ github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddB github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/manuelarte/embeddedstructfieldcheck v0.3.0 h1:VhGqK8gANDvFYDxQkjPbv7/gDJtsGU9k6qj/hC2hgso= +github.com/manuelarte/embeddedstructfieldcheck v0.3.0/go.mod h1:LSo/IQpPfx1dXMcX4ibZCYA7Yy6ayZHIaOGM70+1Wy8= +github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8= +github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= @@ -401,13 +409,12 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY= -github.com/mgechev/revive v1.7.0/go.mod h1:qZnwcNhoguE58dfi96IJeSTPeZQejNeoMQLUZGi4SW4= +github.com/mgechev/revive v1.10.0 h1:x2oJsd7yrDp0mC6IgZqSKBTjSUC9Zk5Ob2WfBwZic2I= +github.com/mgechev/revive v1.10.0/go.mod h1:1MRO9zUV7Yukhqh/nGRKSaw6xC5XDzPWPja5GMPWoSE= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -431,12 +438,10 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.19.1 h1:mjwbOlDQxZi9Cal+KfbEJTCz327OLNfwNvoZ70NJ+c4= github.com/nunnatsa/ginkgolinter v0.19.1/go.mod h1:jkQ3naZDmxaZMXPWaS9rblH+i+GWXQCaS/JFIWcOH2s= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= @@ -446,16 +451,16 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.7.1 h1:RyLVXIbosq1gBdk/pChWA8zWYLsq9UEw7a1L5TVMCnA= -github.com/polyfloyd/go-errorlint v1.7.1/go.mod h1:aXjNb1x2TNhoLsk26iv1yl7a+zTnXPhwEMtEXukiLR8= +github.com/polyfloyd/go-errorlint v1.8.0 h1:DL4RestQqRLr8U4LygLw8g2DX6RN1eBJOpa2mzsrl1Q= +github.com/polyfloyd/go-errorlint v1.8.0/go.mod h1:G2W0Q5roxbLCt0ZQbdoxQxXktTjwNyDbEaj3n7jvl4s= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= @@ -507,18 +512,18 @@ github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9f github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ= -github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= -github.com/securego/gosec/v2 v2.22.2 h1:IXbuI7cJninj0nRpZSLCUlotsj8jGusohfONMrHoF6g= -github.com/securego/gosec/v2 v2.22.2/go.mod h1:UEBGA+dSKb+VqM6TdehR7lnQtIIMorYJ4/9CW1KVQBE= +github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= +github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= +github.com/securego/gosec/v2 v2.22.4 h1:21VdNGcKicFSv6rUDBc0cEtEl7lWyCKZxKIm0iwvrIM= +github.com/securego/gosec/v2 v2.22.4/go.mod h1:ww5Yie7KJ3AH8XZQTletkW5zOmIse6FACs/Ys8VR3qE= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil/v4 v4.25.2 h1:NMscG3l2CqtWFS86kj3vP7soOczqrQYIEhO/pMvvQkk= -github.com/shirou/gopsutil/v4 v4.25.2/go.mod h1:34gBYJzyqCDT11b6bMHP0XCvWeU3J61XRT7a2EmCRTA= +github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= +github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -528,12 +533,12 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM= -github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c= +github.com/sonatard/noctx v0.3.3 h1:9+wFUxZfjiCdNadFaGH55sa7Y1r6yKZiAsUVmCP+tjw= +github.com/sonatard/noctx v0.3.3/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= @@ -551,18 +556,12 @@ github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8B github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= @@ -573,18 +572,18 @@ github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.5.0 h1:aNwfVI4I3+gdxjMgYPus9eHmoBeJIbnajOyqZYStzuw= -github.com/tetafro/godot v1.5.0/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/tetafro/godot v1.5.1 h1:PZnjCol4+FqaEzvZg5+O8IY2P3hfY9JzRBNPv1pEDS4= +github.com/tetafro/godot v1.5.1/go.mod h1:cCdPtEndkmqqrhiCfkmxDodMQJ/f3L1BCNskCUZdTwk= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= -github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg= -github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= +github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= +github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg= -github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/tomarrell/wrapcheck/v2 v2.11.0 h1:BJSt36snX9+4WTIXeJ7nvHBQBcm1h2SjQMSlmQ6aFSU= +github.com/tomarrell/wrapcheck/v2 v2.11.0/go.mod h1:wFL9pDWDAbXhhPZZt+nG8Fu+h29TtnZ2MW6Lx4BRXIU= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI= @@ -593,8 +592,8 @@ github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSW github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA= github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU= -github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U= -github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg= +github.com/uudashr/iface v1.4.0 h1:ImZ+1oEJPXvjap7nK0md7gA9RRH7PMp4vliaLkJ2+cg= +github.com/uudashr/iface v1.4.0/go.mod h1:i/H4cfRMPe0izticV8Yz0g6/zcsh5xXlvthrdh1kqcY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= @@ -622,10 +621,14 @@ gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= -go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE= -go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM= -go-simpler.org/sloglint v0.9.0 h1:/40NQtjRx9txvsB/RN022KsUJU+zaaSb/9q9BSefSrE= -go-simpler.org/sloglint v0.9.0/go.mod h1:G/OrAF6uxj48sHahCzrbarVMptL2kjWTaUeC8+fOGww= +go-simpler.org/musttag v0.13.1 h1:lw2sJyu7S1X8lc8zWUAdH42y+afdcCnHhWpnkWvd6vU= +go-simpler.org/musttag v0.13.1/go.mod h1:8r450ehpMLQgvpb6sg+hV5Ur47eH6olp/3yEanfG97k= +go-simpler.org/sloglint v0.11.0 h1:JlR1X4jkbeaffiyjLtymeqmGDKBDO1ikC6rjiuFAOco= +go-simpler.org/sloglint v0.11.0/go.mod h1:CFDO8R1i77dlciGfPEPvYke2ZMx4eyGiEIWkyeW2Pvw= +go.augendre.info/arangolint v0.2.0 h1:2NP/XudpPmfBhQKX4rMk+zDYIj//qbt4hfZmSSTcpj8= +go.augendre.info/arangolint v0.2.0/go.mod h1:Vx4KSJwu48tkE+8uxuf0cbBnAPgnt8O1KWiT7bljq7w= +go.augendre.info/fatcontext v0.8.0 h1:2dfk6CQbDGeu1YocF59Za5Pia7ULeAM6friJ3LP7lmk= +go.augendre.info/fatcontext v0.8.0/go.mod h1:oVJfMgwngMsHO+KB2MdgzcO+RvtNdiCEOlWvSFtax/s= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -690,13 +693,11 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -731,14 +732,12 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -760,8 +759,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -810,20 +809,17 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= @@ -834,13 +830,11 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -895,13 +889,11 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -981,8 +973,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1011,8 +1003,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= -mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= -mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= +mvdan.cc/gofumpt v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k= +mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg= mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8= mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5ginj6dA2oLE7YNlta9qhBNNdCaLE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/jsonschema/golangci.jsonschema.json b/jsonschema/golangci.jsonschema.json index 776a489afd98..0f2ef5fcc50b 100644 --- a/jsonschema/golangci.jsonschema.json +++ b/jsonschema/golangci.jsonschema.json @@ -490,7 +490,6 @@ "G110", "G111", "G112", - "G113", "G114", "G115", "G201", @@ -540,6 +539,7 @@ "fieldalignment", "findcall", "framepointer", + "httpmux", "httpresponse", "ifaceassert", "loopclosure", @@ -632,6 +632,7 @@ "redefines-builtin-id", "redundant-build-tag", "redundant-import-alias", + "redundant-test-main-exit", "string-format", "string-of-int", "struct-tag", @@ -664,6 +665,7 @@ }, "tagliatelle-cases": { "enum": [ + "", "camel", "pascal", "kebab", @@ -740,6 +742,7 @@ "fatcontext", "forbidigo", "forcetypeassert", + "funcorder", "funlen", "ginkgolinter", "gocheckcompilerdirectives", @@ -803,7 +806,6 @@ "stylecheck", "tagalign", "tagliatelle", - "tenv", "testableexamples", "testifylint", "testpackage", @@ -1302,6 +1304,22 @@ } } }, + "funcorderSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "constructor": { + "description": "Checks that constructors are placed after the structure declaration.", + "type": "boolean", + "default": true + }, + "struct-method": { + "description": "Checks if the exported methods of a structure are placed before the non-exported ones.", + "type": "boolean", + "default": true + } + } + }, "funlenSettings": { "type": "object", "additionalProperties": false, @@ -1488,9 +1506,12 @@ "type": "boolean", "default": true }, - "ignore-strings": { + "ignore-string-values": { "description": "Exclude strings matching the given regular expression", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "numbers": { "description": "Search also for duplicated numbers.", @@ -1506,6 +1527,16 @@ "description": "Maximum value, only works with `numbers`", "type": "integer", "default": 3 + }, + "find-duplicates": { + "description": "Detects constants with identical values", + "type": "boolean", + "default": false + }, + "eval-const-expressions": { + "description": "Evaluates of constant expressions like Prefix + \"suffix\"", + "type": "boolean", + "default": false } } }, @@ -2963,6 +2994,11 @@ "type": "boolean", "default": false }, + "msg-style": { + "description": "Enforce message style.", + "enum": ["", "lowercased", "capitalized"], + "default": "" + }, "key-naming-case": { "description": "Enforce a single key naming convention.", "enum": ["snake", "kebab", "camel", "pascal"] @@ -3339,17 +3375,6 @@ } } }, - "tenvSettings": { - "type": "object", - "additionalProperties": false, - "properties": { - "all": { - "description": "The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.", - "type": "boolean", - "default": false - } - } - }, "testifylintSettings": { "type": "object", "additionalProperties": false, @@ -3934,6 +3959,11 @@ "items": { "type": "string" } + }, + "report-internal-errors": { + "description": "Determines whether wrapcheck should report errors returned from inside the package.", + "type": "boolean", + "default": false } } }, @@ -4234,6 +4264,11 @@ } } }, + "path-mode": { + "type": "string", + "default": "", + "examples": ["abs"] + }, "path-prefix": { "description": "Add a prefix to the output file references.", "type": "string", @@ -4328,6 +4363,9 @@ "forbidigo": { "$ref": "#/definitions/settings/definitions/forbidigoSettings" }, + "funcorder": { + "$ref": "#/definitions/settings/definitions/funcorderSettings" + }, "funlen": { "$ref": "#/definitions/settings/definitions/funlenSettings" }, @@ -4475,9 +4513,6 @@ "tagliatelle": { "$ref": "#/definitions/settings/definitions/tagliatelleSettings" }, - "tenv": { - "$ref": "#/definitions/settings/definitions/tenvSettings" - }, "testifylint": { "$ref": "#/definitions/settings/definitions/testifylintSettings" }, @@ -4639,6 +4674,10 @@ "items": { "type": "string" } + }, + "warn-unused": { + "type": "boolean", + "default": false } } } diff --git a/jsonschema/golangci.next.jsonschema.json b/jsonschema/golangci.next.jsonschema.json index 776a489afd98..7e9db6cf8342 100644 --- a/jsonschema/golangci.next.jsonschema.json +++ b/jsonschema/golangci.next.jsonschema.json @@ -490,7 +490,6 @@ "G110", "G111", "G112", - "G113", "G114", "G115", "G201", @@ -540,6 +539,8 @@ "fieldalignment", "findcall", "framepointer", + "hostport", + "httpmux", "httpresponse", "ifaceassert", "loopclosure", @@ -632,10 +633,12 @@ "redefines-builtin-id", "redundant-build-tag", "redundant-import-alias", + "redundant-test-main-exit", "string-format", "string-of-int", "struct-tag", "superfluous-else", + "time-date", "time-equal", "time-naming", "unchecked-type-assertion", @@ -643,12 +646,14 @@ "unexported-naming", "unexported-return", "unhandled-error", + "unnecessary-format", "unnecessary-stmt", "unreachable-code", "unused-parameter", "unused-receiver", "use-any", "use-errors-new", + "use-fmt-print", "useless-break", "var-declaration", "var-naming", @@ -659,11 +664,13 @@ "enum": [ "identical", "unused", - "opaque" + "opaque", + "unexported" ] }, "tagliatelle-cases": { "enum": [ + "", "camel", "pascal", "kebab", @@ -715,6 +722,7 @@ "anyOf": [ { "enum": [ + "arangolint", "asasalint", "asciicheck", "bidichk", @@ -730,6 +738,7 @@ "dupl", "dupword", "durationcheck", + "embeddedstructfieldcheck", "errcheck", "errchkjson", "errname", @@ -740,6 +749,7 @@ "fatcontext", "forbidigo", "forcetypeassert", + "funcorder", "funlen", "ginkgolinter", "gocheckcompilerdirectives", @@ -784,6 +794,7 @@ "nilnil", "nlreturn", "noctx", + "noinlineerr", "nolintlint", "nonamedreturns", "nosprintfhostport", @@ -803,7 +814,6 @@ "stylecheck", "tagalign", "tagliatelle", - "tenv", "testableexamples", "testifylint", "testpackage", @@ -834,7 +844,8 @@ "gofmt", "gofumpt", "goimports", - "golines" + "golines", + "swaggo" ] }, "settings": { @@ -1083,6 +1094,17 @@ } } }, + "embeddedstructfieldcheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "forbid-mutex": { + "description": "Checks that sync.Mutex and sync.RWMutex are not used as embedded fields.", + "type": "boolean", + "default": false + } + } + }, "errcheckSettings": { "type": "object", "additionalProperties": false, @@ -1109,6 +1131,11 @@ "description": "To disable the errcheck built-in exclude list", "type": "boolean", "default": false + }, + "verbose": { + "description": "Display function signature instead of selector", + "type": "boolean", + "default": false } } }, @@ -1302,6 +1329,27 @@ } } }, + "funcorderSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "constructor": { + "description": "Checks that constructors are placed after the structure declaration.", + "type": "boolean", + "default": true + }, + "struct-method": { + "description": "Checks if the exported methods of a structure are placed before the non-exported ones.", + "type": "boolean", + "default": true + }, + "alphabetical": { + "description": "Checks if the constructors and/or structure methods are sorted alphabetically.", + "type": "boolean", + "default": false + } + } + }, "funlenSettings": { "type": "object", "additionalProperties": false, @@ -1488,9 +1536,12 @@ "type": "boolean", "default": true }, - "ignore-strings": { + "ignore-string-values": { "description": "Exclude strings matching the given regular expression", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "numbers": { "description": "Search also for duplicated numbers.", @@ -1506,6 +1557,16 @@ "description": "Maximum value, only works with `numbers`", "type": "integer", "default": 3 + }, + "find-duplicates": { + "description": "Detects constants with identical values", + "type": "boolean", + "default": false + }, + "eval-const-expressions": { + "description": "Evaluates of constant expressions like Prefix + \"suffix\"", + "type": "boolean", + "default": false } } }, @@ -1943,6 +2004,11 @@ "type": "boolean", "default": false }, + "ignore-forbidden": { + "description": "Forbid the use of the `ignore` directives. (>= go1.25)", + "type": "boolean", + "default": false + }, "toolchain-forbidden": { "description": "Forbid the use of the `toolchain` directive.", "type": "boolean", @@ -2963,6 +3029,11 @@ "type": "boolean", "default": false }, + "msg-style": { + "description": "Enforce message style.", + "enum": ["", "lowercased", "capitalized"], + "default": "" + }, "key-naming-case": { "description": "Enforce a single key naming convention.", "enum": ["snake", "kebab", "camel", "pascal"] @@ -3339,17 +3410,6 @@ } } }, - "tenvSettings": { - "type": "object", - "additionalProperties": false, - "properties": { - "all": { - "description": "The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.", - "type": "boolean", - "default": false - } - } - }, "testifylintSettings": { "type": "object", "additionalProperties": false, @@ -3677,6 +3737,11 @@ "type": "boolean", "default": false }, + "time-date-month": { + "description": "Suggest the use of time.Month in time.Date.", + "type": "boolean", + "default": false + }, "crypto-hash": { "description": "Suggest the use of crypto.Hash.String().", "type": "boolean", @@ -3934,6 +3999,11 @@ "items": { "type": "string" } + }, + "report-internal-errors": { + "description": "Determines whether wrapcheck should report errors returned from inside the package.", + "type": "boolean", + "default": false } } }, @@ -4234,6 +4304,11 @@ } } }, + "path-mode": { + "type": "string", + "default": "", + "examples": ["abs"] + }, "path-prefix": { "description": "Add a prefix to the output file references.", "type": "string", @@ -4307,6 +4382,9 @@ "dupl": { "$ref": "#/definitions/settings/definitions/duplSettings" }, + "embeddedstructfieldcheck": { + "$ref": "#/definitions/settings/definitions/embeddedstructfieldcheckSettings" + }, "errcheck": { "$ref": "#/definitions/settings/definitions/errcheckSettings" }, @@ -4328,6 +4406,9 @@ "forbidigo": { "$ref": "#/definitions/settings/definitions/forbidigoSettings" }, + "funcorder": { + "$ref": "#/definitions/settings/definitions/funcorderSettings" + }, "funlen": { "$ref": "#/definitions/settings/definitions/funlenSettings" }, @@ -4475,9 +4556,6 @@ "tagliatelle": { "$ref": "#/definitions/settings/definitions/tagliatelleSettings" }, - "tenv": { - "$ref": "#/definitions/settings/definitions/tenvSettings" - }, "testifylint": { "$ref": "#/definitions/settings/definitions/testifylintSettings" }, @@ -4639,6 +4717,10 @@ "items": { "type": "string" } + }, + "warn-unused": { + "type": "boolean", + "default": false } } } diff --git a/jsonschema/golangci.v1.64.jsonschema.json b/jsonschema/golangci.v1.64.jsonschema.json index f80ccf06235a..b265c1a8233c 100644 --- a/jsonschema/golangci.v1.64.jsonschema.json +++ b/jsonschema/golangci.v1.64.jsonschema.json @@ -310,6 +310,7 @@ }, "tagliatelle-cases": { "enum": [ + "", "camel", "pascal", "kebab", diff --git a/jsonschema/golangci.v1.jsonschema.json b/jsonschema/golangci.v1.jsonschema.json index f80ccf06235a..b265c1a8233c 100644 --- a/jsonschema/golangci.v1.jsonschema.json +++ b/jsonschema/golangci.v1.jsonschema.json @@ -310,6 +310,7 @@ }, "tagliatelle-cases": { "enum": [ + "", "camel", "pascal", "kebab", diff --git a/jsonschema/golangci.v2.0.jsonschema.json b/jsonschema/golangci.v2.0.jsonschema.json new file mode 100644 index 000000000000..437943b5f318 --- /dev/null +++ b/jsonschema/golangci.v2.0.jsonschema.json @@ -0,0 +1,4738 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/golangci-lint.json", + "definitions": { + "gocritic-checks": { + "enum": [ + "appendAssign", + "appendCombine", + "argOrder", + "assignOp", + "badCall", + "badCond", + "badLock", + "badRegexp", + "badSorting", + "badSyncOnceFunc", + "boolExprSimplify", + "builtinShadow", + "builtinShadowDecl", + "captLocal", + "caseOrder", + "codegenComment", + "commentFormatting", + "commentedOutCode", + "commentedOutImport", + "defaultCaseOrder", + "deferInLoop", + "deferUnlambda", + "deprecatedComment", + "docStub", + "dupArg", + "dupBranchBody", + "dupCase", + "dupImport", + "dupSubExpr", + "dynamicFmtString", + "elseif", + "emptyDecl", + "emptyFallthrough", + "emptyStringTest", + "equalFold", + "evalOrder", + "exitAfterDefer", + "exposedSyncMutex", + "externalErrorReassign", + "filepathJoin", + "flagDeref", + "flagName", + "hexLiteral", + "httpNoBody", + "hugeParam", + "ifElseChain", + "importShadow", + "indexAlloc", + "initClause", + "ioutilDeprecated", + "mapKey", + "methodExprCall", + "nestingReduce", + "newDeref", + "nilValReturn", + "octalLiteral", + "offBy1", + "paramTypeCombine", + "preferDecodeRune", + "preferFilepathJoin", + "preferFprint", + "preferStringWriter", + "preferWriteByte", + "ptrToRefParam", + "rangeAppendAll", + "rangeExprCopy", + "rangeValCopy", + "redundantSprint", + "regexpMust", + "regexpPattern", + "regexpSimplify", + "returnAfterHttpError", + "ruleguard", + "singleCaseSwitch", + "sliceClear", + "sloppyLen", + "sloppyReassign", + "sloppyTypeAssert", + "sortSlice", + "sprintfQuotedString", + "sqlQuery", + "stringConcatSimplify", + "stringXbytes", + "stringsCompare", + "switchTrue", + "syncMapLoadAndDelete", + "timeExprSimplify", + "todoCommentWithoutDetail", + "tooManyResultsChecker", + "truncateCmp", + "typeAssertChain", + "typeDefFirst", + "typeSwitchVar", + "typeUnparen", + "uncheckedInlineErr", + "underef", + "unlabelStmt", + "unlambda", + "unnamedResult", + "unnecessaryBlock", + "unnecessaryDefer", + "unslice", + "valSwap", + "weakCond", + "whyNoLint", + "wrapperFunc", + "yodaStyleExpr" + ] + }, + "gocritic-tags": { + "enum": [ + "diagnostic", + "style", + "performance", + "experimental", + "opinionated", + "security" + ] + }, + "staticcheck-checks": { + "enum": [ + "*", + "all", + "SA*", + "-SA*", + "SA1*", + "-SA1*", + "SA1000", + "-SA1000", + "SA1001", + "-SA1001", + "SA1002", + "-SA1002", + "SA1003", + "-SA1003", + "SA1004", + "-SA1004", + "SA1005", + "-SA1005", + "SA1006", + "-SA1006", + "SA1007", + "-SA1007", + "SA1008", + "-SA1008", + "SA1010", + "-SA1010", + "SA1011", + "-SA1011", + "SA1012", + "-SA1012", + "SA1013", + "-SA1013", + "SA1014", + "-SA1014", + "SA1015", + "-SA1015", + "SA1016", + "-SA1016", + "SA1017", + "-SA1017", + "SA1018", + "-SA1018", + "SA1019", + "-SA1019", + "SA1020", + "-SA1020", + "SA1021", + "-SA1021", + "SA1023", + "-SA1023", + "SA1024", + "-SA1024", + "SA1025", + "-SA1025", + "SA1026", + "-SA1026", + "SA1027", + "-SA1027", + "SA1028", + "-SA1028", + "SA1029", + "-SA1029", + "SA1030", + "-SA1030", + "SA1031", + "-SA1031", + "SA1032", + "-SA1032", + "SA2*", + "-SA2*", + "SA2000", + "-SA2000", + "SA2001", + "-SA2001", + "SA2002", + "-SA2002", + "SA2003", + "-SA2003", + "SA3*", + "-SA3*", + "SA3000", + "-SA3000", + "SA3001", + "-SA3001", + "SA4*", + "-SA4*", + "SA4000", + "-SA4000", + "SA4001", + "-SA4001", + "SA4003", + "-SA4003", + "SA4004", + "-SA4004", + "SA4005", + "-SA4005", + "SA4006", + "-SA4006", + "SA4008", + "-SA4008", + "SA4009", + "-SA4009", + "SA4010", + "-SA4010", + "SA4011", + "-SA4011", + "SA4012", + "-SA4012", + "SA4013", + "-SA4013", + "SA4014", + "-SA4014", + "SA4015", + "-SA4015", + "SA4016", + "-SA4016", + "SA4017", + "-SA4017", + "SA4018", + "-SA4018", + "SA4019", + "-SA4019", + "SA4020", + "-SA4020", + "SA4021", + "-SA4021", + "SA4022", + "-SA4022", + "SA4023", + "-SA4023", + "SA4024", + "-SA4024", + "SA4025", + "-SA4025", + "SA4026", + "-SA4026", + "SA4027", + "-SA4027", + "SA4028", + "-SA4028", + "SA4029", + "-SA4029", + "SA4030", + "-SA4030", + "SA4031", + "-SA4031", + "SA4032", + "-SA4032", + "SA5*", + "-SA5*", + "SA5000", + "-SA5000", + "SA5001", + "-SA5001", + "SA5002", + "-SA5002", + "SA5003", + "-SA5003", + "SA5004", + "-SA5004", + "SA5005", + "-SA5005", + "SA5007", + "-SA5007", + "SA5008", + "-SA5008", + "SA5009", + "-SA5009", + "SA5010", + "-SA5010", + "SA5011", + "-SA5011", + "SA5012", + "-SA5012", + "SA6*", + "-SA6*", + "SA6000", + "-SA6000", + "SA6001", + "-SA6001", + "SA6002", + "-SA6002", + "SA6003", + "-SA6003", + "SA6005", + "-SA6005", + "SA6006", + "-SA6006", + "SA9*", + "-SA9*", + "SA9001", + "-SA9001", + "SA9002", + "-SA9002", + "SA9003", + "-SA9003", + "SA9004", + "-SA9004", + "SA9005", + "-SA9005", + "SA9006", + "-SA9006", + "SA9007", + "-SA9007", + "SA9008", + "-SA9008", + "SA9009", + "-SA9009", + "ST*", + "-ST*", + "ST1*", + "-ST1*", + "ST1000", + "-ST1000", + "ST1001", + "-ST1001", + "ST1003", + "-ST1003", + "ST1005", + "-ST1005", + "ST1006", + "-ST1006", + "ST1008", + "-ST1008", + "ST1011", + "-ST1011", + "ST1012", + "-ST1012", + "ST1013", + "-ST1013", + "ST1015", + "-ST1015", + "ST1016", + "-ST1016", + "ST1017", + "-ST1017", + "ST1018", + "-ST1018", + "ST1019", + "-ST1019", + "ST1020", + "-ST1020", + "ST1021", + "-ST1021", + "ST1022", + "-ST1022", + "ST1023", + "-ST1023", + "S*", + "-S*", + "S1*", + "-S1*", + "S1000", + "-S1000", + "S1001", + "-S1001", + "S1002", + "-S1002", + "S1003", + "-S1003", + "S1004", + "-S1004", + "S1005", + "-S1005", + "S1006", + "-S1006", + "S1007", + "-S1007", + "S1008", + "-S1008", + "S1009", + "-S1009", + "S1010", + "-S1010", + "S1011", + "-S1011", + "S1012", + "-S1012", + "S1016", + "-S1016", + "S1017", + "-S1017", + "S1018", + "-S1018", + "S1019", + "-S1019", + "S1020", + "-S1020", + "S1021", + "-S1021", + "S1023", + "-S1023", + "S1024", + "-S1024", + "S1025", + "-S1025", + "S1028", + "-S1028", + "S1029", + "-S1029", + "S1030", + "-S1030", + "S1031", + "-S1031", + "S1032", + "-S1032", + "S1033", + "-S1033", + "S1034", + "-S1034", + "S1035", + "-S1035", + "S1036", + "-S1036", + "S1037", + "-S1037", + "S1038", + "-S1038", + "S1039", + "-S1039", + "S1040", + "-S1040", + "QF*", + "-QF*", + "QF1*", + "-QF1*", + "QF1001", + "-QF1001", + "QF1002", + "-QF1002", + "QF1003", + "-QF1003", + "QF1004", + "-QF1004", + "QF1005", + "-QF1005", + "QF1006", + "-QF1006", + "QF1007", + "-QF1007", + "QF1008", + "-QF1008", + "QF1009", + "-QF1009", + "QF1010", + "-QF1010", + "QF1011", + "-QF1011", + "QF1012", + "-QF1012" + ] + }, + "gosec-rules": { + "enum": [ + "G101", + "G102", + "G103", + "G104", + "G106", + "G107", + "G108", + "G109", + "G110", + "G111", + "G112", + "G113", + "G114", + "G115", + "G201", + "G202", + "G203", + "G204", + "G301", + "G302", + "G303", + "G304", + "G305", + "G306", + "G307", + "G401", + "G402", + "G403", + "G404", + "G405", + "G406", + "G501", + "G502", + "G503", + "G504", + "G505", + "G506", + "G507", + "G601", + "G602" + ] + }, + "govet-analyzers": { + "enum": [ + "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", + "stdversion", + "stringintconv", + "structtag", + "testinggoroutine", + "tests", + "timeformat", + "unmarshal", + "unreachable", + "unsafeptr", + "unusedresult", + "unusedwrite", + "waitgroup" + ] + }, + "revive-rules": { + "enum": [ + "add-constant", + "argument-limit", + "atomic", + "banned-characters", + "bare-return", + "blank-imports", + "bool-literal-in-expr", + "call-to-gc", + "cognitive-complexity", + "comment-spacings", + "comments-density", + "confusing-naming", + "confusing-results", + "constant-logical-expr", + "context-as-argument", + "context-keys-type", + "cyclomatic", + "datarace", + "deep-exit", + "defer", + "dot-imports", + "duplicated-imports", + "early-return", + "empty-block", + "empty-lines", + "enforce-map-style", + "enforce-repeated-arg-type-style", + "enforce-slice-style", + "error-naming", + "error-return", + "error-strings", + "errorf", + "exported", + "file-header", + "file-length-limit", + "filename-format", + "flag-parameter", + "function-length", + "function-result-limit", + "get-return", + "identical-branches", + "if-return", + "import-alias-naming", + "import-shadowing", + "imports-blocklist", + "increment-decrement", + "indent-error-flow", + "line-length-limit", + "max-control-nesting", + "max-public-structs", + "modifies-parameter", + "modifies-value-receiver", + "nested-structs", + "optimize-operands-order", + "package-comments", + "range-val-address", + "range-val-in-closure", + "range", + "receiver-naming", + "redefines-builtin-id", + "redundant-build-tag", + "redundant-import-alias", + "redundant-test-main-exit", + "string-format", + "string-of-int", + "struct-tag", + "superfluous-else", + "time-equal", + "time-naming", + "unchecked-type-assertion", + "unconditional-recursion", + "unexported-naming", + "unexported-return", + "unhandled-error", + "unnecessary-stmt", + "unreachable-code", + "unused-parameter", + "unused-receiver", + "use-any", + "use-errors-new", + "useless-break", + "var-declaration", + "var-naming", + "waitgroup-by-value" + ] + }, + "iface-analyzers": { + "enum": [ + "identical", + "unused", + "opaque" + ] + }, + "tagliatelle-cases": { + "enum": [ + "", + "camel", + "pascal", + "kebab", + "snake", + "goCamel", + "goPascal", + "goKebab", + "goSnake", + "upper", + "upperSnake", + "lower", + "header" + ] + }, + "relative-path-modes": { + "enum": [ + "gomod", + "gitroot", + "cfg", + "wd" + ] + }, + "simple-format": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "$ref": "#/definitions/formats-path", + "default": "stdout" + } + } + }, + "formats-path" : { + "anyOf": [ + { + "enum": [ + "stdout", + "stderr" + ] + }, + { + "type": "string" + } + ] + }, + "linter-names": { + "$comment": "anyOf with enum is used to allow auto-completion of non-custom linters", + "description": "Usable linter names.", + "anyOf": [ + { + "enum": [ + "asasalint", + "asciicheck", + "bidichk", + "bodyclose", + "canonicalheader", + "containedctx", + "contextcheck", + "copyloopvar", + "cyclop", + "decorder", + "depguard", + "dogsled", + "dupl", + "dupword", + "durationcheck", + "errcheck", + "errchkjson", + "errname", + "errorlint", + "exhaustive", + "exhaustruct", + "exptostd", + "fatcontext", + "forbidigo", + "forcetypeassert", + "funlen", + "ginkgolinter", + "gocheckcompilerdirectives", + "gochecknoglobals", + "gochecknoinits", + "gochecksumtype", + "gocognit", + "goconst", + "gocritic", + "gocyclo", + "godot", + "godox", + "err113", + "goheader", + "gomoddirectives", + "gomodguard", + "goprintffuncname", + "gosec", + "gosimple", + "gosmopolitan", + "govet", + "grouper", + "iface", + "importas", + "inamedparam", + "ineffassign", + "interfacebloat", + "intrange", + "ireturn", + "lll", + "loggercheck", + "maintidx", + "makezero", + "mirror", + "misspell", + "mnd", + "musttag", + "nakedret", + "nestif", + "nilerr", + "nilnesserr", + "nilnil", + "nlreturn", + "noctx", + "nolintlint", + "nonamedreturns", + "nosprintfhostport", + "paralleltest", + "perfsprint", + "prealloc", + "predeclared", + "promlinter", + "protogetter", + "reassign", + "recvcheck", + "revive", + "rowserrcheck", + "sloglint", + "sqlclosecheck", + "staticcheck", + "stylecheck", + "tagalign", + "tagliatelle", + "testableexamples", + "testifylint", + "testpackage", + "thelper", + "tparallel", + "unconvert", + "unparam", + "unused", + "usestdlibvars", + "usetesting", + "varnamelen", + "wastedassign", + "whitespace", + "wrapcheck", + "wsl", + "zerologlint" + ] + }, + { + "type": "string" + } + ] + }, + "formatter-names": { + "description": "Usable formatter names.", + "enum": [ + "gci", + "gofmt", + "gofumpt", + "goimports", + "golines" + ] + }, + "settings": { + "definitions": { + "dupwordSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "keywords": { + "description": "Keywords for detecting duplicate words. If this list is not empty, only the words defined in this list will be detected.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "examples": ["the", "and", "a"] + } + }, + "ignore": { + "description": "Keywords used to ignore detection.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "examples": ["0C0C"] + } + } + } + }, + "asasalintSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "exclude": { + "description": "To specify a set of function names to exclude.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "examples": ["\\.Wrapf"] + } + }, + "use-builtin-exclusions": { + "description": "To enable/disable the asasalint builtin exclusions of function names.", + "type": "boolean", + "default": true + } + } + }, + "bidichkSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "left-to-right-embedding": { + "description": "Disallow: LEFT-TO-RIGHT-EMBEDDING", + "type": "boolean", + "default": false + }, + "right-to-left-embedding": { + "description": "Disallow: RIGHT-TO-LEFT-EMBEDDING", + "type": "boolean", + "default": false + }, + "pop-directional-formatting": { + "description": "Disallow: POP-DIRECTIONAL-FORMATTING", + "type": "boolean", + "default": false + }, + "left-to-right-override": { + "description": "Disallow: LEFT-TO-RIGHT-OVERRIDE", + "type": "boolean", + "default": false + }, + "right-to-left-override": { + "description": "Disallow: RIGHT-TO-LEFT-OVERRIDE", + "type": "boolean", + "default": false + }, + "left-to-right-isolate": { + "description": "Disallow: LEFT-TO-RIGHT-ISOLATE", + "type": "boolean", + "default": false + }, + "right-to-left-isolate": { + "description": "Disallow: RIGHT-TO-LEFT-ISOLATE", + "type": "boolean", + "default": false + }, + "first-strong-isolate": { + "description": "Disallow: FIRST-STRONG-ISOLATE", + "type": "boolean", + "default": false + }, + "pop-directional-isolate": { + "description": "Disallow: POP-DIRECTIONAL-ISOLATE", + "type": "boolean", + "default": false + } + } + }, + "cyclopSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "max-complexity": { + "description": "Max complexity the function can have", + "type": "integer", + "default": 10, + "minimum": 0 + }, + "package-average": { + "description": "Max average complexity in package", + "type": "number", + "default": 0, + "minimum": 0 + } + } + }, + "decorderSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "dec-order": { + "type": "array", + "default": [["type", "const", "var", "func"]], + "items": { + "enum": ["type", "const", "var", "func"] + } + }, + "ignore-underscore-vars": { + "description": "Underscore vars (vars with \"_\" as the name) will be ignored at all checks", + "default": true, + "type": "boolean" + }, + "disable-dec-order-check": { + "description": "Order of declarations is not checked", + "default": true, + "type": "boolean" + }, + "disable-init-func-first-check": { + "description": "Allow init func to be anywhere in file", + "default": true, + "type": "boolean" + }, + "disable-dec-num-check": { + "description": "Multiple global type, const and var declarations are allowed", + "default": true, + "type": "boolean" + }, + "disable-type-dec-num-check": { + "description": "Type declarations will be ignored for dec num check", + "default": true, + "type": "boolean" + }, + "disable-const-dec-num-check": { + "description": "Const declarations will be ignored for dec num check", + "default": true, + "type": "boolean" + }, + "disable-var-dec-num-check": { + "description": "Var declarations will be ignored for dec num check", + "default": true, + "type": "boolean" + } + } + }, + "depguardSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "rules": { + "description": "Rules to apply.", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[^.]+$": { + "description": "Name of a rule.", + "type": "object", + "additionalProperties": false, + "properties": { + "list-mode": { + "description": "Used to determine the package matching priority.", + "enum": ["original", "strict", "lax"], + "default": "original" + }, + "files": { + "description": "List of file globs that will match this list of settings to compare against.", + "additionalProperties": false, + "type": "array", + "items": { + "type": "string" + } + }, + "allow": { + "description": "List of allowed packages.", + "additionalProperties": false, + "type": "array", + "items": { + "type": "string" + } + }, + "deny": { + "description": "Packages that are not allowed where the value is a suggestion.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "desc": { + "description": "Description", + "type": "string" + }, + "pkg": { + "description": "Package", + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "dogsledSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "max-blank-identifiers": { + "description": "Check assignments with too many blank identifiers.", + "type": "integer", + "default": 2, + "minimum": 0 + } + } + }, + "duplSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "threshold": { + "description": "Tokens count to trigger issue.", + "type": "integer", + "default": 150, + "minimum": 0 + } + } + }, + "errcheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "check-type-assertions": { + "description": "Report about not checking errors in type assertions, i.e.: `a := b.(MyStruct)`", + "type": "boolean", + "default": false + }, + "check-blank": { + "description": "Report about assignment of errors to blank identifier", + "type": "boolean", + "default": false + }, + "exclude-functions": { + "description": "List of functions to exclude from checking, where each entry is a single function to exclude", + "type": "array", + "examples": ["io/ioutil.ReadFile", "io.Copy(*bytes.Buffer)"], + "items": { + "type": "string" + } + }, + "disable-default-exclusions": { + "description": "To disable the errcheck built-in exclude list", + "type": "boolean", + "default": false + } + } + }, + "errchkjsonSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "check-error-free-encoding": { + "type": "boolean", + "default": false + }, + "report-no-exported": { + "description": "Issue on struct that doesn't have exported fields.", + "type": "boolean", + "default": false + } + } + }, + "errorlintSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "errorf": { + "description": "Check whether fmt.Errorf uses the %w verb for formatting errors", + "type": "boolean", + "default": true + }, + "errorf-multi": { + "description": "Permit more than 1 %w verb, valid per Go 1.20", + "type": "boolean", + "default": true + }, + "asserts": { + "description": "Check for plain type assertions and type switches.", + "type": "boolean", + "default": true + }, + "comparison": { + "description": "Check for plain error comparisons", + "type": "boolean", + "default": true + }, + "allowed-errors": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "err": { + "type": "string" + }, + "fun": { + "type": "string" + } + } + } + }, + "allowed-errors-wildcard": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "err": { + "type": "string" + }, + "fun": { + "type": "string" + } + } + } + } + } + }, + "exhaustiveSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "check": { + "description": "Program elements to check for exhaustiveness.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "examples": ["switch", "map"] + } + }, + "explicit-exhaustive-switch": { + "description": "Only run exhaustive check on switches with \"//exhaustive:enforce\" comment.", + "type": "boolean", + "default": false + }, + "explicit-exhaustive-map": { + "description": "Only run exhaustive check on map literals with \"//exhaustive:enforce\" comment.", + "type": "boolean", + "default": false + }, + "default-case-required": { + "description": "Switch statement requires default case even if exhaustive.", + "type": "boolean", + "default": false + }, + "default-signifies-exhaustive": { + "description": "Presence of `default` case in switch statements satisfies exhaustiveness, even if all enum members are not listed.", + "type": "boolean", + "default": false + }, + "ignore-enum-members": { + "description": "Enum members matching `regex` do not have to be listed in switch statements to satisfy exhaustiveness", + "type": "string" + }, + "ignore-enum-types": { + "description": "Enum types matching the supplied regex do not have to be listed in switch statements to satisfy exhaustiveness.", + "type": "string" + }, + "package-scope-only": { + "description": "Consider enums only in package scopes, not in inner scopes.", + "type": "boolean", + "default": false + } + } + }, + "exhaustructSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "include": { + "description": "List of regular expressions to match struct packages and names.", + "type": "array", + "examples": [".*\\.Test"], + "items": { + "type": "string" + } + }, + "exclude": { + "description": "List of regular expressions to exclude struct packages and names from check.", + "type": "array", + "examples": ["cobra\\.Command$"], + "items": { + "type": "string" + } + } + } + }, + "fatcontextSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "check-struct-pointers": { + "description": "Check for potential fat contexts in struct pointers.", + "type": "boolean", + "default": false + } + } + }, + "forbidigoSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "exclude-godoc-examples": { + "description": "Exclude code in godoc examples.", + "type": "boolean", + "default": true + }, + "analyze-types": { + "description": "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.", + "type": "boolean", + "default": true + }, + "forbid": { + "description": "List of identifiers to forbid (written using `regexp`)", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "pattern": { + "description": "Pattern", + "type": "string" + }, + "pkg": { + "description": "Package", + "type": "string" + }, + "msg": { + "description": "Message", + "type": "string" + } + } + } + } + } + }, + "funlenSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "lines": { + "description": "Limit lines number per function.", + "type": "integer", + "default": 60 + }, + "statements": { + "description": "Limit statements number per function.", + "type": "integer", + "default": 40 + }, + "ignore-comments": { + "description": "Ignore comments when counting lines.", + "type": "boolean", + "default": true + } + } + }, + "gciSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "sections": { + "description": "Section configuration to compare against.", + "type": "array", + "items": { + "anyOf": [ + { + "enum": [ + "standard", + "default", + "blank", + "dot", + "alias", + "localmodule" + ] + }, + { + "type": "string" + } + ] + }, + "default": ["standard", "default"] + }, + "no-inline-comments": { + "description": "Checks that no inline Comments are present.", + "type": "boolean", + "default": false + }, + "no-prefix-comments": { + "description": "Checks that no prefix Comments(comment lines above an import) are present.", + "type": "boolean", + "default": false + }, + "custom-order": { + "description": "Enable custom order of sections.", + "type": "boolean", + "default": false + }, + "no-lex-order": { + "description": "Drops lexical ordering for custom sections.", + "type": "boolean", + "default": false + } + } + }, + "ginkgolinterSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "suppress-len-assertion": { + "description": "Suppress the wrong length assertion warning.", + "type": "boolean", + "default": false + }, + "suppress-nil-assertion": { + "description": "Suppress the wrong nil assertion warning.", + "type": "boolean", + "default": false + }, + "suppress-err-assertion": { + "description": "Suppress the wrong error assertion warning.", + "type": "boolean", + "default": false + }, + "suppress-compare-assertion": { + "description": "Suppress the wrong comparison assertion warning.", + "type": "boolean", + "default": false + }, + "suppress-async-assertion": { + "description": "Suppress the function all in async assertion warning.", + "type": "boolean", + "default": false + }, + "suppress-type-compare-assertion": { + "description": "Suppress warning for comparing values from different types, like int32 and uint32.", + "type": "boolean", + "default": false + }, + "forbid-focus-container": { + "description": "Trigger warning for ginkgo focus containers like FDescribe, FContext, FWhen or FIt.", + "type": "boolean", + "default": false + }, + "allow-havelen-zero": { + "description": "Don't trigger warnings for HaveLen(0).", + "type": "boolean", + "default": false + }, + "force-expect-to": { + "description": "Force using `Expect` with `To`, `ToNot` or `NotTo`", + "type": "boolean", + "default": false + }, + "validate-async-intervals": { + "description": "Best effort validation of async intervals (timeout and polling).", + "type": "boolean", + "default": false + }, + "forbid-spec-pollution": { + "description": "Trigger a warning for variable assignments in ginkgo containers like `Describe`, `Context` and `When`, instead of in `BeforeEach()`.", + "type": "boolean", + "default": false + }, + "force-succeed": { + "description": "Force using the Succeed matcher for error functions, and the HaveOccurred matcher for non-function error values.", + "type": "boolean", + "default": false + } + } + }, + "gochecksumtypeSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "default-signifies-exhaustive": { + "description": "Presence of `default` case in switch statements satisfies exhaustiveness, if all members are not listed.", + "type": "boolean", + "default": true + }, + "include-shared-interfaces": { + "description": "Include shared interfaces in the exhaustiviness check.", + "type": "boolean", + "default": false + } + } + }, + "gocognitSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "min-complexity": { + "description": "Minimal code complexity to report (we recommend 10-20).", + "type": "integer", + "default": 30 + } + } + }, + "goconstSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "match-constant": { + "description": "Look for existing constants matching the values", + "type": "boolean", + "default": true + }, + "min-len": { + "description": "Minimum length of string constant.", + "type": "integer", + "default": 3 + }, + "min-occurrences": { + "description": "Minimum occurrences count to trigger.", + "type": "integer", + "default": 3 + }, + "ignore-calls": { + "description": "Ignore when constant is not used as function argument", + "type": "boolean", + "default": true + }, + "ignore-strings": { + "description": "Exclude strings matching the given regular expression", + "type": "string" + }, + "numbers": { + "description": "Search also for duplicated numbers.", + "type": "boolean", + "default": false + }, + "min": { + "description": "Minimum value, only works with `numbers`", + "type": "integer", + "default": 3 + }, + "max": { + "description": "Maximum value, only works with `numbers`", + "type": "integer", + "default": 3 + } + } + }, + "gocriticSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled-checks": { + "description": "Which checks should be enabled. By default, a list of stable checks is used. To see it, run `GL_DEBUG=gocritic golangci-lint run`.", + "type": "array", + "items": { + "$ref": "#/definitions/gocritic-checks" + } + }, + "disabled-checks": { + "description": "Which checks should be disabled.", + "type": "array", + "items": { + "$ref": "#/definitions/gocritic-checks" + }, + "default": [] + }, + "enabled-tags": { + "description": "Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.", + "type": "array", + "items": { + "$ref": "#/definitions/gocritic-tags" + } + }, + "disabled-tags": { + "description": "Disable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.", + "type": "array", + "items": { + "$ref": "#/definitions/gocritic-tags" + } + }, + "settings": { + "description": "Settings passed to gocritic. Properties must be valid and enabled check names.", + "type": "object", + "additionalProperties": false, + "properties": { + "captLocal": { + "type": "object", + "additionalProperties": false, + "properties": { + "paramsOnly" : { + "type": "boolean", + "default": true + } + } + }, + "commentedOutCode": { + "type": "object", + "additionalProperties": false, + "properties": { + "minLength" : { + "type": "number", + "default": 15 + } + } + }, + "elseif": { + "type": "object", + "additionalProperties": false, + "properties": { + "skipBalanced" : { + "type": "boolean", + "default": true + } + } + }, + "hugeParam": { + "type": "object", + "additionalProperties": false, + "properties": { + "sizeThreshold" : { + "type": "number", + "default": 80 + } + } + }, + "ifElseChain": { + "type": "object", + "additionalProperties": false, + "properties": { + "minThreshold" : { + "type": "number", + "default": 2 + } + } + }, + "nestingReduce": { + "type": "object", + "additionalProperties": false, + "properties": { + "bodyWidth" : { + "type": "number", + "default": 5 + } + } + }, + "rangeExprCopy": { + "type": "object", + "additionalProperties": false, + "properties": { + "sizeThreshold" : { + "type": "number", + "default": 512 + }, + "skipTestFuncs" : { + "type": "boolean", + "default": true + } + } + }, + "rangeValCopy": { + "type": "object", + "additionalProperties": false, + "properties": { + "sizeThreshold" : { + "type": "number", + "default": 128 + }, + "skipTestFuncs" : { + "type": "boolean", + "default": true + } + } + }, + "ruleguard": { + "type": "object", + "additionalProperties": false, + "properties": { + "debug" : { + "type": "string" + }, + "enable" : { + "type": "string" + }, + "disable" : { + "type": "string" + }, + "failOn" : { + "type": "string" + }, + "rules" : { + "type": "string" + } + } + }, + "tooManyResultsChecker": { + "type": "object", + "additionalProperties": false, + "properties": { + "maxResults" : { + "type": "number", + "default": 5 + } + } + }, + "truncateCmp": { + "type": "object", + "additionalProperties": false, + "properties": { + "skipArchDependent" : { + "type": "boolean", + "default": true + } + } + }, + "underef": { + "type": "object", + "additionalProperties": false, + "properties": { + "skipRecvDeref" : { + "type": "boolean", + "default": true + } + } + }, + "unnamedResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "checkExported" : { + "type": "boolean", + "default": false + } + } + } + } + }, + "disable-all": { + "type": "boolean", + "default": false + }, + "enable-all": { + "type": "boolean", + "default": false + } + } + }, + "gocycloSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "min-complexity": { + "description": "Minimum code complexity to report (we recommend 10-20).", + "type": "integer", + "default": 30 + } + } + }, + "godotSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "scope": { + "description": "Comments to be checked.", + "enum": ["declarations", "toplevel", "all"], + "default": "declarations" + }, + "exclude": { + "description": "List of regexps for excluding particular comment lines from check.", + "type": "array", + "items": { + "type": "string" + } + }, + "period": { + "description": "Check that each sentence ends with a period.", + "type": "boolean", + "default": true + }, + "capital": { + "description": "Check that each sentence starts with a capital letter.", + "type": "boolean", + "default": false + }, + "check-all": { + "description": "DEPRECATED: Check all top-level comments, not only declarations.", + "type": "boolean", + "default": false + } + } + }, + "godoxSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "keywords": { + "description": "Report any comments starting with one of these keywords. This is useful for TODO or FIXME comments that might be left in the code accidentally and should be resolved before merging.", + "type": "array", + "items": { + "type": "string" + }, + "default": ["TODO", "BUG", "FIXME"] + } + } + }, + "gofmtSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "simplify": { + "description": "Simplify code.", + "type": "boolean", + "default": true + }, + "rewrite-rules": { + "description": "Apply the rewrite rules to the source before reformatting.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "pattern": { + "type": "string" + }, + "replacement": { + "type": "string" + } + } + } + } + } + }, + "golinesSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "max-len": { + "type": "integer", + "default": 100 + }, + "tab-len": { + "type": "integer", + "default": 4 + }, + "shorten-comments": { + "type": "boolean", + "default": false + }, + "reformat-tags": { + "type": "boolean", + "default": true + }, + "chain-split-dots": { + "type": "boolean", + "default": true + } + } + }, + "interfacebloatSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "max": { + "description": "The maximum number of methods allowed for an interface.", + "type": "integer" + } + } + }, + "gofumptSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "extra-rules": { + "description": "Choose whether or not to use the extra rules that are disabled by default.", + "type": "boolean", + "default": false + }, + "module-path": { + "description": " Module path which contains the source code being formatted.", + "type": "string" + } + } + }, + "goheaderSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "values": { + "type": "object", + "additionalProperties": false, + "properties": { + "const": { + "description": "Constants to use in the template.", + "type": "object", + "patternProperties": { + "^.+$": { + "description": "Value for the constant.", + "type": "string" + } + }, + "additionalProperties": false, + "examples": [ + { + "YEAR": "2030", + "COMPANY": "MY FUTURISTIC COMPANY" + } + ] + }, + "regexp": { + "description": "Regular expressions to use in your template.", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^.+$": { + "type": "string" + } + }, + "examples": [ + { + "AUTHOR": ".*@mycompany\\.com" + } + ] + } + } + }, + "template": { + "description": "Template to put on top of every file.", + "type": "string", + "examples": [ + "{{ MY COMPANY }}\nSPDX-License-Identifier: Apache-2.0\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License." + ] + }, + "template-path": { + "description": "Path to the file containing the template source.", + "type": "string", + "examples": ["my_header_template.txt"] + } + }, + "oneOf": [ + { "required": ["template"] }, + { "required": ["template-path"] } + ] + }, + "goimportsSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "local-prefixes": { + "description": "Put imports beginning with prefix after 3rd-party packages. It is a list of prefixes.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "gomoddirectivesSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "replace-local": { + "description": "Allow local `replace` directives.", + "type": "boolean", + "default": true + }, + "replace-allow-list": { + "description": "List of allowed `replace` directives.", + "type": "array", + "items": { + "type": "string" + } + }, + "retract-allow-no-explanation": { + "description": "Allow to not explain why the version has been retracted in the `retract` directives.", + "type": "boolean", + "default": false + }, + "exclude-forbidden": { + "description": "Forbid the use of the `exclude` directives.", + "type": "boolean", + "default": false + }, + "toolchain-forbidden": { + "description": "Forbid the use of the `toolchain` directive.", + "type": "boolean", + "default": false + }, + "toolchain-pattern": { + "description": "Defines a pattern to validate `toolchain` directive.", + "type": "string" + }, + "tool-forbidden": { + "description": "Forbid the use of the `tool` directives.", + "type": "boolean", + "default": false + }, + "go-debug-forbidden": { + "description": "Forbid the use of the `godebug` directive.", + "type": "boolean", + "default": false + }, + "go-version-pattern": { + "description": "Defines a pattern to validate `go` minimum version directive.", + "type": "string", + "default": "" + } + } + }, + "gomodguardSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "allowed": { + "type": "object", + "additionalProperties": false, + "properties": { + "modules": { + "description": "List of allowed modules.", + "type": "array", + "items": { + "type": "string", + "examples": ["gopkg.in/yaml.v2"] + } + }, + "domains": { + "description": "List of allowed module domains.", + "type": "array", + "items": { + "type": "string", + "examples": ["golang.org"] + } + } + } + }, + "blocked": { + "type": "object", + "additionalProperties": false, + "properties": { + "modules": { + "description": "List of blocked modules.", + "type": "array", + "items": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "recommendations": { + "description": "Recommended modules that should be used instead.", + "type": "array", + "items": { + "type": "string" + } + }, + "reason": { + "description": "Reason why the recommended module should be used.", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + }, + "versions": { + "description": "List of blocked module version constraints.", + "type": "array", + "items": { + "type": "object", + "patternProperties": { + "^.*$": { + "type": "object", + "additionalProperties": false, + "properties": { + "version": { + "description": "Version constraint.", + "type": "string" + }, + "reason": { + "description": "Reason why the version constraint exists.", + "type": "string" + } + }, + "required": ["reason"] + } + } + } + }, + "local-replace-directives": { + "description": "Raise lint issues if loading local path with replace directive", + "type": "boolean", + "default": true + } + } + } + } + }, + "gosecSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "includes": { + "type": "array", + "description": "To select a subset of rules to run", + "examples": [["G401"]], + "items": { + "$ref": "#/definitions/gosec-rules" + } + }, + "excludes": { + "type": "array", + "description": "To specify a set of rules to explicitly exclude", + "examples": [["G401"]], + "items": { + "$ref": "#/definitions/gosec-rules" + } + }, + "severity": { + "description": "Filter out the issues with a lower severity than the given value", + "type": "string", + "enum": ["low", "medium", "high"], + "default": "low" + }, + "confidence": { + "description": "Filter out the issues with a lower confidence than the given value", + "type": "string", + "enum": ["low", "medium", "high"], + "default": "low" + }, + "config": { + "description": "To specify the configuration of rules", + "type": "object" + }, + "concurrency": { + "description": "Concurrency value", + "type": "integer" + } + } + }, + "gosmopolitanSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "allow-time-local": { + "description": "Allow and ignore `time.Local` usages.", + "type": "boolean", + "default": false + }, + "escape-hatches": { + "description": "List of fully qualified names in the `full/pkg/path.name` form, to act as \"i18n escape hatches\".", + "type": "array", + "items": { + "type": "string" + } + }, + "watch-for-scripts": { + "description": "List of Unicode scripts to watch for any usage in string literals.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "govetSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "settings": { + "description": "Settings per analyzer. Map of analyzer name to specific settings.\nRun `go tool vet help` to find out more.", + "type": "object", + "propertyNames": { + "$ref": "#/definitions/govet-analyzers" + }, + "patternProperties": { + "^.*$": { + "description": "Run `go tool vet help ` to see all settings.", + "type": "object" + } + } + }, + "enable": { + "description": "Enable analyzers by name.", + "type": "array", + "items": { + "$ref": "#/definitions/govet-analyzers" + } + }, + "disable": { + "description": "Disable analyzers by name.", + "type": "array", + "items": { + "$ref": "#/definitions/govet-analyzers" + } + }, + "enable-all": { + "description": "Enable all analyzers.", + "type": "boolean", + "default": false + }, + "disable-all": { + "description": "Disable all analyzers.", + "type": "boolean", + "default": false + } + } + }, + "grouperSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "const-require-single-const": { + "type": "boolean", + "default": false + }, + "const-require-grouping": { + "type": "boolean", + "default": false + }, + "import-require-single-import": { + "type": "boolean", + "default": false + }, + "import-require-grouping": { + "type": "boolean", + "default": false + }, + "type-require-single-type": { + "type": "boolean", + "default": false + }, + "type-require-grouping": { + "type": "boolean", + "default": false + }, + "var-require-single-var": { + "type": "boolean", + "default": false + }, + "var-require-grouping": { + "type": "boolean", + "default": false + } + } + }, + "ifaceSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "enable": { + "description": "Enable analyzers by name.", + "type": "array", + "items": { + "$ref": "#/definitions/iface-analyzers" + } + }, + "settings": { + "type": "object", + "additionalProperties": false, + "properties": { + "unused": { + "type": "object", + "additionalProperties": false, + "properties": { + "exclude": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "importasSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "no-unaliased": { + "description": "Do not allow unaliased imports of aliased packages.", + "type": "boolean", + "default": false + }, + "no-extra-aliases": { + "description": "Do not allow non-required aliases.", + "type": "boolean", + "default": false + }, + "alias": { + "description": "List of aliases", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "pkg": { + "description": "Package path e.g. knative.dev/serving/pkg/apis/autoscaling/v1alpha1", + "type": "string" + }, + "alias": { + "description": "Package alias e.g. autoscalingv1alpha1", + "type": "string" + } + }, + "required": ["pkg", "alias"] + } + } + } + }, + "inamedparamSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "skip-single-param": { + "description": "Skips check for interface methods with only a single parameter.", + "type": "boolean", + "default": false + } + } + }, + "ireturnSettings": { + "type": "object", + "additionalProperties": false, + "description": "Use either `reject` or `allow` properties for interfaces matching.", + "properties": { + "allow": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": ["anon", "error", "empty", "stdlib"] + } + ] + } + }, + "reject": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": ["anon", "error", "empty", "stdlib"] + } + ] + } + } + }, + "anyOf": [ + { + "not": { + "properties": { + "allow": { + "const": "reject" + } + } + }, + "required": ["allow"] + }, + { + "required": ["reject"] + } + ] + }, + "lllSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "tab-width": { + "description": "Width of \"\\t\" in spaces.", + "type": "integer", + "minimum": 0, + "default": 1 + }, + "line-length": { + "description": "Maximum allowed line length, lines longer will be reported.", + "type": "integer", + "minimum": 1, + "default": 120 + } + } + }, + "maintidxSettings": { + "description": "Maintainability index https://docs.microsoft.com/en-us/visualstudio/code-quality/code-metrics-maintainability-index-range-and-meaning?view=vs-2022", + "type": "object", + "additionalProperties": false, + "properties": { + "under": { + "description": "Minimum accatpable maintainability index level (see https://docs.microsoft.com/en-us/visualstudio/code-quality/code-metrics-maintainability-index-range-and-meaning?view=vs-2022)", + "type": "number", + "default": 20 + } + } + }, + "makezeroSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "always": { + "description": "Allow only slices initialized with a length of zero.", + "type": "boolean", + "default": false + } + } + }, + "loggercheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "kitlog": { + "description": "Allow check for the github.com/go-kit/log library.", + "type": "boolean", + "default": true + }, + "klog": { + "description": "Allow check for the k8s.io/klog/v2 library.", + "type": "boolean", + "default": true + }, + "logr": { + "description": "Allow check for the github.com/go-logr/logr library.", + "type": "boolean", + "default": true + }, + "slog": { + "description": "Allow check for the log/slog library.", + "type": "boolean", + "default": true + }, + "zap": { + "description": "Allow check for the \"sugar logger\" from go.uber.org/zap library.", + "type": "boolean", + "default": true + }, + "require-string-key": { + "description": "Require all logging keys to be inlined constant strings.", + "type": "boolean", + "default": false + }, + "no-printf-like": { + "description": "Require printf-like format specifier (%s, %d for example) not present.", + "type": "boolean", + "default": false + }, + "rules": { + "description": "List of custom rules to check against, where each rule is a single logger pattern, useful for wrapped loggers.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "misspellSettings": { + "description": "Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English.", + "type": "object", + "additionalProperties": false, + "properties": { + "locale": { + "enum": ["US", "UK"] + }, + "ignore-rules": { + "description": "List of rules to ignore.", + "type": "array", + "items": { + "type": "string" + } + }, + "mode": { + "description": "Mode of the analysis.", + "enum": ["restricted", "", "default"], + "default": "" + }, + "extra-words": { + "description": "Extra word corrections.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "correction": { + "type": "string" + }, + "typo": { + "type": "string" + } + } + } + } + } + }, + "musttagSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "functions": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "arg-pos": { + "type": "integer" + } + } + } + } + } + }, + "nakedretSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "max-func-lines": { + "description": "Report if a function has more lines of code than this value and it has naked returns.", + "type": "integer", + "minimum": 0, + "default": 30 + } + } + }, + "nestifSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "min-complexity": { + "description": "Minimum complexity of \"if\" statements to report.", + "type": "integer", + "default": 5 + } + } + }, + "nilnilSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "only-two": { + "type": "boolean", + "description": "To check functions with only two return values.", + "default": true + }, + "detect-opposite": { + "type": "boolean", + "description": "In addition, detect opposite situation (simultaneous return of non-nil error and valid value).", + "default": false + }, + "checked-types": { + "type": "array", + "description": "List of return types to check.", + "items": { + "enum": ["chan", "func", "iface", "map", "ptr", "uintptr", "unsafeptr"] + }, + "default": ["chan", "func", "iface", "map", "ptr", "uintptr", "unsafeptr"] + } + } + }, + "nlreturnSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "block-size": { + "description": "set block size that is still ok", + "type": "number", + "default": 0, + "minimum": 0 + } + } + }, + "mndSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "ignored-files": { + "description": "List of file patterns to exclude from analysis.", + "examples": [["magic1_.*.go"]], + "type": "array", + "items": { + "type": "string" + } + }, + "ignored-functions": { + "description": "Comma-separated list of function patterns to exclude from the analysis.", + "examples": [["math.*", "http.StatusText", "make"]], + "type": "array", + "items": { + "type": "string" + } + }, + "ignored-numbers": { + "description": "List of numbers to exclude from analysis.", + "examples": [["1000", "1234_567_890", "3.14159264"]], + "type": "array", + "items": { + "type": "string" + } + }, + "checks": { + "description": "The list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description.", + "type": "array", + "items": { + "enum": [ + "argument", + "case", + "condition", + "operation", + "return", + "assign" + ] + } + } + } + }, + "nolintlintSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "allow-unused": { + "description": "Enable to ensure that nolint directives are all used.", + "type": "boolean", + "default": true + }, + "allow-no-explanation": { + "description": "Exclude these linters from requiring an explanation.", + "type": "array", + "items": { + "$ref": "#/definitions/linter-names" + }, + "default": [] + }, + "require-explanation": { + "description": "Enable to require an explanation of nonzero length after each nolint directive.", + "type": "boolean", + "default": false + }, + "require-specific": { + "description": "Enable to require nolint directives to mention the specific linter being suppressed.", + "type": "boolean", + "default": false + } + } + }, + "reassignSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "patterns": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "recvcheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "disable-builtin": { + "description": "Disables the built-in method exclusions.", + "type": "boolean", + "default": true + }, + "exclusions": { + "description": "User-defined method exclusions.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "nonamedreturnsSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "report-error-in-defer": { + "description": "Report named error if it is assigned inside defer.", + "type": "boolean", + "default": false + } + } + }, + "paralleltestSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "ignore-missing": { + "description": "Ignore missing calls to `t.Parallel()` and only report incorrect uses of it.", + "type": "boolean", + "default": false + }, + "ignore-missing-subtests": { + "description": "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.", + "type": "boolean", + "default": false + } + } + }, + "perfsprintSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "integer-format": { + "description": "Enable/disable optimization of integer formatting.", + "type": "boolean", + "default": true + }, + "int-conversion": { + "description": "Optimizes even if it requires an int or uint type cast.", + "type": "boolean", + "default": true + }, + "error-format": { + "description": "Enable/disable optimization of error formatting.", + "type": "boolean", + "default": true + }, + "err-error": { + "description": "Optimizes into `err.Error()` even if it is only equivalent for non-nil errors.", + "type": "boolean", + "default": false + }, + "errorf": { + "description": "Optimizes `fmt.Errorf`.", + "type": "boolean", + "default": true + }, + "string-format": { + "description": "Enable/disable optimization of string formatting.", + "type": "boolean", + "default": true + }, + "sprintf1": { + "description": "Optimizes `fmt.Sprintf` with only one argument.", + "type": "boolean", + "default": true + }, + "strconcat": { + "description": "Optimizes into strings concatenation.", + "type": "boolean", + "default": true + }, + "bool-format": { + "description": "Enable/disable optimization of bool formatting.", + "type": "boolean", + "default": true + }, + "hex-format": { + "description": "Enable/disable optimization of hex formatting.", + "type": "boolean", + "default": true + } + } + }, + "preallocSettings": { + "description": "We do not recommend using this linter before doing performance profiling.\nFor most programs usage of `prealloc` will be premature optimization.", + "type": "object", + "additionalProperties": false, + "properties": { + "simple": { + "description": "Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.", + "type": "boolean", + "default": true + }, + "range-loops": { + "description": "Report preallocation suggestions on range loops.", + "type": "boolean", + "default": true + }, + "for-loops": { + "description": "Report preallocation suggestions on for loops.", + "type": "boolean", + "default": false + } + } + }, + "predeclaredSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "ignore": { + "description": "List of predeclared identifiers to not report on.", + "type": "array", + "items": { + "type": "string" + } + }, + "qualified-name": { + "description": "Include method names and field names in checks.", + "type": "boolean", + "default": false + } + } + }, + "promlinterSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "strict": {}, + "disabled-linters": { + "type": "array", + "items": { + "enum": [ + "Help", + "MetricUnits", + "Counter", + "HistogramSummaryReserved", + "MetricTypeInName", + "ReservedChars", + "CamelCase", + "UnitAbbreviations" + ] + } + } + } + }, + "protogetterSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "skip-generated-by": { + "type": "array", + "items": { + "type": "string", + "examples": ["protoc-gen-go-my-own-generator"] + } + }, + "skip-files": { + "type": "array", + "items": { + "type": "string", + "examples": ["*.pb.go"] + } + }, + "skip-any-generated": { + "description": "Skip any generated files from the checking.", + "type": "boolean", + "default": false + }, + "replace-first-arg-in-append": { + "description": "Skip first argument of append function.", + "type": "boolean", + "default": false + } + } + }, + "reviveSettings": { + "type": "object", + "additionalProperties": false, + "examples": [ + { + "ignore-generated-header": true, + "severity": "warning", + "rules": [ + { + "name": "indent-error-flow", + "severity": "warning" + }, + { + "name": "add-constant", + "severity": "warning", + "arguments": [ + { + "maxLitCount": "3", + "allowStrs": "\"\"", + "allowInts": "0,1,2", + "allowFloats": "0.0,0.,1.0,1.,2.0,2." + } + ] + } + ] + } + ], + "properties": { + "max-open-files": { + "type": "integer" + }, + "confidence": { + "type": "number" + }, + "severity": { + "type": "string", + "enum": ["warning", "error"] + }, + "enable-all-rules": { + "type": "boolean", + "default": false + }, + "directives": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "enum": ["specify-disable-reason"] + }, + "severity": { + "type": "string", + "enum": ["warning", "error"] + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + } + }, + "arguments": { + "type": "array" + } + } + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name"], + "properties": { + "name": { + "$ref": "#/definitions/revive-rules", + "title": "The rule name" + }, + "disabled": { + "type": "boolean" + }, + "severity": { + "type": "string", + "enum": ["warning", "error"] + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + } + }, + "arguments": { + "type": "array" + } + } + } + } + } + }, + "rowserrcheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "packages": { + "type": "array", + "items": { + "description": "", + "type": "string", + "examples": ["github.com/jmoiron/sqlx"] + } + } + } + }, + "sloglintSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "kv-only": { + "description": "Enforce using key-value pairs only (incompatible with attr-only).", + "type": "boolean", + "default": false + }, + "no-global": { + "description": "Enforce not using global loggers.", + "enum": ["", "all", "default"], + "default": "" + }, + "no-mixed-args": { + "description": "Enforce not mixing key-value pairs and attributes.", + "type": "boolean", + "default": true + }, + "context": { + "description": "Enforce using methods that accept a context.", + "enum": ["", "all", "scope"], + "default": "" + }, + "static-msg": { + "description": "Enforce using static values for log messages.", + "type": "boolean", + "default": false + }, + "key-naming-case": { + "description": "Enforce a single key naming convention.", + "enum": ["snake", "kebab", "camel", "pascal"] + }, + "attr-only": { + "description": "Enforce using attributes only (incompatible with kv-only).", + "type": "boolean", + "default": false + }, + "no-raw-keys": { + "description": "Enforce using constants instead of raw keys.", + "type": "boolean", + "default": false + }, + "forbidden-keys": { + "description": "Enforce not using specific keys.", + "type": "array", + "items": { + "type": "string" + } + }, + "args-on-sep-lines": { + "description": "Enforce putting arguments on separate lines.", + "type": "boolean", + "default": false + } + } + }, + "spancheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "checks": { + "description": "Checks to enable.", + "type": "array", + "items": { + "enum": ["end", "record-error", "set-status"] + } + }, + "ignore-check-signatures": { + "description": "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.", + "type": "array", + "items": { + "type": "string" + } + }, + "extra-start-span-signatures": { + "description": "A list of regexes for additional function signatures that create spans.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "staticcheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "checks": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/staticcheck-checks" + }, + { + "type": "string" + } + ] + } + }, + "dot-import-whitelist": { + "description": "By default, ST1001 forbids all uses of dot imports in non-test packages. This setting allows setting a whitelist of import paths that can be dot-imported anywhere.", + "type": "array", + "items": { + "type": "string" + } + }, + "http-status-code-whitelist": { + "description": "ST1013 recommends using constants from the net/http package instead of hard-coding numeric HTTP status codes. This setting specifies a list of numeric status codes that this check does not complain about.", + "default": ["200", "400", "404", "500"], + "type": "array", + "items": { + "enum": [ + "100", + "101", + "102", + "103", + "200", + "201", + "202", + "203", + "204", + "205", + "206", + "207", + "208", + "226", + "300", + "301", + "302", + "303", + "304", + "305", + "306", + "307", + "308", + "400", + "401", + "402", + "403", + "404", + "405", + "406", + "407", + "408", + "409", + "410", + "411", + "412", + "413", + "414", + "415", + "416", + "417", + "418", + "421", + "422", + "423", + "424", + "425", + "426", + "428", + "429", + "431", + "451", + "500", + "501", + "502", + "503", + "504", + "505", + "506", + "507", + "508", + "510", + "511" + ] + } + }, + "initialisms": { + "description": "ST1003 check, among other things, for the correct capitalization of initialisms. The set of known initialisms can be configured with this option.", + "type": "array", + "items": { + "type": "string", + "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" + ] + } + } + } + }, + "tagalignSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "align": { + "description": "Align and sort can be used together or separately.", + "type": "boolean", + "default": true + }, + "sort": { + "description": "Whether enable tags sort.", + "type": "boolean", + "default": true + }, + "order": { + "description": "Specify the order of tags, the other tags will be sorted by name.", + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "examples": [ + [ + "json", + "yaml", + "yml", + "toml", + "mapstructure", + "binding", + "validate" + ] + ] + }, + "strict": { + "description": "Whether enable strict style.", + "type": "boolean", + "default": false + } + } + }, + "tagliatelleSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "case": { + "type": "object", + "additionalProperties": false, + "properties": { + "use-field-name": { + "description": "Use the struct field name to check the name of the struct tag.", + "type": "boolean", + "default": false + }, + "ignored-fields": { + "description": "The field names to ignore.", + "type": "array", + "items": { + "type": "string", + "examples": ["example"] + } + }, + "rules": { + "type": "object", + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/tagliatelle-cases" + } + } + }, + "extended-rules": { + "description": "Defines the association between tag name and case.", + "type": "object", + "patternProperties": { + "^.+$": { + "type": "object", + "additionalProperties": false, + "required": ["case"], + "properties": { + "case": { + "$ref": "#/definitions/tagliatelle-cases" + }, + "extra-initialisms": { + "type": "boolean", + "default": false + }, + "initialism-overrides": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": "boolean", + "default": false + } + } + } + } + } + } + }, + "overrides": { + "description": "Overrides the default/root configuration.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["pkg"], + "properties": { + "pkg": { + "description": "A package path.", + "type": "string" + }, + "use-field-name": { + "description": "Use the struct field name to check the name of the struct tag.", + "type": "boolean", + "default": false + }, + "ignored-fields": { + "description": "The field names to ignore.", + "type": "array", + "items": { + "type": "string", + "examples": ["example"] + } + }, + "ignore": { + "description": "Ignore the package (takes precedence over all other configurations).", + "type": "boolean", + "default": false + }, + "rules": { + "type": "object", + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/tagliatelle-cases" + } + } + }, + "extended-rules": { + "description": "Defines the association between tag name and case.", + "type": "object", + "patternProperties": { + "^.+$": { + "type": "object", + "additionalProperties": false, + "required": ["case"], + "properties": { + "case": { + "$ref": "#/definitions/tagliatelle-cases" + }, + "extra-initialisms": { + "type": "boolean", + "default": false + }, + "initialism-overrides": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": "boolean", + "default": false + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "testifylintSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "enable-all": { + "description": "Enable all checkers.", + "type": "boolean", + "default": false + }, + "disable-all": { + "description": "Disable all checkers.", + "type": "boolean", + "default": false + }, + "enable": { + "description": "Enable specific checkers.", + "type": "array", + "items": { + "enum": [ + "blank-import", + "bool-compare", + "compares", + "contains", + "empty", + "encoded-compare", + "equal-values", + "error-is-as", + "error-nil", + "expected-actual", + "float-compare", + "formatter", + "go-require", + "len", + "negative-positive", + "nil-compare", + "regexp", + "require-error", + "suite-broken-parallel", + "suite-dont-use-pkg", + "suite-extra-assert-call", + "suite-method-signature", + "suite-subtest-run", + "suite-thelper", + "useless-assert" + ] + }, + "default": [ + "blank-import", + "bool-compare", + "compares", + "contains", + "empty", + "encoded-compare", + "equal-values", + "error-is-as", + "error-nil", + "expected-actual", + "float-compare", + "formatter", + "go-require", + "len", + "negative-positive", + "nil-compare", + "regexp", + "require-error", + "suite-broken-parallel", + "suite-dont-use-pkg", + "suite-extra-assert-call", + "suite-method-signature", + "suite-subtest-run", + "useless-assert" + ] + }, + "disable": { + "description": "Disable specific checkers.", + "type": "array", + "items": { + "enum": [ + "blank-import", + "bool-compare", + "compares", + "contains", + "empty", + "encoded-compare", + "equal-values", + "error-is-as", + "error-nil", + "expected-actual", + "float-compare", + "formatter", + "go-require", + "len", + "negative-positive", + "nil-compare", + "regexp", + "require-error", + "suite-broken-parallel", + "suite-dont-use-pkg", + "suite-extra-assert-call", + "suite-method-signature", + "suite-subtest-run", + "suite-thelper", + "useless-assert" + ], + "default": [ + "suite-thelper" + ] + } + }, + "bool-compare": { + "type": "object", + "additionalProperties": false, + "properties": { + "ignore-custom-types": { + "description": "To ignore user defined types (over builtin bool).", + "type": "boolean", + "default": false + } + } + }, + "expected-actual": { + "type": "object", + "additionalProperties": false, + "properties": { + "pattern": { + "description": "Regexp for expected variable name.", + "type": "string", + "default": "(^(exp(ected)?|want(ed)?)([A-Z]\\w*)?$)|(^(\\w*[a-z])?(Exp(ected)?|Want(ed)?)$)" + } + } + }, + "formatter": { + "type": "object", + "additionalProperties": false, + "properties": { + "check-format-string": { + "description": "To enable go vet's printf checks.", + "type": "boolean", + "default": true + }, + "require-f-funcs": { + "description": "To require f-assertions (e.g. assert.Equalf) if format string is used, even if there are no variable-length variables.", + "type": "boolean", + "default": false + }, + "require-string-msg": { + "description": "To require that the first element of msgAndArgs (msg) has a string type.", + "type": "boolean", + "default": true + } + } + }, + "go-require": { + "type": "object", + "additionalProperties": false, + "properties": { + "ignore-http-handlers": { + "description": "To ignore HTTP handlers (like http.HandlerFunc).", + "type": "boolean", + "default": false + } + } + }, + "require-error": { + "type": "object", + "additionalProperties": false, + "properties": { + "fn-pattern": { + "description": "Regexp for assertions to analyze. If defined, then only matched error assertions will be reported.", + "type": "string", + "default": "" + } + } + }, + "suite-extra-assert-call": { + "type": "object", + "additionalProperties": false, + "properties": { + "mode": { + "description": "To require or remove extra Assert() call?", + "type": "string", + "enum": ["remove", "require"], + "default": "remove" + } + } + } + } + }, + "testpackageSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "skip-regexp": { + "description": "Files with names matching this regular expression are skipped.", + "type": "string", + "examples": ["(export|internal)_test\\.go"] + }, + "allow-packages": { + "description": "List of packages that don't end with _test that tests are allowed to be in.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "examples": ["example"] + } + } + } + }, + "thelperSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "test": { + "type": "object", + "additionalProperties": false, + "properties": { + "begin": { + "description": "Check if `t.Helper()` begins helper function.", + "default": true, + "type": "boolean" + }, + "first": { + "description": "Check if *testing.T is first param of helper function.", + "default": true, + "type": "boolean" + }, + "name": { + "description": "Check if *testing.T param has t name.", + "default": true, + "type": "boolean" + } + } + }, + "benchmark": { + "type": "object", + "additionalProperties": false, + "properties": { + "begin": { + "description": "Check if `b.Helper()` begins helper function.", + "default": true, + "type": "boolean" + }, + "first": { + "description": "Check if *testing.B is first param of helper function.", + "default": true, + "type": "boolean" + }, + "name": { + "description": "Check if *testing.B param has b name.", + "default": true, + "type": "boolean" + } + } + }, + "tb": { + "type": "object", + "additionalProperties": false, + "properties": { + "begin": { + "description": "Check if `tb.Helper()` begins helper function.", + "default": true, + "type": "boolean" + }, + "first": { + "description": "Check if *testing.TB is first param of helper function.", + "default": true, + "type": "boolean" + }, + "name": { + "description": "Check if *testing.TB param has tb name.", + "default": true, + "type": "boolean" + } + } + }, + "fuzz": { + "type": "object", + "additionalProperties": false, + "properties": { + "begin": { + "description": "Check if `f.Helper()` begins helper function.", + "default": true, + "type": "boolean" + }, + "first": { + "description": "Check if *testing.F is first param of helper function.", + "default": true, + "type": "boolean" + }, + "name": { + "description": "Check if *testing.F param has f name.", + "default": true, + "type": "boolean" + } + } + } + } + }, + "usestdlibvarsSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "http-method": { + "description": "Suggest the use of http.MethodXX.", + "type": "boolean", + "default": true + }, + "http-status-code": { + "description": "Suggest the use of http.StatusXX.", + "type": "boolean", + "default": true + }, + "time-weekday": { + "description": "Suggest the use of time.Weekday.String().", + "type": "boolean", + "default": false + }, + "time-month": { + "description": "Suggest the use of time.Month.String().", + "type": "boolean", + "default": false + }, + "time-layout": { + "description": "Suggest the use of time.Layout.", + "type": "boolean", + "default": false + }, + "crypto-hash": { + "description": "Suggest the use of crypto.Hash.String().", + "type": "boolean", + "default": false + }, + "default-rpc-path": { + "description": "Suggest the use of rpc.DefaultXXPath.", + "type": "boolean", + "default": false + }, + "sql-isolation-level": { + "description": "Suggest the use of sql.LevelXX.String().", + "type": "boolean", + "default": false + }, + "tls-signature-scheme": { + "description": "Suggest the use of tls.SignatureScheme.String().", + "type": "boolean", + "default": false + }, + "constant-kind": { + "description": "Suggest the use of constant.Kind.String().", + "type": "boolean", + "default": false + } + } + }, + "usetestingSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "context-background": { + "type": "boolean", + "default": true + }, + "context-todo": { + "type": "boolean", + "default": true + }, + "os-chdir": { + "type": "boolean", + "default": true + }, + "os-mkdir-temp": { + "type": "boolean", + "default": true + }, + "os-setenv": { + "type": "boolean", + "default": true + }, + "os-create-temp": { + "type": "boolean", + "default": true + }, + "os-temp-dir": { + "type": "boolean", + "default": false + } + } + }, + "unconvertSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "fast-math": { + "type": "boolean", + "default": false + }, + "safe": { + "type": "boolean", + "default": false + } + } + }, + "unparamSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "check-exported": { + "description": "Inspect exported functions. Set to true if no external program/library imports your code.\n\nWARNING: if you enable this setting, unparam will report a lot of false-positives in text editors:\nif it's called for subdir of a project it can't find external interfaces. All text editor integrations\nwith golangci-lint call it on a directory with the changed file.", + "type": "boolean", + "default": false + } + } + }, + "unusedSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "field-writes-are-uses": { + "description": "", + "type": "boolean", + "default": true + }, + "post-statements-are-reads": { + "description": "", + "type": "boolean", + "default": false + }, + "exported-fields-are-used": { + "description": "", + "type": "boolean", + "default": true + }, + "parameters-are-used": { + "description": "", + "type": "boolean", + "default": true + }, + "local-variables-are-used": { + "description": "", + "type": "boolean", + "default": true + }, + "generated-is-used": { + "description": "", + "type": "boolean", + "default": true + } + } + }, + "varnamelenSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "max-distance": { + "description": "Variables used in at most this N-many lines will be ignored.", + "type": "integer", + "default": 5 + }, + "min-name-length": { + "description": "The minimum length of a variable's name that is considered `long`.", + "type": "integer", + "default": 3 + }, + "check-receiver": { + "description": "Check method receiver names.", + "default": false, + "type": "boolean" + }, + "check-return": { + "description": "Check named return values.", + "default": false, + "type": "boolean" + }, + "check-type-param": { + "description": "Check type parameters.", + "default": false, + "type": "boolean" + }, + "ignore-type-assert-ok": { + "description": "Ignore `ok` variables that hold the bool return value of a type assertion", + "default": false, + "type": "boolean" + }, + "ignore-map-index-ok": { + "description": "Ignore `ok` variables that hold the bool return value of a map index.", + "default": false, + "type": "boolean" + }, + "ignore-chan-recv-ok": { + "description": "Ignore `ok` variables that hold the bool return value of a channel receive.", + "default": false, + "type": "boolean" + }, + "ignore-names": { + "description": "Optional list of variable names that should be ignored completely.", + "default": [[]], + "type": "array", + "items": { + "type": "string" + } + }, + "ignore-decls": { + "description": "Optional list of variable declarations that should be ignored completely.", + "type": "array", + "items": { + "type": "string" + }, + "examples": [ + ["c echo.Context", "t testing.T", "f *foo.Bar", "const C"] + ] + } + } + }, + "whitespaceSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "multi-if": { + "description": "Enforces newlines (or comments) after every multi-line if statement", + "type": "boolean", + "default": false + }, + "multi-func": { + "description": "Enforces newlines (or comments) after every multi-line function signature", + "type": "boolean", + "default": false + } + } + }, + "wrapcheckSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "extra-ignore-sigs": { + "description": "An array of strings specifying additional substrings of signatures to ignore.", + "default": [ + ".CustomError(", + ".SpecificWrap(" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "ignore-sigs": { + "description": "An array of strings which specify substrings of signatures to ignore.", + "default": [ + ".Errorf(", + "errors.New(", + "errors.Unwrap(", + ".Wrap(", + ".Wrapf(", + ".WithMessage(", + ".WithMessagef(", + ".WithStack(" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "ignore-sig-regexps": { + "description": "An array of strings which specify regular expressions of signatures to ignore.", + "default": [""], + "type": "array", + "items": { + "type": "string" + } + }, + "ignore-package-globs": { + "description": "An array of glob patterns which, if any match the package of the function returning the error, will skip wrapcheck analysis for this error.", + "default": [""], + "type": "array", + "items": { + "type": "string" + } + }, + "ignore-interface-regexps": { + "description": "An array of glob patterns which, if matched to an underlying interface name, will ignore unwrapped errors returned from a function whose call is defined on the given interface.", + "default": [""], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "wslSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "allow-assign-and-anything": { + "description": "Controls if you may cuddle assignments and anything without needing an empty line between them.", + "type": "boolean", + "default": false + }, + "allow-assign-and-call": { + "description": "Allow calls and assignments to be cuddled as long as the lines have any matching variables, fields or types.", + "type": "boolean", + "default": true + }, + "allow-cuddle-declarations": { + "description": "Allow declarations (var) to be cuddled.", + "type": "boolean", + "default": false + }, + "allow-cuddle-with-calls": { + "description": "A list of call idents that everything can be cuddled with.", + "type": "array", + "items": { + "type": "string" + } + }, + "allow-cuddle-with-rhs": { + "description": "AllowCuddleWithRHS is a list of right hand side variables that is allowed to be cuddled with anything.", + "type": "array", + "items": { + "type": "string" + } + }, + "allow-cuddle-used-in-block": { + "description": "Allow cuddling with any block as long as the variable is used somewhere in the block", + "type": "boolean", + "default": false + }, + "allow-multiline-assign": { + "description": "Allow multiline assignments to be cuddled.", + "type": "boolean", + "default": true + }, + "allow-separated-leading-comment": { + "description": "Allow leading comments to be separated with empty lines.", + "type": "boolean", + "default": false + }, + "allow-trailing-comment": { + "description": "Allow trailing comments in ending of blocks.", + "type": "boolean", + "default": false + }, + "error-variable-names": { + "description": "When force-err-cuddling is enabled this is a list of names used for error variables to check for in the conditional.", + "type": "array", + "items": { + "type": "string" + } + }, + "force-case-trailing-whitespace": { + "description": "Force newlines in end of case at this limit (0 = never).", + "type": "integer", + "minimum": 0, + "default": 0 + }, + "force-err-cuddling": { + "description": "Causes an error when an If statement that checks an error variable doesn't cuddle with the assignment of that variable.", + "type": "boolean", + "default": false + }, + "force-short-decl-cuddling": { + "description": "Causes an error if a short declaration (:=) cuddles with anything other than another short declaration.", + "type": "boolean", + "default": false + }, + "strict-append": { + "description": "If true, append is only allowed to be cuddled if appending value is matching variables, fields or types on line above.", + "type": "boolean", + "default": true + } + } + }, + "copyloopvarSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "check-alias": { + "type": "boolean", + "default": false + } + } + }, + "customSettings": { + "description": "The custom section can be used to define linter plugins to be loaded at runtime. See README of golangci-lint for more information.\nEach custom linter should have a unique name.", + "type": "object", + "patternProperties": { + "^.*$": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "description": "The plugin type.", + "enum": ["module", "goplugin"], + "default": "goplugin" + }, + "path": { + "description": "The path to the plugin *.so. Can be absolute or local.", + "type": "string", + "examples": ["/path/to/example.so"] + }, + "description": { + "description": "The description of the linter, for documentation purposes only.", + "type": "string" + }, + "original-url": { + "description": "Intended to point to the repo location of the linter, for documentation purposes only.", + "type": "string" + }, + "settings": { + "description": "Plugins settings/configuration. Only work with plugin based on `linterdb.PluginConstructor`.", + "type": "object" + } + }, + "oneOf": [ + { + "properties": { + "type": {"enum": ["module"] } + }, + "required": ["type"] + }, + { + "required": ["path"] + } + ] + } + } + } + } + } + }, + "type": "object", + "additionalProperties": false, + "required": ["version"], + "properties": { + "version": { + "type": "string", + "default": "2" + }, + "run": { + "description": "Options for analysis running,", + "type": "object", + "additionalProperties": false, + "properties": { + "concurrency": { + "description": "Number of concurrent runners. Defaults to the number of available CPU cores.", + "type": "integer", + "minimum": 0, + "examples": [4] + }, + "timeout": { + "description": "Timeout for the analysis.", + "type": "string", + "pattern": "^((\\d+h)?(\\d+m)?(\\d+(?:\\.\\d)?s)?|0)$", + "default": "1m", + "examples": ["30s", "5m", "5m30s"] + }, + "issues-exit-code": { + "description": "Exit code when at least one issue was found.", + "type": "integer", + "default": 1 + }, + "tests": { + "description": "Enable inclusion of test files.", + "type": "boolean", + "default": true + }, + "build-tags": { + "description": "List of build tags to pass to all linters.", + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "examples": [["mytag"]] + }, + "modules-download-mode": { + "description": "Option to pass to \"go list -mod={option}\".\nSee \"go help modules\" for more information.", + "enum": ["mod", "readonly", "vendor"] + }, + "allow-parallel-runners": { + "description": "Allow multiple parallel golangci-lint instances running. If disabled, golangci-lint acquires file lock on start.", + "type": "boolean", + "default": false + }, + "allow-serial-runners": { + "description": "Allow multiple golangci-lint instances running, but serialize them around a lock.", + "type": "boolean", + "default": false + }, + "go": { + "description": "Targeted Go version.", + "type": "string", + "default": "1.17" + }, + "relative-path-mode": { + "description": "The mode used to evaluate relative paths.", + "type": "string", + "$ref": "#/definitions/relative-path-modes", + "default": "wd" + } + } + }, + "output": { + "description": "Output configuration options.", + "type": "object", + "additionalProperties": false, + "properties": { + "formats": { + "description": "Output formats to use.", + "type": "object", + "additionalProperties": false, + "properties": { + "text": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "$ref": "#/definitions/formats-path", + "default": "stdout" + }, + "print-linter-name": { + "type": "boolean", + "default": true + }, + "print-issued-lines": { + "type": "boolean", + "default": true + }, + "colors": { + "type": "boolean", + "default": true + } + } + }, + "json": { + "$ref": "#/definitions/simple-format" + }, + "tab": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "$ref": "#/definitions/formats-path", + "default": "stdout" + }, + "print-linter-name": { + "type": "boolean", + "default": true + }, + "colors": { + "type": "boolean", + "default": true + } + } + }, + "html": { + "$ref": "#/definitions/simple-format" + }, + "checkstyle": { + "$ref": "#/definitions/simple-format" + }, + "code-climate": { + "$ref": "#/definitions/simple-format" + }, + "junit-xml": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "$ref": "#/definitions/formats-path", + "default": "stdout" + }, + "extended": { + "type": "boolean", + "default": true + } + } + }, + "teamcity": { + "$ref": "#/definitions/simple-format" + }, + "sarif": { + "$ref": "#/definitions/simple-format" + } + } + }, + "path-prefix": { + "description": "Add a prefix to the output file references.", + "type": "string", + "default": "" + }, + "show-stats": { + "description": "Show statistics per linter.", + "type": "boolean", + "default": true + }, + "sort-order": { + "type": "array", + "items": { + "enum": ["linter", "severity", "file"] + } + } + } + }, + "linters": { + "type": "object", + "additionalProperties": false, + "properties": { + "default": { + "enum": [ + "standard", + "all", + "none", + "fast" + ] + }, + "enable": { + "description": "List of enabled linters.", + "type": "array", + "items": { + "$ref": "#/definitions/linter-names" + } + }, + "disable": { + "description": "List of disabled linters.", + "type": "array", + "items": { + "$ref": "#/definitions/linter-names" + } + }, + "settings": { + "description": "All available settings of specific linters.", + "type": "object", + "additionalProperties": false, + "properties": { + "dupword": { + "$ref": "#/definitions/settings/definitions/dupwordSettings" + }, + "asasalint": { + "$ref": "#/definitions/settings/definitions/asasalintSettings" + }, + "bidichk": { + "$ref": "#/definitions/settings/definitions/bidichkSettings" + }, + "cyclop": { + "$ref": "#/definitions/settings/definitions/cyclopSettings" + }, + "decorder": { + "$ref": "#/definitions/settings/definitions/decorderSettings" + }, + "depguard":{ + "$ref": "#/definitions/settings/definitions/depguardSettings" + }, + "dogsled": { + "$ref": "#/definitions/settings/definitions/dogsledSettings" + }, + "dupl": { + "$ref": "#/definitions/settings/definitions/duplSettings" + }, + "errcheck": { + "$ref": "#/definitions/settings/definitions/errcheckSettings" + }, + "errchkjson": { + "$ref": "#/definitions/settings/definitions/errchkjsonSettings" + }, + "errorlint": { + "$ref": "#/definitions/settings/definitions/errorlintSettings" + }, + "exhaustive": { + "$ref": "#/definitions/settings/definitions/exhaustiveSettings" + }, + "exhaustruct": { + "$ref": "#/definitions/settings/definitions/exhaustructSettings" + }, + "fatcontext": { + "$ref": "#/definitions/settings/definitions/fatcontextSettings" + }, + "forbidigo": { + "$ref": "#/definitions/settings/definitions/forbidigoSettings" + }, + "funlen": { + "$ref": "#/definitions/settings/definitions/funlenSettings" + }, + "ginkgolinter": { + "$ref": "#/definitions/settings/definitions/ginkgolinterSettings" + }, + "gochecksumtype": { + "$ref": "#/definitions/settings/definitions/gochecksumtypeSettings" + }, + "gocognit": { + "$ref": "#/definitions/settings/definitions/gocognitSettings" + }, + "goconst": { + "$ref": "#/definitions/settings/definitions/goconstSettings" + }, + "gocritic": { + "$ref": "#/definitions/settings/definitions/gocriticSettings" + }, + "gocyclo": { + "$ref": "#/definitions/settings/definitions/gocycloSettings" + }, + "godot": { + "$ref": "#/definitions/settings/definitions/godotSettings" + }, + "godox": { + "$ref": "#/definitions/settings/definitions/godoxSettings" + }, + "interfacebloat":{ + "$ref": "#/definitions/settings/definitions/interfacebloatSettings" + }, + "goheader": { + "$ref": "#/definitions/settings/definitions/goheaderSettings" + }, + "gomoddirectives": { + "$ref": "#/definitions/settings/definitions/gomoddirectivesSettings" + }, + "gomodguard": { + "$ref": "#/definitions/settings/definitions/gomodguardSettings" + }, + "gosec": { + "$ref": "#/definitions/settings/definitions/gosecSettings" + }, + "gosmopolitan": { + "$ref": "#/definitions/settings/definitions/gosmopolitanSettings" + }, + "govet": { + "$ref": "#/definitions/settings/definitions/govetSettings" + }, + "grouper": { + "$ref": "#/definitions/settings/definitions/grouperSettings" + }, + "iface": { + "$ref": "#/definitions/settings/definitions/ifaceSettings" + }, + "importas": { + "$ref": "#/definitions/settings/definitions/importasSettings" + }, + "inamedparam": { + "$ref": "#/definitions/settings/definitions/inamedparamSettings" + }, + "ireturn": { + "$ref": "#/definitions/settings/definitions/ireturnSettings" + }, + "lll": { + "$ref": "#/definitions/settings/definitions/lllSettings" + }, + "maintidx": { + "$ref": "#/definitions/settings/definitions/maintidxSettings" + }, + "makezero":{ + "$ref": "#/definitions/settings/definitions/makezeroSettings" + }, + "loggercheck": { + "$ref": "#/definitions/settings/definitions/loggercheckSettings" + }, + "misspell": { + "$ref": "#/definitions/settings/definitions/misspellSettings" + }, + "musttag": { + "$ref": "#/definitions/settings/definitions/musttagSettings" + }, + "nakedret": { + "$ref": "#/definitions/settings/definitions/nakedretSettings" + }, + "nestif": { + "$ref": "#/definitions/settings/definitions/nestifSettings" + }, + "nilnil": { + "$ref": "#/definitions/settings/definitions/nilnilSettings" + }, + "nlreturn": { + "$ref": "#/definitions/settings/definitions/nlreturnSettings" + }, + "mnd": { + "$ref": "#/definitions/settings/definitions/mndSettings" + }, + "nolintlint":{ + "$ref": "#/definitions/settings/definitions/nolintlintSettings" + }, + "reassign": { + "$ref": "#/definitions/settings/definitions/reassignSettings" + }, + "recvcheck": { + "$ref": "#/definitions/settings/definitions/recvcheckSettings" + }, + "nonamedreturns": { + "$ref": "#/definitions/settings/definitions/nonamedreturnsSettings" + }, + "paralleltest": { + "$ref": "#/definitions/settings/definitions/paralleltestSettings" + }, + "perfsprint": { + "$ref": "#/definitions/settings/definitions/perfsprintSettings" + }, + "prealloc": { + "$ref": "#/definitions/settings/definitions/preallocSettings" + }, + "predeclared": { + "$ref": "#/definitions/settings/definitions/predeclaredSettings" + }, + "promlinter": { + "$ref": "#/definitions/settings/definitions/promlinterSettings" + }, + "protogetter": { + "$ref": "#/definitions/settings/definitions/protogetterSettings" + }, + "revive": { + "$ref": "#/definitions/settings/definitions/reviveSettings" + }, + "rowserrcheck": { + "$ref": "#/definitions/settings/definitions/rowserrcheckSettings" + }, + "sloglint": { + "$ref": "#/definitions/settings/definitions/sloglintSettings" + }, + "spancheck": { + "$ref": "#/definitions/settings/definitions/spancheckSettings" + }, + "staticcheck":{ + "$ref": "#/definitions/settings/definitions/staticcheckSettings" + }, + "tagalign": { + "$ref": "#/definitions/settings/definitions/tagalignSettings" + }, + "tagliatelle": { + "$ref": "#/definitions/settings/definitions/tagliatelleSettings" + }, + "testifylint": { + "$ref": "#/definitions/settings/definitions/testifylintSettings" + }, + "testpackage": { + "$ref": "#/definitions/settings/definitions/testpackageSettings" + }, + "thelper": { + "$ref": "#/definitions/settings/definitions/thelperSettings" + }, + "usestdlibvars": { + "$ref": "#/definitions/settings/definitions/usestdlibvarsSettings" + }, + "usetesting": { + "$ref": "#/definitions/settings/definitions/usetestingSettings" + }, + "unconvert": { + "$ref": "#/definitions/settings/definitions/unconvertSettings" + }, + "unparam": { + "$ref": "#/definitions/settings/definitions/unparamSettings" + }, + "unused": { + "$ref": "#/definitions/settings/definitions/unusedSettings" + }, + "varnamelen": { + "$ref": "#/definitions/settings/definitions/varnamelenSettings" + }, + "whitespace": { + "$ref": "#/definitions/settings/definitions/whitespaceSettings" + }, + "wrapcheck": { + "$ref": "#/definitions/settings/definitions/wrapcheckSettings" + }, + "wsl": { + "$ref": "#/definitions/settings/definitions/wslSettings" + }, + "copyloopvar": { + "$ref": "#/definitions/settings/definitions/copyloopvarSettings" + }, + "custom":{ + "$ref": "#/definitions/settings/definitions/customSettings" + } + } + }, + "exclusions":{ + "type": "object", + "additionalProperties": false, + "properties": { + "generated": { + "enum": ["strict", "lax", "disable"], + "default": "strict" + }, + "warn-unused": { + "type": "boolean", + "default": false + }, + "presets": { + "type": "array", + "items": { + "enum": [ + "comments", + "std-error-handling", + "common-false-positives", + "legacy" + ] + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "path-except": { + "type": "string" + }, + "linters": { + "type": "array", + "items": { + "$ref": "#/definitions/linter-names" + } + }, + "text": { + "type": "string" + }, + "source": { + "type": "string" + } + }, + "anyOf": [ + { "required": ["path"] }, + { "required": ["path-except"] }, + { "required": ["linters"] }, + { "required": ["text"] }, + { "required": ["source"] } + ] + } + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + }, + "paths-except": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "formatters": { + "type": "object", + "additionalProperties": false, + "properties": { + "enable": { + "description": "List of enabled formatters.", + "type": "array", + "items": { + "$ref": "#/definitions/formatter-names" + } + }, + "settings": { + "type": "object", + "additionalProperties": false, + "properties": { + "gci": { + "$ref": "#/definitions/settings/definitions/gciSettings" + }, + "gofmt": { + "$ref": "#/definitions/settings/definitions/gofmtSettings" + }, + "gofumpt": { + "$ref": "#/definitions/settings/definitions/gofumptSettings" + }, + "goimports": { + "$ref": "#/definitions/settings/definitions/goimportsSettings" + }, + "golines": { + "$ref": "#/definitions/settings/definitions/golinesSettings" + } + } + }, + "exclusions": { + "type": "object", + "additionalProperties": false, + "properties": { + "generated": { + "enum": ["strict", "lax", "disable"], + "default": "strict" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "issues": { + "type": "object", + "additionalProperties": false, + "properties": { + "max-issues-per-linter": { + "description": "Maximum issues count per one linter. Set to 0 to disable.", + "type": "integer", + "default": 50, + "minimum": 0 + }, + "max-same-issues": { + "description": "Maximum count of issues with the same text. Set to 0 to disable.", + "type": "integer", + "default": 3, + "minimum": 0 + }, + "new": { + "description": "Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.", + "type": "boolean", + "default": false + }, + "new-from-merge-base": { + "description": "Show only new issues created after the best common ancestor (merge-base against HEAD).", + "type": "string" + }, + "new-from-rev": { + "description": "Show only new issues created after this git revision.", + "type": "string" + }, + "new-from-patch": { + "description": "Show only new issues created in git patch with this file path.", + "type": "string", + "examples": ["path/to/patch/file"] + }, + "fix": { + "description": "Fix found issues (if it's supported by the linter).", + "type": "boolean", + "default": false + }, + "uniq-by-line": { + "description": "Make issues output unique by line.", + "type": "boolean", + "default": true + }, + "whole-files": { + "description": "Show issues in any part of update files (requires new-from-rev or new-from-patch).", + "type": "boolean", + "default": false + } + } + }, + "severity": { + "type": "object", + "additionalProperties": false, + "properties": { + "default": { + "description": "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.", + "type": "string", + "default": "" + }, + "rules": { + "description": "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.\nOnly affects out formats that support setting severity information.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "severity": { + "type": "string" + }, + "path": { + "type": "string" + }, + "path-except": { + "type": "string" + }, + "linters": { + "type": "array", + "items": { + "$ref": "#/definitions/linter-names" + } + }, + "text": { + "type": "string" + }, + "source": { + "type": "string" + } + }, + "required": ["severity"], + "anyOf": [ + { "required": ["path"] }, + { "required": ["path-except"] }, + { "required": ["linters"] }, + { "required": ["text"] }, + { "required": ["source"] } + ] + }, + "default": [] + } + }, + "required": ["default"] + } + } +} diff --git a/pkg/commands/config.go b/pkg/commands/config.go index eba00fe0d770..6628aa427b05 100644 --- a/pkg/commands/config.go +++ b/pkg/commands/config.go @@ -96,7 +96,7 @@ func (c *configCommand) preRunE(cmd *cobra.Command, args []string) error { // It only needs to know the path of the configuration file. cfg := config.NewDefault() - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts, cfg, args) + loader := config.NewLintersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts, cfg, args) err := loader.Load(config.LoadOptions{}) if err != nil { diff --git a/pkg/commands/flagsets.go b/pkg/commands/flagsets.go index 2ef165852d02..cc4b00436e3a 100644 --- a/pkg/commands/flagsets.go +++ b/pkg/commands/flagsets.go @@ -62,6 +62,8 @@ func setupRunFlagSet(v *viper.Viper, fs *pflag.FlagSet) { func setupOutputFlagSet(v *viper.Viper, fs *pflag.FlagSet) { internal.AddFlagAndBind(v, fs, fs.String, "path-prefix", "output.path-prefix", "", color.GreenString("Path prefix to add to output")) + internal.AddFlagAndBind(v, fs, fs.String, "path-mode", "output.path-mode", "", + color.GreenString("Path mode to use (empty, or 'abs')")) internal.AddFlagAndBind(v, fs, fs.Bool, "show-stats", "output.show-stats", true, color.GreenString("Show statistics per linter")) setupOutputFormatsFlagSet(v, fs) diff --git a/pkg/commands/fmt.go b/pkg/commands/fmt.go index a67be04fd1dc..502dcebdfe9c 100644 --- a/pkg/commands/fmt.go +++ b/pkg/commands/fmt.go @@ -20,8 +20,9 @@ import ( type fmtOptions struct { config.LoaderOptions - diff bool // Flag only. - stdin bool // Flag only. + diff bool // Flag only. + diffColored bool // Flag only. + stdin bool // Flag only. } type fmtCommand struct { @@ -70,6 +71,7 @@ func newFmtCommand(logger logutils.Log, info BuildInfo) *fmtCommand { setupFormattersFlagSet(c.viper, fs) fs.BoolVarP(&c.opts.diff, "diff", "d", false, color.GreenString("Display diffs instead of rewriting files")) + fs.BoolVar(&c.opts.diffColored, "diff-colored", false, color.GreenString("Display diffs instead of rewriting files (with colors)")) fs.BoolVar(&c.opts.stdin, "stdin", false, color.GreenString("Use standard input for piping source files")) c.cmd = fmtCmd @@ -80,7 +82,7 @@ func newFmtCommand(logger logutils.Log, info BuildInfo) *fmtCommand { func (c *fmtCommand) persistentPreRunE(cmd *cobra.Command, args []string) error { c.log.Infof("%s", c.buildInfo.String()) - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + loader := config.NewFormattersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) err := loader.Load(config.LoadOptions{CheckDeprecation: true, Validation: true}) if err != nil { @@ -102,7 +104,7 @@ func (c *fmtCommand) preRunE(_ *cobra.Command, _ []string) error { matcher := processors.NewGeneratedFileMatcher(c.cfg.Formatters.Exclusions.Generated) - opts, err := goformat.NewRunnerOptions(c.cfg, c.opts.diff, c.opts.stdin) + opts, err := goformat.NewRunnerOptions(c.cfg, c.opts.diff, c.opts.diffColored, c.opts.stdin) if err != nil { return fmt.Errorf("build walk options: %w", err) } diff --git a/pkg/commands/formatters.go b/pkg/commands/formatters.go index 0c64056550be..22a9914ae2ff 100644 --- a/pkg/commands/formatters.go +++ b/pkg/commands/formatters.go @@ -59,7 +59,8 @@ func newFormattersCommand(logger logutils.Log) *formattersCommand { fs.SortFlags = false // sort them as they are defined here setupConfigFileFlagSet(fs, &c.opts.LoaderOptions) - setupLintersFlagSet(c.viper, fs) + + setupFormattersFlagSet(c.viper, fs) fs.BoolVar(&c.opts.JSON, "json", false, color.GreenString("Display as JSON")) @@ -69,7 +70,7 @@ func newFormattersCommand(logger logutils.Log) *formattersCommand { } func (c *formattersCommand) preRunE(cmd *cobra.Command, args []string) error { - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + loader := config.NewFormattersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) err := loader.Load(config.LoadOptions{Validation: true}) if err != nil { diff --git a/pkg/commands/internal/migrate/cloner/cloner.go b/pkg/commands/internal/migrate/cloner/cloner.go index 9c2400bc69b1..9a94aaf8e070 100644 --- a/pkg/commands/internal/migrate/cloner/cloner.go +++ b/pkg/commands/internal/migrate/cloner/cloner.go @@ -142,7 +142,7 @@ func convertType(expr ast.Expr) ast.Expr { } switch ident.Name { - case "bool", "string", "int", "int8", "int16", "int32", "int64", "float32", "float64": + case "bool", "string", "uint", "uint8", "uint16", "uint32", "uint64", "int", "int8", "int16", "int32", "int64", "float32", "float64": return &ast.StarExpr{X: ident} default: diff --git a/pkg/commands/internal/migrate/migrate_linter_names.go b/pkg/commands/internal/migrate/migrate_linter_names.go index da003e9af77d..bbb178ab3846 100644 --- a/pkg/commands/internal/migrate/migrate_linter_names.go +++ b/pkg/commands/internal/migrate/migrate_linter_names.go @@ -749,11 +749,8 @@ func allEnabled(old versionone.Linters, linters []LinterInfo) []LinterInfo { var results []LinterInfo for _, linter := range linters { - for _, name := range old.Enable { - if linter.isName(name) { - results = append(results, linter) - break - } + if slices.ContainsFunc(old.Enable, linter.isName) { + results = append(results, linter) } } @@ -764,11 +761,8 @@ func allDisabled(old versionone.Linters, linters []LinterInfo) []LinterInfo { var results []LinterInfo for _, linter := range linters { - for _, name := range old.Disable { - if linter.isName(name) { - results = append(results, linter) - break - } + if slices.ContainsFunc(old.Disable, linter.isName) { + results = append(results, linter) } } diff --git a/pkg/commands/internal/migrate/migrate_linters_settings.go b/pkg/commands/internal/migrate/migrate_linters_settings.go index a0559388d403..5accd9f593e5 100644 --- a/pkg/commands/internal/migrate/migrate_linters_settings.go +++ b/pkg/commands/internal/migrate/migrate_linters_settings.go @@ -789,10 +789,32 @@ func toSpancheckSettings(old versionone.SpancheckSettings) versiontwo.SpancheckS } func toStaticCheckSettings(old versionone.LintersSettings) versiontwo.StaticCheckSettings { - checks := slices.Concat(old.Staticcheck.Checks, old.Stylecheck.Checks, old.Gosimple.Checks) + var checks []string + + for _, check := range slices.Concat(old.Staticcheck.Checks, old.Stylecheck.Checks, old.Gosimple.Checks) { + if check == "*" { + checks = append(checks, "all") + continue + } + checks = append(checks, check) + } + + checks = Unique(checks) + + slices.SortFunc(checks, func(a, b string) int { + if a == "all" { + return -1 + } + + if b == "all" { + return 1 + } + + return strings.Compare(a, b) + }) return versiontwo.StaticCheckSettings{ - Checks: Unique(checks), + Checks: checks, Initialisms: old.Stylecheck.Initialisms, DotImportWhitelist: old.Stylecheck.DotImportWhitelist, HTTPStatusCodeWhitelist: old.Stylecheck.HTTPStatusCodeWhitelist, diff --git a/pkg/commands/internal/migrate/testdata/yaml/linters-settings_nakedret_zero.golden.yml b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_nakedret_zero.golden.yml new file mode 100644 index 000000000000..69e5a3b11394 --- /dev/null +++ b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_nakedret_zero.golden.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + nakedret: + max-func-lines: 0 diff --git a/pkg/commands/internal/migrate/testdata/yaml/linters-settings_nakedret_zero.yml b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_nakedret_zero.yml new file mode 100644 index 000000000000..c15f3c7bab1a --- /dev/null +++ b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_nakedret_zero.yml @@ -0,0 +1,11 @@ +issues: + # Only to not generate unrelated elements inside golden. + exclude-use-default: false + # Only to not generate unrelated elements inside golden. + exclude-generated: strict + # Only to not generate unrelated elements inside golden. + exclude-dirs-use-default: false + +linters-settings: + nakedret: + max-func-lines: 0 diff --git a/pkg/commands/internal/migrate/testdata/yaml/linters-settings_staticcheck_merge.golden.yml b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_staticcheck_merge.golden.yml new file mode 100644 index 000000000000..229a095f01f8 --- /dev/null +++ b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_staticcheck_merge.golden.yml @@ -0,0 +1,204 @@ +version: "2" +linters: + settings: + staticcheck: + checks: + - all + - -S1000 + - -S1001 + - -S1002 + - -SA1000 + - -SA1001 + - -SA1002 + - -ST1000 + - -ST1001 + - -ST1003 + - S1003 + - S1004 + - S1005 + - S1006 + - S1007 + - S1008 + - S1009 + - S1010 + - S1011 + - S1012 + - S1016 + - S1017 + - S1018 + - S1019 + - S1020 + - S1021 + - S1023 + - S1024 + - S1025 + - S1028 + - S1029 + - S1030 + - S1031 + - S1032 + - S1033 + - S1034 + - S1035 + - S1036 + - S1037 + - S1038 + - S1039 + - S1040 + - SA1003 + - SA1004 + - SA1005 + - SA1006 + - SA1007 + - SA1008 + - SA1010 + - SA1011 + - SA1012 + - SA1013 + - SA1014 + - SA1015 + - SA1016 + - SA1017 + - SA1018 + - SA1019 + - SA1020 + - SA1021 + - SA1023 + - SA1024 + - SA1025 + - SA1026 + - SA1027 + - SA1028 + - SA1029 + - SA1030 + - SA1031 + - SA1032 + - SA2000 + - SA2001 + - SA2002 + - SA2003 + - SA3000 + - SA3001 + - SA4000 + - SA4001 + - SA4003 + - SA4004 + - SA4005 + - SA4006 + - SA4008 + - SA4009 + - SA4010 + - SA4011 + - SA4012 + - SA4013 + - SA4014 + - SA4015 + - SA4016 + - SA4017 + - SA4018 + - SA4019 + - SA4020 + - SA4021 + - SA4022 + - SA4023 + - SA4024 + - SA4025 + - SA4026 + - SA4027 + - SA4028 + - SA4029 + - SA4030 + - SA4031 + - SA4032 + - SA5000 + - SA5001 + - SA5002 + - SA5003 + - SA5004 + - SA5005 + - SA5007 + - SA5008 + - SA5009 + - SA5010 + - SA5011 + - SA5012 + - SA6000 + - SA6001 + - SA6002 + - SA6003 + - SA6005 + - SA6006 + - SA9001 + - SA9002 + - SA9003 + - SA9004 + - SA9005 + - SA9006 + - SA9007 + - SA9008 + - SA9009 + - ST1005 + - ST1006 + - ST1008 + - ST1011 + - ST1012 + - ST1013 + - ST1015 + - ST1016 + - ST1017 + - ST1018 + - ST1019 + - ST1020 + - ST1021 + - ST1022 + - ST1023 + 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 + dot-import-whitelist: + - fmt + http-status-code-whitelist: + - "200" + - "400" + - "404" + - "500" diff --git a/pkg/commands/internal/migrate/testdata/yaml/linters-settings_staticcheck_merge.yml b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_staticcheck_merge.yml new file mode 100644 index 000000000000..3d9fe3cbbfc0 --- /dev/null +++ b/pkg/commands/internal/migrate/testdata/yaml/linters-settings_staticcheck_merge.yml @@ -0,0 +1,172 @@ +issues: + # Only to not generate unrelated elements inside golden. + exclude-use-default: false + # Only to not generate unrelated elements inside golden. + exclude-generated: strict + # Only to not generate unrelated elements inside golden. + exclude-dirs-use-default: false + +linters-settings: + staticcheck: + checks: + - all + - '-SA1000' + - '-SA1001' + - '-SA1002' + - SA1003 + - SA1004 + - SA1005 + - SA1006 + - SA1007 + - SA1008 + - SA1010 + - SA1011 + - SA1012 + - SA1013 + - SA1014 + - SA1015 + - SA1016 + - SA1017 + - SA1018 + - SA1019 + - SA1020 + - SA1021 + - SA1023 + - SA1024 + - SA1025 + - SA1026 + - SA1027 + - SA1028 + - SA1029 + - SA1030 + - SA1031 + - SA1032 + - SA2000 + - SA2001 + - SA2002 + - SA2003 + - SA3000 + - SA3001 + - SA4000 + - SA4001 + - SA4003 + - SA4004 + - SA4005 + - SA4006 + - SA4008 + - SA4009 + - SA4010 + - SA4011 + - SA4012 + - SA4013 + - SA4014 + - SA4015 + - SA4016 + - SA4017 + - SA4018 + - SA4019 + - SA4020 + - SA4021 + - SA4022 + - SA4023 + - SA4024 + - SA4025 + - SA4026 + - SA4027 + - SA4028 + - SA4029 + - SA4030 + - SA4031 + - SA4032 + - SA5000 + - SA5001 + - SA5002 + - SA5003 + - SA5004 + - SA5005 + - SA5007 + - SA5008 + - SA5009 + - SA5010 + - SA5011 + - SA5012 + - SA6000 + - SA6001 + - SA6002 + - SA6003 + - SA6005 + - SA6006 + - SA9001 + - SA9002 + - SA9003 + - SA9004 + - SA9005 + - SA9006 + - SA9007 + - SA9008 + - SA9009 + + gosimple: + checks: + - '*' + - '-S1000' + - '-S1001' + - '-S1002' + - S1003 + - S1004 + - S1005 + - S1006 + - S1007 + - S1008 + - S1009 + - S1010 + - S1011 + - S1012 + - S1016 + - S1017 + - S1018 + - S1019 + - S1020 + - S1021 + - S1023 + - S1024 + - S1025 + - S1028 + - S1029 + - S1030 + - S1031 + - S1032 + - S1033 + - S1034 + - S1035 + - S1036 + - S1037 + - S1038 + - S1039 + - S1040 + + stylecheck: + dot-import-whitelist: + - fmt + 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" ] + http-status-code-whitelist: [ "200", "400", "404", "500" ] + checks: + - all + - '-ST1000' + - '-ST1001' + - '-ST1003' + - ST1005 + - ST1006 + - ST1008 + - ST1011 + - ST1012 + - ST1013 + - ST1015 + - ST1016 + - ST1017 + - ST1018 + - ST1019 + - ST1020 + - ST1021 + - ST1022 + - ST1023 diff --git a/pkg/commands/internal/migrate/versionone/linters_settings.go b/pkg/commands/internal/migrate/versionone/linters_settings.go index 49427c447530..44583b7d34e0 100644 --- a/pkg/commands/internal/migrate/versionone/linters_settings.go +++ b/pkg/commands/internal/migrate/versionone/linters_settings.go @@ -489,7 +489,7 @@ type MustTagSettings struct { } type NakedretSettings struct { - MaxFuncLines uint `mapstructure:"max-func-lines"` + MaxFuncLines *uint `mapstructure:"max-func-lines"` } type NestifSettings struct { diff --git a/pkg/commands/internal/migrate/versiontwo/formatters.go b/pkg/commands/internal/migrate/versiontwo/formatters.go index bd1b6f931155..417714947a69 100644 --- a/pkg/commands/internal/migrate/versiontwo/formatters.go +++ b/pkg/commands/internal/migrate/versiontwo/formatters.go @@ -9,6 +9,7 @@ type Formatters struct { } type FormatterExclusions struct { - Generated *string `yaml:"generated,omitempty" toml:"generated,multiline,omitempty"` - Paths []string `yaml:"paths,omitempty" toml:"paths,multiline,omitempty"` + Generated *string `yaml:"generated,omitempty" toml:"generated,multiline,omitempty"` + Paths []string `yaml:"paths,omitempty" toml:"paths,multiline,omitempty"` + WarnUnused *bool `yaml:"warn-unused,omitempty" toml:"warn-unused,multiline,omitempty"` } diff --git a/pkg/commands/internal/migrate/versiontwo/linters_settings.go b/pkg/commands/internal/migrate/versiontwo/linters_settings.go index 3461620e20f7..3a0d6b7b6a2a 100644 --- a/pkg/commands/internal/migrate/versiontwo/linters_settings.go +++ b/pkg/commands/internal/migrate/versiontwo/linters_settings.go @@ -21,6 +21,7 @@ type LintersSettings struct { Exhaustruct ExhaustructSettings `yaml:"exhaustruct,omitempty" toml:"exhaustruct,multiline,omitempty"` Fatcontext FatcontextSettings `yaml:"fatcontext,omitempty" toml:"fatcontext,multiline,omitempty"` Forbidigo ForbidigoSettings `yaml:"forbidigo,omitempty" toml:"forbidigo,multiline,omitempty"` + FuncOrder FuncOrderSettings `yaml:"funcorder,omitempty" toml:"funcorder,multiline,omitempty"` Funlen FunlenSettings `yaml:"funlen,omitempty" toml:"funlen,multiline,omitempty"` GinkgoLinter GinkgoLinterSettings `yaml:"ginkgolinter,omitempty" toml:"ginkgolinter,multiline,omitempty"` Gocognit GocognitSettings `yaml:"gocognit,omitempty" toml:"gocognit,multiline,omitempty"` @@ -210,6 +211,11 @@ type ForbidigoPattern struct { Msg *string `yaml:"msg,omitempty,omitempty" toml:"msg,omitempty,multiline,omitempty"` } +type FuncOrderSettings struct { + Constructor *bool `yaml:"constructor,omitempty,omitempty" toml:"constructor,omitempty,multiline,omitempty"` + StructMethod *bool `yaml:"struct-method,omitempty,omitempty" toml:"struct-method,omitempty,multiline,omitempty"` +} + type FunlenSettings struct { Lines *int `yaml:"lines,omitempty" toml:"lines,multiline,omitempty"` Statements *int `yaml:"statements,omitempty" toml:"statements,multiline,omitempty"` @@ -241,14 +247,18 @@ type GocognitSettings struct { } type GoConstSettings struct { - IgnoreStrings *string `yaml:"ignore-strings,omitempty" toml:"ignore-strings,multiline,omitempty"` - MatchWithConstants *bool `yaml:"match-constant,omitempty" toml:"match-constant,multiline,omitempty"` - MinStringLen *int `yaml:"min-len,omitempty" toml:"min-len,multiline,omitempty"` - MinOccurrencesCount *int `yaml:"min-occurrences,omitempty" toml:"min-occurrences,multiline,omitempty"` - ParseNumbers *bool `yaml:"numbers,omitempty" toml:"numbers,multiline,omitempty"` - NumberMin *int `yaml:"min,omitempty" toml:"min,multiline,omitempty"` - NumberMax *int `yaml:"max,omitempty" toml:"max,multiline,omitempty"` - IgnoreCalls *bool `yaml:"ignore-calls,omitempty" toml:"ignore-calls,multiline,omitempty"` + IgnoreStringValues []string `yaml:"ignore-string-values,omitempty" toml:"ignore-string-values,multiline,omitempty"` + MatchWithConstants *bool `yaml:"match-constant,omitempty" toml:"match-constant,multiline,omitempty"` + MinStringLen *int `yaml:"min-len,omitempty" toml:"min-len,multiline,omitempty"` + MinOccurrencesCount *int `yaml:"min-occurrences,omitempty" toml:"min-occurrences,multiline,omitempty"` + ParseNumbers *bool `yaml:"numbers,omitempty" toml:"numbers,multiline,omitempty"` + NumberMin *int `yaml:"min,omitempty" toml:"min,multiline,omitempty"` + NumberMax *int `yaml:"max,omitempty" toml:"max,multiline,omitempty"` + IgnoreCalls *bool `yaml:"ignore-calls,omitempty" toml:"ignore-calls,multiline,omitempty"` + FindDuplicates *bool `yaml:"find-duplicates,omitempty" toml:"find-duplicates,multiline,omitempty"` + EvalConstExpressions *bool `yaml:"eval-const-expressions,omitempty" toml:"eval-const-expressions,multiline,omitempty"` + + IgnoreStrings *string `yaml:"ignore-strings,omitempty" toml:"ignore-strings,multiline,omitempty"` } type GoCriticSettings struct { @@ -436,7 +446,7 @@ type MustTagFunction struct { } type NakedretSettings struct { - MaxFuncLines uint `yaml:"max-func-lines,omitempty" toml:"max-func-lines,multiline,omitempty"` + MaxFuncLines *uint `yaml:"max-func-lines,omitempty" toml:"max-func-lines,multiline,omitempty"` } type NestifSettings struct { @@ -444,6 +454,7 @@ type NestifSettings struct { } type NilNilSettings struct { + OnlyTwo *bool `yaml:"only-two,omitempty" toml:"only-two,multiline,omitempty"` DetectOpposite *bool `yaml:"detect-opposite,omitempty" toml:"detect-opposite,multiline,omitempty"` CheckedTypes []string `yaml:"checked-types,omitempty" toml:"checked-types,multiline,omitempty"` } @@ -560,6 +571,7 @@ type SlogLintSettings struct { NoGlobal *string `yaml:"no-global,omitempty" toml:"no-global,multiline,omitempty"` Context *string `yaml:"context,omitempty" toml:"context,multiline,omitempty"` StaticMsg *bool `yaml:"static-msg,omitempty" toml:"static-msg,multiline,omitempty"` + MsgStyle *string `yaml:"msg-style,omitempty" toml:"msg-style,multiline,omitempty"` NoRawKeys *bool `yaml:"no-raw-keys,omitempty" toml:"no-raw-keys,multiline,omitempty"` KeyNamingCase *string `yaml:"key-naming-case,omitempty" toml:"key-naming-case,multiline,omitempty"` ForbiddenKeys []string `yaml:"forbidden-keys,omitempty" toml:"forbidden-keys,multiline,omitempty"` @@ -639,6 +651,7 @@ type TestifylintExpectedActual struct { type TestifylintFormatter struct { CheckFormatString *bool `yaml:"check-format-string,omitempty" toml:"check-format-string,multiline,omitempty"` RequireFFuncs *bool `yaml:"require-f-funcs,omitempty" toml:"require-f-funcs,multiline,omitempty"` + RequireStringMsg *bool `yaml:"require-string-msg,omitempty" toml:"require-string-msg,multiline,omitempty"` } type TestifylintGoRequire struct { @@ -736,6 +749,7 @@ type WrapcheckSettings struct { IgnoreSigRegexps []string `yaml:"ignore-sig-regexps,omitempty" toml:"ignore-sig-regexps,multiline,omitempty"` IgnorePackageGlobs []string `yaml:"ignore-package-globs,omitempty" toml:"ignore-package-globs,multiline,omitempty"` IgnoreInterfaceRegexps []string `yaml:"ignore-interface-regexps,omitempty" toml:"ignore-interface-regexps,multiline,omitempty"` + ReportInternalErrors *bool `yaml:"report-internal-errors,omitempty" toml:"report-internal-errors,multiline,omitempty"` } type WSLSettings struct { diff --git a/pkg/commands/internal/migrate/versiontwo/output.go b/pkg/commands/internal/migrate/versiontwo/output.go index ed6bab7e375d..16afb6701eef 100644 --- a/pkg/commands/internal/migrate/versiontwo/output.go +++ b/pkg/commands/internal/migrate/versiontwo/output.go @@ -5,6 +5,7 @@ package versiontwo type Output struct { Formats Formats `yaml:"formats,omitempty" toml:"formats,multiline,omitempty"` SortOrder []string `yaml:"sort-order,omitempty" toml:"sort-order,multiline,omitempty"` - PathPrefix *string `yaml:"path-prefix,omitempty" toml:"path-prefix,multiline,omitempty"` ShowStats *bool `yaml:"show-stats,omitempty" toml:"show-stats,multiline,omitempty"` + PathPrefix *string `yaml:"path-prefix,omitempty" toml:"path-prefix,multiline,omitempty"` + PathMode *string `yaml:"path-mode,omitempty" toml:"path-mode,multiline,omitempty"` } diff --git a/pkg/commands/linters.go b/pkg/commands/linters.go index 3578bc4fbbdd..40036bb8567f 100644 --- a/pkg/commands/linters.go +++ b/pkg/commands/linters.go @@ -69,7 +69,7 @@ func newLintersCommand(logger logutils.Log) *lintersCommand { } func (c *lintersCommand) preRunE(cmd *cobra.Command, args []string) error { - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + loader := config.NewLintersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) err := loader.Load(config.LoadOptions{Validation: true}) if err != nil { diff --git a/pkg/commands/migrate.go b/pkg/commands/migrate.go index 7c73209ed180..78e7842bed04 100644 --- a/pkg/commands/migrate.go +++ b/pkg/commands/migrate.go @@ -81,10 +81,6 @@ func newMigrateCommand(log logutils.Log, info BuildInfo) *migrateCommand { } func (c *migrateCommand) execute(_ *cobra.Command, _ []string) error { - if c.cfg.Version != "" { - return fmt.Errorf("configuration version is already set: %s", c.cfg.Version) - } - srcPath := c.viper.ConfigFileUsed() if srcPath == "" { c.log.Warnf("No config file detected") @@ -141,6 +137,10 @@ func (c *migrateCommand) preRunE(cmd *cobra.Command, _ []string) error { return fmt.Errorf("unsupported format: %s", c.opts.format) } + if c.cfg.Version != "" { + return fmt.Errorf("configuration version is already set: %s", c.cfg.Version) + } + if c.opts.skipValidation { return nil } diff --git a/pkg/commands/root.go b/pkg/commands/root.go index e3dcc527b118..3a160bea410f 100644 --- a/pkg/commands/root.go +++ b/pkg/commands/root.go @@ -115,6 +115,9 @@ func setupLogger(logger logutils.Log) error { logger.Fatalf("invalid value %q for --color; must be 'always', 'auto', or 'never'", opts.Color) } + // For log level colors (mainly for verbose output) + logutils.DisableColors(color.NoColor) + return nil } diff --git a/pkg/commands/run.go b/pkg/commands/run.go index 7faa00161fdb..1864559f9fc3 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -21,10 +21,12 @@ import ( "github.com/fatih/color" "github.com/gofrs/flock" + "github.com/ldez/grignotin/goenv" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" "go.uber.org/automaxprocs/maxprocs" + "golang.org/x/mod/sumdb/dirhash" "gopkg.in/yaml.v3" "github.com/golangci/golangci-lint/v2/internal/cache" @@ -151,7 +153,7 @@ func (c *runCommand) persistentPreRunE(cmd *cobra.Command, args []string) error c.log.Infof("%s", c.buildInfo.String()) - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + loader := config.NewLintersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) err := loader.Load(config.LoadOptions{CheckDeprecation: true, Validation: true}) if err != nil { @@ -216,7 +218,7 @@ func (c *runCommand) preRunE(_ *cobra.Command, args []string) error { c.contextBuilder = lint.NewContextBuilder(c.cfg, pkgLoader, pkgCache, guard) - if err = initHashSalt(c.buildInfo.Version, c.cfg); err != nil { + if err = initHashSalt(c.log.Child(logutils.DebugKeyGoModSalt), c.buildInfo.Version, c.cfg); err != nil { return fmt.Errorf("failed to init hash salt: %w", err) } @@ -374,7 +376,7 @@ func (c *runCommand) runAndPrint(ctx context.Context) error { } // runAnalysis executes the linters that have been enabled in the configuration. -func (c *runCommand) runAnalysis(ctx context.Context) ([]result.Issue, error) { +func (c *runCommand) runAnalysis(ctx context.Context) ([]*result.Issue, error) { lintersToRun, err := c.dbManager.GetOptimizedLinters() if err != nil { return nil, err @@ -406,7 +408,7 @@ func (c *runCommand) setOutputToDevNull() (savedStdout, savedStderr *os.File) { return } -func (c *runCommand) setExitCodeIfIssuesFound(issues []result.Issue) { +func (c *runCommand) setExitCodeIfIssuesFound(issues []*result.Issue) { if len(issues) != 0 { c.exitCode = c.cfg.Run.ExitCodeIfIssuesFound } @@ -431,7 +433,7 @@ func (c *runCommand) printDeprecatedLinterMessages(enabledLinters map[string]*li } } -func (c *runCommand) printStats(issues []result.Issue) { +func (c *runCommand) printStats(issues []*result.Issue) { if !c.cfg.Output.ShowStats { return } @@ -582,6 +584,7 @@ func setupConfigFileFlagSet(fs *pflag.FlagSet, cfg *config.LoaderOptions) { func setupRunPersistentFlags(fs *pflag.FlagSet, opts *runOptions) { fs.BoolVar(&opts.PrintResourcesUsage, "print-resources-usage", false, color.GreenString("Print avg and max memory usage of golangci-lint and total time")) + _ = fs.MarkDeprecated("print-resources-usage", "use --verbose instead") fs.StringVar(&opts.CPUProfilePath, "cpu-profile-path", "", color.GreenString("Path to CPU profile output file")) fs.StringVar(&opts.MemProfilePath, "mem-profile-path", "", color.GreenString("Path to memory profile output file")) @@ -618,7 +621,7 @@ func formatMemory(memBytes uint64) string { // Related to cache. -func initHashSalt(version string, cfg *config.Config) error { +func initHashSalt(logger logutils.Log, version string, cfg *config.Config) error { binSalt, err := computeBinarySalt(version) if err != nil { return fmt.Errorf("failed to calculate binary salt: %w", err) @@ -629,9 +632,18 @@ func initHashSalt(version string, cfg *config.Config) error { return fmt.Errorf("failed to calculate config salt: %w", err) } + goModSalt, err := computeGoModSalt() + if err != nil { + // NOTE: missing go.mod must be ignored. + logger.Warnf("Failed to calculate go.mod salt: %v", err) + } + b := bytes.NewBuffer(binSalt) b.Write(configSalt) + b.WriteString(goModSalt) + cache.SetSalt(b) + return nil } @@ -648,15 +660,19 @@ func computeBinarySalt(version string) ([]byte, error) { if err != nil { return nil, err } + f, err := os.Open(p) if err != nil { return nil, err } + defer f.Close() + h := sha256.New() if _, err := io.Copy(h, f); err != nil { return nil, err } + return h.Sum(nil), nil } @@ -678,5 +694,29 @@ func computeConfigSalt(cfg *config.Config) ([]byte, error) { if _, err := h.Write(configData.Bytes()); err != nil { return nil, err } + return h.Sum(nil), nil } + +func computeGoModSalt() (string, error) { + values, err := goenv.Get(context.Background(), goenv.GOMOD) + if err != nil { + return "", fmt.Errorf("failed to get goenv: %w", err) + } + + goModPath := filepath.Clean(values[goenv.GOMOD]) + + data, err := os.ReadFile(goModPath) + if err != nil { + return "", fmt.Errorf("failed to read go.mod: %w", err) + } + + sum, err := dirhash.Hash1([]string{goModPath}, func(string) (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader(data)), nil + }) + if err != nil { + return "", fmt.Errorf("failed to compute go.sum: %w", err) + } + + return sum, nil +} diff --git a/pkg/config/config.go b/pkg/config/config.go index a6236a23f3af..6d7586621d8b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -13,6 +13,8 @@ import ( "github.com/ldez/grignotin/goenv" "github.com/ldez/grignotin/gomod" "golang.org/x/mod/modfile" + + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) // defaultGoVersion the value should be "oldstable" - 1. @@ -102,8 +104,8 @@ func IsGoGreaterThanOrEqual(current, limit string) bool { return v1.GreaterThanOrEqual(l) } -func detectGoVersion(ctx context.Context) string { - return cmp.Or(detectGoVersionFromGoMod(ctx), defaultGoVersion) +func detectGoVersion(ctx context.Context, log logutils.Log) string { + return cmp.Or(detectGoVersionFromGoMod(ctx, log), defaultGoVersion) } // detectGoVersionFromGoMod tries to get Go version from go.mod. @@ -111,7 +113,7 @@ func detectGoVersion(ctx context.Context) string { // else it returns `go` version if present, // else it returns `GOVERSION` version if present, // else it returns empty. -func detectGoVersionFromGoMod(ctx context.Context) string { +func detectGoVersionFromGoMod(ctx context.Context, log logutils.Log) string { values, err := goenv.Get(ctx, goenv.GOMOD, goenv.GOVERSION) if err != nil { values = map[string]string{ @@ -128,6 +130,10 @@ func detectGoVersionFromGoMod(ctx context.Context) string { return parseGoVersion(values[goenv.GOVERSION]) } + if file.Module != nil { + log.Infof("Module name %q", file.Module.Mod.Path) + } + // The toolchain exists only if 'toolchain' version > 'go' version. // If 'toolchain' version <= 'go' version, `go mod tidy` will remove 'toolchain' version from go.mod. if file.Toolchain != nil && file.Toolchain.Name != "" { diff --git a/pkg/config/formatters.go b/pkg/config/formatters.go index 1bb623bc4ba8..e1723ac101fd 100644 --- a/pkg/config/formatters.go +++ b/pkg/config/formatters.go @@ -14,7 +14,7 @@ type Formatters struct { func (f *Formatters) Validate() error { for _, n := range f.Enable { if !slices.Contains(getAllFormatterNames(), n) { - return fmt.Errorf("%s is a formatter", n) + return fmt.Errorf("%s is not a formatter", n) } } @@ -22,6 +22,7 @@ func (f *Formatters) Validate() error { } type FormatterExclusions struct { - Generated string `mapstructure:"generated"` - Paths []string `mapstructure:"paths"` + Generated string `mapstructure:"generated"` + Paths []string `mapstructure:"paths"` + WarnUnused bool `mapstructure:"warn-unused"` } diff --git a/pkg/config/linters.go b/pkg/config/linters.go index 590d9448a197..2669f2e64778 100644 --- a/pkg/config/linters.go +++ b/pkg/config/linters.go @@ -49,5 +49,5 @@ func (l *Linters) validateNoFormatters() error { } func getAllFormatterNames() []string { - return []string{"gci", "gofmt", "gofumpt", "goimports", "golines"} + return []string{"gci", "gofmt", "gofumpt", "goimports", "golines", "swaggo"} } diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index 86ee4fea48d2..e2838d808acb 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -41,6 +41,10 @@ var defaultLintersSettings = LintersSettings{ Forbidigo: ForbidigoSettings{ ExcludeGodocExamples: true, }, + FuncOrder: FuncOrderSettings{ + Constructor: true, + StructMethod: true, + }, Funlen: FunlenSettings{ IgnoreComments: true, }, @@ -201,83 +205,85 @@ var defaultLintersSettings = LintersSettings{ type LintersSettings struct { FormatterSettings `mapstructure:"-"` - Asasalint AsasalintSettings `mapstructure:"asasalint"` - BiDiChk BiDiChkSettings `mapstructure:"bidichk"` - CopyLoopVar CopyLoopVarSettings `mapstructure:"copyloopvar"` - Cyclop CyclopSettings `mapstructure:"cyclop"` - Decorder DecorderSettings `mapstructure:"decorder"` - Depguard DepGuardSettings `mapstructure:"depguard"` - Dogsled DogsledSettings `mapstructure:"dogsled"` - Dupl DuplSettings `mapstructure:"dupl"` - DupWord DupWordSettings `mapstructure:"dupword"` - Errcheck ErrcheckSettings `mapstructure:"errcheck"` - ErrChkJSON ErrChkJSONSettings `mapstructure:"errchkjson"` - ErrorLint ErrorLintSettings `mapstructure:"errorlint"` - Exhaustive ExhaustiveSettings `mapstructure:"exhaustive"` - Exhaustruct ExhaustructSettings `mapstructure:"exhaustruct"` - Fatcontext FatcontextSettings `mapstructure:"fatcontext"` - Forbidigo ForbidigoSettings `mapstructure:"forbidigo"` - Funlen FunlenSettings `mapstructure:"funlen"` - GinkgoLinter GinkgoLinterSettings `mapstructure:"ginkgolinter"` - Gocognit GocognitSettings `mapstructure:"gocognit"` - GoChecksumType GoChecksumTypeSettings `mapstructure:"gochecksumtype"` - Goconst GoConstSettings `mapstructure:"goconst"` - Gocritic GoCriticSettings `mapstructure:"gocritic"` - Gocyclo GoCycloSettings `mapstructure:"gocyclo"` - Godot GodotSettings `mapstructure:"godot"` - Godox GodoxSettings `mapstructure:"godox"` - Goheader GoHeaderSettings `mapstructure:"goheader"` - GoModDirectives GoModDirectivesSettings `mapstructure:"gomoddirectives"` - Gomodguard GoModGuardSettings `mapstructure:"gomodguard"` - Gosec GoSecSettings `mapstructure:"gosec"` - Gosmopolitan GosmopolitanSettings `mapstructure:"gosmopolitan"` - Govet GovetSettings `mapstructure:"govet"` - Grouper GrouperSettings `mapstructure:"grouper"` - Iface IfaceSettings `mapstructure:"iface"` - ImportAs ImportAsSettings `mapstructure:"importas"` - Inamedparam INamedParamSettings `mapstructure:"inamedparam"` - InterfaceBloat InterfaceBloatSettings `mapstructure:"interfacebloat"` - Ireturn IreturnSettings `mapstructure:"ireturn"` - Lll LllSettings `mapstructure:"lll"` - LoggerCheck LoggerCheckSettings `mapstructure:"loggercheck"` - MaintIdx MaintIdxSettings `mapstructure:"maintidx"` - Makezero MakezeroSettings `mapstructure:"makezero"` - Misspell MisspellSettings `mapstructure:"misspell"` - Mnd MndSettings `mapstructure:"mnd"` - MustTag MustTagSettings `mapstructure:"musttag"` - Nakedret NakedretSettings `mapstructure:"nakedret"` - Nestif NestifSettings `mapstructure:"nestif"` - NilNil NilNilSettings `mapstructure:"nilnil"` - Nlreturn NlreturnSettings `mapstructure:"nlreturn"` - NoLintLint NoLintLintSettings `mapstructure:"nolintlint"` - NoNamedReturns NoNamedReturnsSettings `mapstructure:"nonamedreturns"` - ParallelTest ParallelTestSettings `mapstructure:"paralleltest"` - PerfSprint PerfSprintSettings `mapstructure:"perfsprint"` - Prealloc PreallocSettings `mapstructure:"prealloc"` - Predeclared PredeclaredSettings `mapstructure:"predeclared"` - Promlinter PromlinterSettings `mapstructure:"promlinter"` - ProtoGetter ProtoGetterSettings `mapstructure:"protogetter"` - Reassign ReassignSettings `mapstructure:"reassign"` - Recvcheck RecvcheckSettings `mapstructure:"recvcheck"` - Revive ReviveSettings `mapstructure:"revive"` - RowsErrCheck RowsErrCheckSettings `mapstructure:"rowserrcheck"` - SlogLint SlogLintSettings `mapstructure:"sloglint"` - Spancheck SpancheckSettings `mapstructure:"spancheck"` - Staticcheck StaticCheckSettings `mapstructure:"staticcheck"` - TagAlign TagAlignSettings `mapstructure:"tagalign"` - Tagliatelle TagliatelleSettings `mapstructure:"tagliatelle"` - Testifylint TestifylintSettings `mapstructure:"testifylint"` - Testpackage TestpackageSettings `mapstructure:"testpackage"` - Thelper ThelperSettings `mapstructure:"thelper"` - Unconvert UnconvertSettings `mapstructure:"unconvert"` - Unparam UnparamSettings `mapstructure:"unparam"` - Unused UnusedSettings `mapstructure:"unused"` - UseStdlibVars UseStdlibVarsSettings `mapstructure:"usestdlibvars"` - UseTesting UseTestingSettings `mapstructure:"usetesting"` - Varnamelen VarnamelenSettings `mapstructure:"varnamelen"` - Whitespace WhitespaceSettings `mapstructure:"whitespace"` - Wrapcheck WrapcheckSettings `mapstructure:"wrapcheck"` - WSL WSLSettings `mapstructure:"wsl"` + Asasalint AsasalintSettings `mapstructure:"asasalint"` + BiDiChk BiDiChkSettings `mapstructure:"bidichk"` + CopyLoopVar CopyLoopVarSettings `mapstructure:"copyloopvar"` + Cyclop CyclopSettings `mapstructure:"cyclop"` + Decorder DecorderSettings `mapstructure:"decorder"` + Depguard DepGuardSettings `mapstructure:"depguard"` + Dogsled DogsledSettings `mapstructure:"dogsled"` + Dupl DuplSettings `mapstructure:"dupl"` + DupWord DupWordSettings `mapstructure:"dupword"` + EmbeddedStructFieldCheck EmbeddedStructFieldCheckSettings `mapstructure:"embeddedstructfieldcheck"` + Errcheck ErrcheckSettings `mapstructure:"errcheck"` + ErrChkJSON ErrChkJSONSettings `mapstructure:"errchkjson"` + ErrorLint ErrorLintSettings `mapstructure:"errorlint"` + Exhaustive ExhaustiveSettings `mapstructure:"exhaustive"` + Exhaustruct ExhaustructSettings `mapstructure:"exhaustruct"` + Fatcontext FatcontextSettings `mapstructure:"fatcontext"` + Forbidigo ForbidigoSettings `mapstructure:"forbidigo"` + FuncOrder FuncOrderSettings `mapstructure:"funcorder"` + Funlen FunlenSettings `mapstructure:"funlen"` + GinkgoLinter GinkgoLinterSettings `mapstructure:"ginkgolinter"` + Gocognit GocognitSettings `mapstructure:"gocognit"` + GoChecksumType GoChecksumTypeSettings `mapstructure:"gochecksumtype"` + Goconst GoConstSettings `mapstructure:"goconst"` + Gocritic GoCriticSettings `mapstructure:"gocritic"` + Gocyclo GoCycloSettings `mapstructure:"gocyclo"` + Godot GodotSettings `mapstructure:"godot"` + Godox GodoxSettings `mapstructure:"godox"` + Goheader GoHeaderSettings `mapstructure:"goheader"` + GoModDirectives GoModDirectivesSettings `mapstructure:"gomoddirectives"` + Gomodguard GoModGuardSettings `mapstructure:"gomodguard"` + Gosec GoSecSettings `mapstructure:"gosec"` + Gosmopolitan GosmopolitanSettings `mapstructure:"gosmopolitan"` + Govet GovetSettings `mapstructure:"govet"` + Grouper GrouperSettings `mapstructure:"grouper"` + Iface IfaceSettings `mapstructure:"iface"` + ImportAs ImportAsSettings `mapstructure:"importas"` + Inamedparam INamedParamSettings `mapstructure:"inamedparam"` + InterfaceBloat InterfaceBloatSettings `mapstructure:"interfacebloat"` + Ireturn IreturnSettings `mapstructure:"ireturn"` + Lll LllSettings `mapstructure:"lll"` + LoggerCheck LoggerCheckSettings `mapstructure:"loggercheck"` + MaintIdx MaintIdxSettings `mapstructure:"maintidx"` + Makezero MakezeroSettings `mapstructure:"makezero"` + Misspell MisspellSettings `mapstructure:"misspell"` + Mnd MndSettings `mapstructure:"mnd"` + MustTag MustTagSettings `mapstructure:"musttag"` + Nakedret NakedretSettings `mapstructure:"nakedret"` + Nestif NestifSettings `mapstructure:"nestif"` + NilNil NilNilSettings `mapstructure:"nilnil"` + Nlreturn NlreturnSettings `mapstructure:"nlreturn"` + NoLintLint NoLintLintSettings `mapstructure:"nolintlint"` + NoNamedReturns NoNamedReturnsSettings `mapstructure:"nonamedreturns"` + ParallelTest ParallelTestSettings `mapstructure:"paralleltest"` + PerfSprint PerfSprintSettings `mapstructure:"perfsprint"` + Prealloc PreallocSettings `mapstructure:"prealloc"` + Predeclared PredeclaredSettings `mapstructure:"predeclared"` + Promlinter PromlinterSettings `mapstructure:"promlinter"` + ProtoGetter ProtoGetterSettings `mapstructure:"protogetter"` + Reassign ReassignSettings `mapstructure:"reassign"` + Recvcheck RecvcheckSettings `mapstructure:"recvcheck"` + Revive ReviveSettings `mapstructure:"revive"` + RowsErrCheck RowsErrCheckSettings `mapstructure:"rowserrcheck"` + SlogLint SlogLintSettings `mapstructure:"sloglint"` + Spancheck SpancheckSettings `mapstructure:"spancheck"` + Staticcheck StaticCheckSettings `mapstructure:"staticcheck"` + TagAlign TagAlignSettings `mapstructure:"tagalign"` + Tagliatelle TagliatelleSettings `mapstructure:"tagliatelle"` + Testifylint TestifylintSettings `mapstructure:"testifylint"` + Testpackage TestpackageSettings `mapstructure:"testpackage"` + Thelper ThelperSettings `mapstructure:"thelper"` + Unconvert UnconvertSettings `mapstructure:"unconvert"` + Unparam UnparamSettings `mapstructure:"unparam"` + Unused UnusedSettings `mapstructure:"unused"` + UseStdlibVars UseStdlibVarsSettings `mapstructure:"usestdlibvars"` + UseTesting UseTestingSettings `mapstructure:"usetesting"` + Varnamelen VarnamelenSettings `mapstructure:"varnamelen"` + Whitespace WhitespaceSettings `mapstructure:"whitespace"` + Wrapcheck WrapcheckSettings `mapstructure:"wrapcheck"` + WSL WSLSettings `mapstructure:"wsl"` Custom map[string]CustomLinterSettings `mapstructure:"custom"` } @@ -362,11 +368,16 @@ type DupWordSettings struct { Ignore []string `mapstructure:"ignore"` } +type EmbeddedStructFieldCheckSettings struct { + ForbidMutex bool `mapstructure:"forbid-mutex"` +} + type ErrcheckSettings struct { DisableDefaultExclusions bool `mapstructure:"disable-default-exclusions"` CheckTypeAssertions bool `mapstructure:"check-type-assertions"` CheckAssignToBlank bool `mapstructure:"check-blank"` ExcludeFunctions []string `mapstructure:"exclude-functions"` + Verbose bool `mapstructure:"verbose"` } type ErrChkJSONSettings struct { @@ -420,6 +431,12 @@ type ForbidigoPattern struct { Msg string `yaml:"msg,omitempty" mapstructure:"msg,omitempty"` } +type FuncOrderSettings struct { + Constructor bool `mapstructure:"constructor,omitempty"` + StructMethod bool `mapstructure:"struct-method,omitempty"` + Alphabetical bool `mapstructure:"alphabetical,omitempty"` +} + type FunlenSettings struct { Lines int `mapstructure:"lines"` Statements int `mapstructure:"statements"` @@ -451,14 +468,19 @@ type GocognitSettings struct { } type GoConstSettings struct { - IgnoreStrings string `mapstructure:"ignore-strings"` - MatchWithConstants bool `mapstructure:"match-constant"` - MinStringLen int `mapstructure:"min-len"` - MinOccurrencesCount int `mapstructure:"min-occurrences"` - ParseNumbers bool `mapstructure:"numbers"` - NumberMin int `mapstructure:"min"` - NumberMax int `mapstructure:"max"` - IgnoreCalls bool `mapstructure:"ignore-calls"` + IgnoreStringValues []string `mapstructure:"ignore-string-values"` + MatchWithConstants bool `mapstructure:"match-constant"` + MinStringLen int `mapstructure:"min-len"` + MinOccurrencesCount int `mapstructure:"min-occurrences"` + ParseNumbers bool `mapstructure:"numbers"` + NumberMin int `mapstructure:"min"` + NumberMax int `mapstructure:"max"` + IgnoreCalls bool `mapstructure:"ignore-calls"` + FindDuplicates bool `mapstructure:"find-duplicates"` + EvalConstExpressions bool `mapstructure:"eval-const-expressions"` + + // Deprecated: use IgnoreStringValues instead. + IgnoreStrings string `mapstructure:"ignore-strings"` } type GoCriticSettings struct { @@ -784,6 +806,7 @@ type SlogLintSettings struct { NoGlobal string `mapstructure:"no-global"` Context string `mapstructure:"context"` StaticMsg bool `mapstructure:"static-msg"` + MsgStyle string `mapstructure:"msg-style"` NoRawKeys bool `mapstructure:"no-raw-keys"` KeyNamingCase string `mapstructure:"key-naming-case"` ForbiddenKeys []string `mapstructure:"forbidden-keys"` @@ -911,6 +934,7 @@ type UseStdlibVarsSettings struct { SQLIsolationLevel bool `mapstructure:"sql-isolation-level"` TLSSignatureScheme bool `mapstructure:"tls-signature-scheme"` ConstantKind bool `mapstructure:"constant-kind"` + TimeDateMonth bool `mapstructure:"time-date-month"` } type UseTestingSettings struct { @@ -965,6 +989,7 @@ type WrapcheckSettings struct { IgnoreSigRegexps []string `mapstructure:"ignore-sig-regexps"` IgnorePackageGlobs []string `mapstructure:"ignore-package-globs"` IgnoreInterfaceRegexps []string `mapstructure:"ignore-interface-regexps"` + ReportInternalErrors bool `mapstructure:"report-internal-errors"` } type WSLSettings struct { diff --git a/pkg/config/loader.go b/pkg/config/loader.go index e153c6adc169..3ff9306486ab 100644 --- a/pkg/config/loader.go +++ b/pkg/config/loader.go @@ -17,6 +17,11 @@ import ( var errConfigDisabled = errors.New("config is disabled by --no-config") +const ( + modeLinters = "linters" + modeFormatters = "formatters" +) + type LoaderOptions struct { Config string // Flag only. The path to the golangci config file, as specified with the --config argument. NoConfig bool // Flag only. @@ -33,9 +38,25 @@ type Loader struct { fs *pflag.FlagSet cfg *Config + + mode string +} + +func NewLintersLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { + loader := newLoader(log, v, fs, opts, cfg, args) + loader.mode = modeLinters + + return loader } -func NewLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { +func NewFormattersLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { + loader := newLoader(log, v, fs, opts, cfg, args) + loader.mode = modeFormatters + + return loader +} + +func newLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { return &Loader{ BaseLoader: NewBaseLoader(log, v, opts, cfg, args), fs: fs, @@ -44,18 +65,15 @@ func NewLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderO } func (l *Loader) Load(opts LoadOptions) error { - err := l.setConfigFile() + err := l.BaseLoader.Load() if err != nil { return err } - err = l.parseConfig() - if err != nil { - return err + if l.mode == modeLinters { + l.applyStringSliceHack() } - l.applyStringSliceHack() - if l.cfg.Linters.Exclusions.Generated == "" { l.cfg.Linters.Exclusions.Generated = GeneratedModeStrict } @@ -143,7 +161,7 @@ func (l *Loader) checkConfigurationVersion() error { func (l *Loader) handleGoVersion() { if l.cfg.Run.Go == "" { - l.cfg.Run.Go = detectGoVersion(context.Background()) + l.cfg.Run.Go = detectGoVersion(context.Background(), l.log) } l.cfg.Linters.Settings.Govet.Go = l.cfg.Run.Go @@ -172,8 +190,15 @@ func (l *Loader) handleDeprecation() error { return nil } -func (*Loader) handleLinterOptionDeprecations() { - // The function is empty but deprecations will happen in the future. +func (l *Loader) handleLinterOptionDeprecations() { + // Deprecated since v2.1.0. + if l.cfg.Linters.Settings.Goconst.IgnoreStrings != "" { + l.log.Warnf("The configuration option `linters.settings.goconst.ignore-strings` is deprecated, " + + "please use `linters.settings.goconst.ignore-string-values`.") + + l.cfg.Linters.Settings.Goconst.IgnoreStringValues = append(l.cfg.Linters.Settings.Goconst.IgnoreStringValues, + l.cfg.Linters.Settings.Goconst.IgnoreStrings) + } } func (l *Loader) handleEnableOnlyOption() error { diff --git a/pkg/config/output.go b/pkg/config/output.go index 43dce3900ccc..803dc3ac2941 100644 --- a/pkg/config/output.go +++ b/pkg/config/output.go @@ -4,16 +4,34 @@ import ( "fmt" "slices" "strings" + + "github.com/golangci/golangci-lint/v2/pkg/fsutils" ) type Output struct { Formats Formats `mapstructure:"formats"` SortOrder []string `mapstructure:"sort-order"` - PathPrefix string `mapstructure:"path-prefix"` ShowStats bool `mapstructure:"show-stats"` + PathPrefix string `mapstructure:"path-prefix"` + PathMode string `mapstructure:"path-mode"` } func (o *Output) Validate() error { + validators := []func() error{ + o.validateSortOrder, + o.validatePathMode, + } + + for _, v := range validators { + if err := v(); err != nil { + return err + } + } + + return nil +} + +func (o *Output) validateSortOrder() error { validOrders := []string{"linter", "file", "severity"} all := strings.Join(o.SortOrder, " ") @@ -30,3 +48,15 @@ func (o *Output) Validate() error { return nil } + +func (o *Output) validatePathMode() error { + switch o.PathMode { + case "", fsutils.OutputPathModeAbsolute: + // Valid + + default: + return fmt.Errorf("unsupported output path mode %q", o.PathMode) + } + + return nil +} diff --git a/pkg/config/output_test.go b/pkg/config/output_test.go index 1e19323d15a0..2b498648113a 100644 --- a/pkg/config/output_test.go +++ b/pkg/config/output_test.go @@ -4,6 +4,8 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/golangci/golangci-lint/v2/pkg/fsutils" ) func TestOutput_Validate(t *testing.T) { @@ -12,29 +14,41 @@ func TestOutput_Validate(t *testing.T) { settings *Output }{ { - desc: "file", + desc: "SortOrder: file", settings: &Output{ SortOrder: []string{"file"}, }, }, { - desc: "linter", + desc: "SortOrder: linter", settings: &Output{ SortOrder: []string{"linter"}, }, }, { - desc: "severity", + desc: "SortOrder: severity", settings: &Output{ SortOrder: []string{"severity"}, }, }, { - desc: "multiple", + desc: "SortOrder: multiple", settings: &Output{ SortOrder: []string{"file", "linter", "severity"}, }, }, + { + desc: "PathMode: empty", + settings: &Output{ + PathMode: "", + }, + }, + { + desc: "PathMode: absolute", + settings: &Output{ + PathMode: fsutils.OutputPathModeAbsolute, + }, + }, } for _, test := range testCases { @@ -54,19 +68,26 @@ func TestOutput_Validate_error(t *testing.T) { expected string }{ { - desc: "invalid sort-order", + desc: "SortOrder: invalid", settings: &Output{ SortOrder: []string{"a"}, }, expected: `unsupported sort-order name "a"`, }, { - desc: "duplicate", + desc: "SortOrder: duplicate", settings: &Output{ SortOrder: []string{"file", "linter", "severity", "linter"}, }, expected: `the sort-order name "linter" is repeated several times`, }, + { + desc: "PathMode: invalid", + settings: &Output{ + PathMode: "example", + }, + expected: `unsupported output path mode "example"`, + }, } for _, test := range testCases { diff --git a/pkg/config/placeholders.go b/pkg/config/placeholders.go new file mode 100644 index 000000000000..b3f35f7b3ac4 --- /dev/null +++ b/pkg/config/placeholders.go @@ -0,0 +1,18 @@ +package config + +import "strings" + +const ( + // placeholderBasePath used inside linters to evaluate relative paths. + placeholderBasePath = "${base-path}" + + // placeholderConfigPath used inside linters to paths relative to configuration. + placeholderConfigPath = "${config-path}" +) + +func NewPlaceholderReplacer(cfg *Config) *strings.Replacer { + return strings.NewReplacer( + placeholderBasePath, cfg.GetBasePath(), + placeholderConfigPath, cfg.GetConfigDir(), + ) +} diff --git a/pkg/fsutils/basepath.go b/pkg/fsutils/basepath.go index f0f4bc762d2a..3761fa0eaa71 100644 --- a/pkg/fsutils/basepath.go +++ b/pkg/fsutils/basepath.go @@ -19,6 +19,9 @@ const ( RelativePathModeWd = "wd" ) +// OutputPathModeAbsolute path mode used to show absolute paths in output reports (user-facing). +const OutputPathModeAbsolute = "abs" + func AllRelativePathModes() []string { return []string{RelativePathModeGoMod, RelativePathModeGitRoot, RelativePathModeCfg, RelativePathModeWd} } diff --git a/pkg/goanalysis/issue.go b/pkg/goanalysis/issue.go index c41702595c55..88a59e53dbc9 100644 --- a/pkg/goanalysis/issue.go +++ b/pkg/goanalysis/issue.go @@ -9,13 +9,13 @@ import ( ) type Issue struct { - result.Issue + *result.Issue Pass *analysis.Pass } -func NewIssue(issue *result.Issue, pass *analysis.Pass) Issue { - return Issue{ - Issue: *issue, +func NewIssue(issue *result.Issue, pass *analysis.Pass) *Issue { + return &Issue{ + Issue: issue, Pass: pass, } } diff --git a/pkg/goanalysis/linter.go b/pkg/goanalysis/linter.go index 80ccfe456408..153e538b5820 100644 --- a/pkg/goanalysis/linter.go +++ b/pkg/goanalysis/linter.go @@ -13,11 +13,6 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/result" ) -const ( - TheOnlyAnalyzerName = "the_only_name" - TheOnlyanalyzerDoc = "the_only_doc" -) - type LoadMode int func (loadMode LoadMode) String() string { @@ -45,7 +40,7 @@ type Linter struct { name, desc string analyzers []*analysis.Analyzer cfg map[string]map[string]any - issuesReporter func(*linter.Context) []Issue + issuesReporter func(*linter.Context) []*Issue contextSetter func(*linter.Context) loadMode LoadMode needUseOriginalPackages bool @@ -55,7 +50,11 @@ func NewLinter(name, desc string, analyzers []*analysis.Analyzer, cfg map[string return &Linter{name: name, desc: desc, analyzers: analyzers, cfg: cfg} } -func (lnt *Linter) Run(_ context.Context, lintCtx *linter.Context) ([]result.Issue, error) { +func NewLinterFromAnalyzer(analyzer *analysis.Analyzer) *Linter { + return NewLinter(analyzer.Name, analyzer.Doc, []*analysis.Analyzer{analyzer}, nil) +} + +func (lnt *Linter) Run(_ context.Context, lintCtx *linter.Context) ([]*result.Issue, error) { if err := lnt.preRun(lintCtx); err != nil { return nil, err } @@ -71,12 +70,49 @@ func (lnt *Linter) LoadMode() LoadMode { return lnt.loadMode } +func (lnt *Linter) WithDesc(desc string) *Linter { + lnt.desc = desc + + return lnt +} + +func (lnt *Linter) WithVersion(v int) *Linter { + if v == 0 { + return lnt + } + + for _, analyzer := range lnt.analyzers { + if lnt.name != analyzer.Name { + continue + } + + // The analyzer name should be the same as the linter name to avoid displaying the name inside the reports. + analyzer.Name = fmt.Sprintf("%s_v%d", analyzer.Name, v) + } + + lnt.name = fmt.Sprintf("%s_v%d", lnt.name, v) + + return lnt +} + +func (lnt *Linter) WithConfig(cfg map[string]any) *Linter { + if len(cfg) == 0 { + return lnt + } + + lnt.cfg = map[string]map[string]any{ + lnt.name: cfg, + } + + return lnt +} + func (lnt *Linter) WithLoadMode(loadMode LoadMode) *Linter { lnt.loadMode = loadMode return lnt } -func (lnt *Linter) WithIssuesReporter(r func(*linter.Context) []Issue) *Linter { +func (lnt *Linter) WithIssuesReporter(r func(*linter.Context) []*Issue) *Linter { lnt.issuesReporter = r return lnt } @@ -176,7 +212,7 @@ func (lnt *Linter) useOriginalPackages() bool { return lnt.needUseOriginalPackages } -func (lnt *Linter) reportIssues(lintCtx *linter.Context) []Issue { +func (lnt *Linter) reportIssues(lintCtx *linter.Context) []*Issue { if lnt.issuesReporter != nil { return lnt.issuesReporter(lintCtx) } diff --git a/pkg/goanalysis/metalinter.go b/pkg/goanalysis/metalinter.go index 4db143baddb3..b9a210a66fc8 100644 --- a/pkg/goanalysis/metalinter.go +++ b/pkg/goanalysis/metalinter.go @@ -21,7 +21,7 @@ func NewMetaLinter(linters []*Linter) *MetaLinter { return ml } -func (ml MetaLinter) Run(_ context.Context, lintCtx *linter.Context) ([]result.Issue, error) { +func (ml MetaLinter) Run(_ context.Context, lintCtx *linter.Context) ([]*result.Issue, error) { for _, l := range ml.linters { if err := l.preRun(lintCtx); err != nil { return nil, fmt.Errorf("failed to pre-run %s: %w", l.Name(), err) @@ -65,8 +65,8 @@ func (MetaLinter) useOriginalPackages() bool { return false // `unused` can't be run by this metalinter } -func (ml MetaLinter) reportIssues(lintCtx *linter.Context) []Issue { - var ret []Issue +func (ml MetaLinter) reportIssues(lintCtx *linter.Context) []*Issue { + var ret []*Issue for _, lnt := range ml.linters { if lnt.issuesReporter != nil { ret = append(ret, lnt.issuesReporter(lintCtx)...) diff --git a/pkg/goanalysis/pkgerrors/errors.go b/pkg/goanalysis/pkgerrors/errors.go index 05d2c5238f8b..5d2b816ac6cf 100644 --- a/pkg/goanalysis/pkgerrors/errors.go +++ b/pkg/goanalysis/pkgerrors/errors.go @@ -15,11 +15,12 @@ type IllTypedError struct { } func (e *IllTypedError) Error() string { - return fmt.Sprintf("errors in package: %v", e.Pkg.Errors) + return fmt.Sprintf("IllTypedError: errors in package: %v", e.Pkg.Errors) } -func BuildIssuesFromIllTypedError(errs []error, lintCtx *linter.Context) ([]result.Issue, error) { - var issues []result.Issue +func BuildIssuesFromIllTypedError(errs []error, lintCtx *linter.Context) ([]*result.Issue, error) { + var issues []*result.Issue + uniqReportedIssues := map[string]bool{} var other error @@ -39,11 +40,19 @@ func BuildIssuesFromIllTypedError(errs []error, lintCtx *linter.Context) ([]resu if uniqReportedIssues[err.Msg] { continue } + uniqReportedIssues[err.Msg] = true lintCtx.Log.Errorf("typechecking error: %s", err.Msg) } else { + key := fmt.Sprintf("%s.%d.%d.%s", issue.FilePath(), issue.Line(), issue.Column(), issue.Text) + if uniqReportedIssues[key] { + continue + } + + uniqReportedIssues[key] = true + issue.Pkg = ill.Pkg // to save to cache later - issues = append(issues, *issue) + issues = append(issues, issue) } } } diff --git a/pkg/goanalysis/pkgerrors/parse.go b/pkg/goanalysis/pkgerrors/parse.go index 8c49a55929ed..2fe1fb529fa4 100644 --- a/pkg/goanalysis/pkgerrors/parse.go +++ b/pkg/goanalysis/pkgerrors/parse.go @@ -26,7 +26,7 @@ func parseError(srcErr packages.Error) (*result.Issue, error) { } func parseErrorPosition(pos string) (*token.Position, error) { - // file:line(:colon) + // file:line(:column) parts := strings.Split(pos, ":") if len(parts) == 1 { return nil, errors.New("no colons") @@ -39,7 +39,7 @@ func parseErrorPosition(pos string) (*token.Position, error) { } var column int - if len(parts) == 3 { // no column + if len(parts) == 3 { // got column column, err = strconv.Atoi(parts[2]) if err != nil { return nil, fmt.Errorf("failed to parse column from %q: %w", parts[2], err) diff --git a/pkg/goanalysis/runner.go b/pkg/goanalysis/runner.go index 808c9d2ad68c..6cc0a7077109 100644 --- a/pkg/goanalysis/runner.go +++ b/pkg/goanalysis/runner.go @@ -76,7 +76,7 @@ func newRunner(prefix string, logger logutils.Log, pkgCache *cache.Cache, loadGu // It provides most of the logic for the main functions of both the // singlechecker and the multi-analysis commands. // It returns the appropriate exit code. -func (r *runner) run(analyzers []*analysis.Analyzer, initialPackages []*packages.Package) ([]Diagnostic, +func (r *runner) run(analyzers []*analysis.Analyzer, initialPackages []*packages.Package) ([]*Diagnostic, []error, map[*analysis.Pass]*packages.Package, ) { debugf("Analyzing %d packages on load mode %s", len(initialPackages), r.loadMode) @@ -275,7 +275,7 @@ func (r *runner) analyze(pkgs []*packages.Package, analyzers []*analysis.Analyze return rootActions } -func extractDiagnostics(roots []*action) (retDiags []Diagnostic, retErrors []error) { +func extractDiagnostics(roots []*action) (retDiags []*Diagnostic, retErrors []error) { extracted := make(map[*action]bool) var extract func(*action) var visitAll func(actions []*action) @@ -322,7 +322,7 @@ func extractDiagnostics(roots []*action) (retDiags []Diagnostic, retErrors []err } seen[k] = true - retDiag := Diagnostic{ + retDiag := &Diagnostic{ File: file, Diagnostic: diag, Analyzer: act.Analyzer, diff --git a/pkg/goanalysis/runner_loadingpackage.go b/pkg/goanalysis/runner_loadingpackage.go index 0bf8f3fbb362..d22dbea30d72 100644 --- a/pkg/goanalysis/runner_loadingpackage.go +++ b/pkg/goanalysis/runner_loadingpackage.go @@ -24,6 +24,9 @@ import ( const unsafePkgName = "unsafe" +// https://github.com/golang/go/blob/go1.23.8/src/internal/types/errors/codes.go#L1484 +const tooNew = 151 + type loadingPackage struct { pkg *packages.Package imports map[string]*loadingPackage @@ -436,6 +439,14 @@ func (lp *loadingPackage) convertError(err error) []packages.Error { case types.Error: // from type checker + + // https://github.com/golang/go/blob/go1.23.8/src/go/types/api.go#L52-L57 + if int(reflect.ValueOf(err).FieldByName("go116code").Int()) == tooNew { + // https://github.com/golang/go/blob/go1.23.8/src/go/types/check.go#L380 + // https://github.com/golang/go/blob/go1.23.8/src/go/types/check.go#L349 + panic(err.Msg) + } + errs = append(errs, packages.Error{ Pos: err.Fset.Position(err.Pos).String(), Msg: err.Msg, diff --git a/pkg/goanalysis/runners.go b/pkg/goanalysis/runners.go index 5ffc1529363b..bcbc0033ef9a 100644 --- a/pkg/goanalysis/runners.go +++ b/pkg/goanalysis/runners.go @@ -3,6 +3,7 @@ package goanalysis import ( "fmt" "go/token" + "slices" "strings" "golang.org/x/tools/go/analysis" @@ -20,11 +21,11 @@ type runAnalyzersConfig interface { getLinterNameForDiagnostic(*Diagnostic) string getAnalyzers() []*analysis.Analyzer useOriginalPackages() bool - reportIssues(*linter.Context) []Issue + reportIssues(*linter.Context) []*Issue getLoadMode() LoadMode } -func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Issue, error) { +func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]*result.Issue, error) { log := lintCtx.Log.Child(logutils.DebugKeyGoAnalysis) sw := timeutils.NewStopwatch("analyzers", log) @@ -56,18 +57,19 @@ func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Iss } }() - buildAllIssues := func() []result.Issue { - var retIssues []result.Issue + buildAllIssues := func() []*result.Issue { + var retIssues []*result.Issue + reportedIssues := cfg.reportIssues(lintCtx) - for i := range reportedIssues { - issue := &reportedIssues[i].Issue - if issue.Pkg == nil { - issue.Pkg = passToPkg[reportedIssues[i].Pass] + for _, reportedIssue := range reportedIssues { + if reportedIssue.Pkg == nil { + reportedIssue.Pkg = passToPkg[reportedIssue.Pass] } - retIssues = append(retIssues, *issue) + + retIssues = append(retIssues, reportedIssue.Issue) } - retIssues = append(retIssues, buildIssues(diags, cfg.getLinterNameForDiagnostic)...) - return retIssues + + return slices.Concat(retIssues, buildIssues(diags, cfg.getLinterNameForDiagnostic)) } errIssues, err := pkgerrors.BuildIssuesFromIllTypedError(errs, lintCtx) @@ -81,11 +83,10 @@ func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Iss return issues, nil } -func buildIssues(diags []Diagnostic, linterNameBuilder func(diag *Diagnostic) string) []result.Issue { - var issues []result.Issue +func buildIssues(diags []*Diagnostic, linterNameBuilder func(diag *Diagnostic) string) []*result.Issue { + var issues []*result.Issue - for i := range diags { - diag := &diags[i] + for _, diag := range diags { linterName := linterNameBuilder(diag) var text string @@ -126,7 +127,7 @@ func buildIssues(diags []Diagnostic, linterNameBuilder func(diag *Diagnostic) st suggestedFixes = append(suggestedFixes, nsf) } - issues = append(issues, result.Issue{ + issues = append(issues, &result.Issue{ FromLinter: linterName, Text: text, Pos: diag.Position, @@ -136,10 +137,16 @@ func buildIssues(diags []Diagnostic, linterNameBuilder func(diag *Diagnostic) st if len(diag.Related) > 0 { for _, info := range diag.Related { - issues = append(issues, result.Issue{ + relatedPos := diag.Pkg.Fset.Position(info.Pos) + + if relatedPos.Filename != diag.Position.Filename { + relatedPos = diag.Position + } + + issues = append(issues, &result.Issue{ FromLinter: linterName, Text: fmt.Sprintf("%s(related information): %s", diag.Analyzer.Name, info.Message), - Pos: diag.Pkg.Fset.Position(info.Pos), + Pos: relatedPos, Pkg: diag.Pkg, }) } diff --git a/pkg/goanalysis/runners_cache.go b/pkg/goanalysis/runners_cache.go index 9673197c9ec9..5cd8a6b1ccd4 100644 --- a/pkg/goanalysis/runners_cache.go +++ b/pkg/goanalysis/runners_cache.go @@ -17,13 +17,12 @@ import ( ) func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages.Package]bool, - issues []result.Issue, lintCtx *linter.Context, analyzers []*analysis.Analyzer, + issues []*result.Issue, lintCtx *linter.Context, analyzers []*analysis.Analyzer, ) { startedAt := time.Now() - perPkgIssues := map[*packages.Package][]result.Issue{} - for ind := range issues { - i := &issues[ind] - perPkgIssues[i.Pkg] = append(perPkgIssues[i.Pkg], *i) + perPkgIssues := map[*packages.Package][]*result.Issue{} + for _, issue := range issues { + perPkgIssues[issue.Pkg] = append(perPkgIssues[issue.Pkg], issue) } var savedIssuesCount int64 = 0 @@ -34,23 +33,22 @@ func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages. wg.Add(workerCount) pkgCh := make(chan *packages.Package, len(allPkgs)) - for i := 0; i < workerCount; i++ { + for range workerCount { go func() { defer wg.Done() for pkg := range pkgCh { pkgIssues := perPkgIssues[pkg] encodedIssues := make([]EncodingIssue, 0, len(pkgIssues)) - for ind := range pkgIssues { - i := &pkgIssues[ind] + for _, issue := range pkgIssues { encodedIssues = append(encodedIssues, EncodingIssue{ - FromLinter: i.FromLinter, - Text: i.Text, - Severity: i.Severity, - Pos: i.Pos, - LineRange: i.LineRange, - SuggestedFixes: i.SuggestedFixes, - ExpectNoLint: i.ExpectNoLint, - ExpectedNoLintLinter: i.ExpectedNoLintLinter, + FromLinter: issue.FromLinter, + Text: issue.Text, + Severity: issue.Severity, + Pos: issue.Pos, + LineRange: issue.LineRange, + SuggestedFixes: issue.SuggestedFixes, + ExpectNoLint: issue.ExpectNoLint, + ExpectedNoLintLinter: issue.ExpectedNoLintLinter, }) } @@ -81,12 +79,12 @@ func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages. func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context, analyzers []*analysis.Analyzer, -) (issuesFromCache []result.Issue, pkgsFromCache map[*packages.Package]bool) { +) (issuesFromCache []*result.Issue, pkgsFromCache map[*packages.Package]bool) { startedAt := time.Now() lintResKey := getIssuesCacheKey(analyzers) type cacheRes struct { - issues []result.Issue + issues []*result.Issue loadErr error } pkgToCacheRes := make(map[*packages.Package]*cacheRes, len(pkgs)) @@ -103,7 +101,7 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context, go func() { defer wg.Done() for pkg := range pkgCh { - var pkgIssues []EncodingIssue + var pkgIssues []*EncodingIssue err := lintCtx.PkgCache.Get(pkg, cache.HashModeNeedAllDeps, lintResKey, &pkgIssues) cacheRes := pkgToCacheRes[pkg] cacheRes.loadErr = err @@ -114,10 +112,9 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context, continue } - issues := make([]result.Issue, 0, len(pkgIssues)) - for i := range pkgIssues { - issue := &pkgIssues[i] - issues = append(issues, result.Issue{ + issues := make([]*result.Issue, 0, len(pkgIssues)) + for _, issue := range pkgIssues { + issues = append(issues, &result.Issue{ FromLinter: issue.FromLinter, Text: issue.Text, Severity: issue.Severity, diff --git a/pkg/goformat/runner.go b/pkg/goformat/runner.go index 4105b9fbf718..f87626158179 100644 --- a/pkg/goformat/runner.go +++ b/pkg/goformat/runner.go @@ -12,7 +12,8 @@ import ( "regexp" "strings" - "github.com/rogpeppe/go-internal/diff" + "github.com/alecthomas/chroma/v2/quick" + rpdiff "github.com/rogpeppe/go-internal/diff" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/fsutils" @@ -32,11 +33,11 @@ type Runner struct { exitCode int } -func NewRunner(log logutils.Log, +func NewRunner(logger logutils.Log, metaFormatter *goformatters.MetaFormatter, matcher *processors.GeneratedFileMatcher, opts RunnerOptions) *Runner { return &Runner{ - log: log, + log: logger, matcher: matcher, metaFormatter: metaFormatter, opts: opts, @@ -56,7 +57,7 @@ func (c *Runner) Run(paths []string) error { } if c.opts.stdin { - return c.process("", savedStdout, os.Stdin) + return c.formatStdIn("", savedStdout, os.Stdin) } for _, path := range paths { @@ -66,6 +67,14 @@ func (c *Runner) Run(paths []string) error { } } + for pattern, count := range c.opts.excludedPathCounter { + if c.opts.warnUnused && count == 0 { + c.log.Warnf("The pattern %q match no issues", pattern) + } else { + c.log.Infof("Skipped %d issues by pattern %q", count, pattern) + } + } + return nil } @@ -112,15 +121,6 @@ func (c *Runner) process(path string, stdout io.Writer, in io.Reader) error { output := c.metaFormatter.Format(path, input) - if c.opts.stdin { - _, err = stdout.Write(output) - if err != nil { - return err - } - - return nil - } - if bytes.Equal(input, output) { return nil } @@ -128,9 +128,19 @@ func (c *Runner) process(path string, stdout io.Writer, in io.Reader) error { if c.opts.diff { newName := filepath.ToSlash(path) oldName := newName + ".orig" - _, err = stdout.Write(diff.Diff(oldName, input, newName, output)) - if err != nil { - return err + + patch := rpdiff.Diff(oldName, input, newName, output) + + if c.opts.colors { + err = quick.Highlight(stdout, string(patch), "diff", "terminal", "native") + if err != nil { + return err + } + } else { + _, err = stdout.Write(patch) + if err != nil { + return err + } } c.exitCode = 1 @@ -149,6 +159,38 @@ func (c *Runner) process(path string, stdout io.Writer, in io.Reader) error { return os.WriteFile(path, output, perms) } +func (c *Runner) formatStdIn(path string, stdout io.Writer, in io.Reader) error { + input, err := io.ReadAll(in) + if err != nil { + return err + } + + match, err := c.matcher.IsGeneratedFile(path, input) + if err != nil { + return err + } + + if match { + // If the file is generated, + // the input should be written to the stdout to avoid emptied the file. + _, err = stdout.Write(input) + if err != nil { + return err + } + + return nil + } + + output := c.metaFormatter.Format(path, input) + + _, err = stdout.Write(output) + if err != nil { + return err + } + + return nil +} + func (c *Runner) setOutputToDevNull() { devNull, err := os.Open(os.DevNull) if err != nil { @@ -168,20 +210,27 @@ type RunnerOptions struct { patterns []*regexp.Regexp generated string diff bool + colors bool stdin bool + + warnUnused bool + excludedPathCounter map[*regexp.Regexp]int } -func NewRunnerOptions(cfg *config.Config, diff, stdin bool) (RunnerOptions, error) { +func NewRunnerOptions(cfg *config.Config, diff, diffColored, stdin bool) (RunnerOptions, error) { basePath, err := fsutils.GetBasePath(context.Background(), cfg.Run.RelativePathMode, cfg.GetConfigDir()) if err != nil { return RunnerOptions{}, fmt.Errorf("get base path: %w", err) } opts := RunnerOptions{ - basePath: basePath, - generated: cfg.Formatters.Exclusions.Generated, - diff: diff, - stdin: stdin, + basePath: basePath, + generated: cfg.Formatters.Exclusions.Generated, + diff: diff || diffColored, + colors: diffColored, + stdin: stdin, + excludedPathCounter: make(map[*regexp.Regexp]int), + warnUnused: cfg.Formatters.Exclusions.WarnUnused, } for _, pattern := range cfg.Formatters.Exclusions.Paths { @@ -191,6 +240,7 @@ func NewRunnerOptions(cfg *config.Config, diff, stdin bool) (RunnerOptions, erro } opts.patterns = append(opts.patterns, exp) + opts.excludedPathCounter[exp] = 0 } return opts, nil @@ -208,6 +258,7 @@ func (o RunnerOptions) MatchAnyPattern(path string) (bool, error) { for _, pattern := range o.patterns { if pattern.MatchString(rel) { + o.excludedPathCounter[pattern]++ return true, nil } } diff --git a/pkg/goformatters/internal/diff.go b/pkg/goformatters/internal/diff.go index 7b9f80bc4228..fcec87bb8bbd 100644 --- a/pkg/goformatters/internal/diff.go +++ b/pkg/goformatters/internal/diff.go @@ -250,10 +250,7 @@ func ExtractDiagnosticFromPatch( } func toDiagnostic(ft *token.File, change Change, adjLine int) analysis.Diagnostic { - from := change.From + adjLine - if from > ft.LineCount() { - from = ft.LineCount() - } + from := min(change.From+adjLine, ft.LineCount()) start := ft.LineStart(from) diff --git a/pkg/goformatters/meta_formatter.go b/pkg/goformatters/meta_formatter.go index 718caaa96003..dbedcd4cba19 100644 --- a/pkg/goformatters/meta_formatter.go +++ b/pkg/goformatters/meta_formatter.go @@ -12,6 +12,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt" "github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports" "github.com/golangci/golangci-lint/v2/pkg/goformatters/golines" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" "github.com/golangci/golangci-lint/v2/pkg/logutils" ) @@ -41,6 +42,10 @@ func NewMetaFormatter(log logutils.Log, cfg *config.Formatters, runCfg *config.R m.formatters = append(m.formatters, goimports.New(&cfg.Settings.GoImports)) } + if slices.Contains(cfg.Enable, swaggo.Name) { + m.formatters = append(m.formatters, swaggo.New()) + } + // gci is a last because the only goal of gci is to handle imports. if slices.Contains(cfg.Enable, gci.Name) { formatter, err := gci.New(&cfg.Settings.Gci) @@ -86,5 +91,5 @@ func (m *MetaFormatter) Format(filename string, src []byte) []byte { } func IsFormatter(name string) bool { - return slices.Contains([]string{gofmt.Name, gofumpt.Name, goimports.Name, gci.Name, golines.Name}, name) + return slices.Contains([]string{gofmt.Name, gofumpt.Name, goimports.Name, gci.Name, golines.Name, swaggo.Name}, name) } diff --git a/pkg/goformatters/swaggo/swaggo.go b/pkg/goformatters/swaggo/swaggo.go new file mode 100644 index 000000000000..2479fb35baba --- /dev/null +++ b/pkg/goformatters/swaggo/swaggo.go @@ -0,0 +1,23 @@ +package swaggo + +import "github.com/golangci/swaggoswag" + +const Name = "swaggo" + +type Formatter struct { + formatter *swaggoswag.Formatter +} + +func New() *Formatter { + return &Formatter{ + formatter: swaggoswag.NewFormatter(), + } +} + +func (*Formatter) Name() string { + return Name +} + +func (f *Formatter) Format(path string, src []byte) ([]byte, error) { + return f.formatter.Format(path, src) +} diff --git a/pkg/golinters/arangolint/arangolint.go b/pkg/golinters/arangolint/arangolint.go new file mode 100644 index 000000000000..1598d532a879 --- /dev/null +++ b/pkg/golinters/arangolint/arangolint.go @@ -0,0 +1,13 @@ +package arangolint + +import ( + "go.augendre.info/arangolint/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/golinters/arangolint/arangolint_integration_test.go b/pkg/golinters/arangolint/arangolint_integration_test.go new file mode 100644 index 000000000000..db0f1aef0923 --- /dev/null +++ b/pkg/golinters/arangolint/arangolint_integration_test.go @@ -0,0 +1,11 @@ +package arangolint + +import ( + "testing" + + "github.com/golangci/golangci-lint/v2/test/testshared/integration" +) + +func TestFromTestdata(t *testing.T) { + integration.RunTestdata(t) +} diff --git a/pkg/golinters/arangolint/testdata/arangolint.go b/pkg/golinters/arangolint/testdata/arangolint.go new file mode 100644 index 000000000000..1cc3f28a87c2 --- /dev/null +++ b/pkg/golinters/arangolint/testdata/arangolint.go @@ -0,0 +1,35 @@ +//golangcitest:args -Earangolint +package arangolint + +import ( + "context" + + "github.com/arangodb/go-driver/v2/arangodb" +) + +func _() { + ctx := context.Background() + arangoClient := arangodb.NewClient(nil) + db, _ := arangoClient.GetDatabase(ctx, "name", nil) + + // direct nil + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, nil) // want "missing AllowImplicit option" + trx, _ := db.BeginTransaction(ctx, arangodb.TransactionCollections{}, nil) // want "missing AllowImplicit option" + _ = trx + + // direct missing + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{LockTimeout: 0}) // want "missing AllowImplicit option" + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{LockTimeout: 0}) // want "missing AllowImplicit option" + + // direct false + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: false}) + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: false}) + + // direct true + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true}) + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true}) + + // direct with other fields + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true, LockTimeout: 0}) + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true, LockTimeout: 0}) +} diff --git a/pkg/golinters/arangolint/testdata/arangolint_cgo.go b/pkg/golinters/arangolint/testdata/arangolint_cgo.go new file mode 100644 index 000000000000..3bc9bc7fefb8 --- /dev/null +++ b/pkg/golinters/arangolint/testdata/arangolint_cgo.go @@ -0,0 +1,52 @@ +//golangcitest:args -Earangolint +package arangolint + +/* + #include + #include + + void myprint(char* s) { + printf("%d\n", s); + } +*/ +import "C" + +import ( + "context" + "unsafe" + + "github.com/arangodb/go-driver/v2/arangodb" +) + +func _() { + cs := C.CString("Hello from stdio\n") + C.myprint(cs) + C.free(unsafe.Pointer(cs)) +} + +func _() { + ctx := context.Background() + arangoClient := arangodb.NewClient(nil) + db, _ := arangoClient.GetDatabase(ctx, "name", nil) + + // direct nil + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, nil) // want "missing AllowImplicit option" + trx, _ := db.BeginTransaction(ctx, arangodb.TransactionCollections{}, nil) // want "missing AllowImplicit option" + _ = trx + + // direct missing + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{LockTimeout: 0}) // want "missing AllowImplicit option" + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{LockTimeout: 0}) // want "missing AllowImplicit option" + + // direct false + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: false}) + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: false}) + + // direct true + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true}) + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true}) + + // direct with other fields + db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true, LockTimeout: 0}) + trx, _ = db.BeginTransaction(ctx, arangodb.TransactionCollections{}, &arangodb.BeginTransactionOptions{AllowImplicit: true, LockTimeout: 0}) +} diff --git a/pkg/golinters/arangolint/testdata/go.mod b/pkg/golinters/arangolint/testdata/go.mod new file mode 100644 index 000000000000..0fb1fc8b4a4e --- /dev/null +++ b/pkg/golinters/arangolint/testdata/go.mod @@ -0,0 +1,19 @@ +module arangolint + +go 1.23.0 + +require github.com/arangodb/go-driver/v2 v2.1.3 + +require ( + github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect + github.com/dchest/siphash v1.2.3 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/kkdai/maglev v0.2.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rs/zerolog v1.34.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect +) diff --git a/pkg/golinters/arangolint/testdata/go.sum b/pkg/golinters/arangolint/testdata/go.sum new file mode 100644 index 000000000000..69d72038590d --- /dev/null +++ b/pkg/golinters/arangolint/testdata/go.sum @@ -0,0 +1,47 @@ +github.com/arangodb/go-driver/v2 v2.1.3 h1:PpLSe8E2RalFuqTGi2yfHDe3ltOomfFCIToB66p1lr8= +github.com/arangodb/go-driver/v2 v2.1.3/go.mod h1:aoDzrsO7PQEFat3Q9pp4zfv6W+WotA7GcCeJQJfX+tc= +github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2LcQBbxd0ZFdbGSyRKTYMZCfBbw/pMJFOk1g= +github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kkdai/maglev v0.2.0 h1:w6DCW0kAA6fstZqXkrBrlgIC3jeIRXkjOYea/m6EK/Y= +github.com/kkdai/maglev v0.2.0/go.mod h1:d+mt8Lmt3uqi9aRb/BnPjzD0fy+ETs1vVXiGRnqHVZ4= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/golinters/asasalint/asasalint.go b/pkg/golinters/asasalint/asasalint.go index 5f33428c2224..0261e109d8aa 100644 --- a/pkg/golinters/asasalint/asasalint.go +++ b/pkg/golinters/asasalint/asasalint.go @@ -2,7 +2,6 @@ package asasalint import ( "github.com/alingse/asasalint" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -19,15 +18,12 @@ func New(settings *config.AsasalintSettings) *goanalysis.Linter { cfg.IgnoreTest = false } - a, err := asasalint.NewAnalyzer(cfg) + analyzer, err := asasalint.NewAnalyzer(cfg) if err != nil { internal.LinterLogger.Fatalf("asasalint: create analyzer: %v", err) } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/asciicheck/asciicheck.go b/pkg/golinters/asciicheck/asciicheck.go index b5cdaa80bbeb..4872770365c6 100644 --- a/pkg/golinters/asciicheck/asciicheck.go +++ b/pkg/golinters/asciicheck/asciicheck.go @@ -2,18 +2,12 @@ package asciicheck import ( "github.com/tdakkota/asciicheck" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := asciicheck.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(asciicheck.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/bidichk/bidichk.go b/pkg/golinters/bidichk/bidichk.go index 2d2a8d664fa4..c35daafbfb77 100644 --- a/pkg/golinters/bidichk/bidichk.go +++ b/pkg/golinters/bidichk/bidichk.go @@ -4,16 +4,14 @@ import ( "strings" "github.com/breml/bidichk/pkg/bidichk" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.BiDiChkSettings) *goanalysis.Linter { - a := bidichk.NewAnalyzer() + var cfg map[string]any - cfg := map[string]map[string]any{} if settings != nil { var opts []string @@ -45,15 +43,13 @@ func New(settings *config.BiDiChkSettings) *goanalysis.Linter { opts = append(opts, "POP-DIRECTIONAL-ISOLATE") } - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "disallowed-runes": strings.Join(opts, ","), } } - return goanalysis.NewLinter( - a.Name, - "Checks for dangerous unicode character sequences", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(bidichk.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/bodyclose/bodyclose.go b/pkg/golinters/bodyclose/bodyclose.go index 0c86fbe76513..f68c4d0a9e6a 100644 --- a/pkg/golinters/bodyclose/bodyclose.go +++ b/pkg/golinters/bodyclose/bodyclose.go @@ -2,18 +2,12 @@ package bodyclose import ( "github.com/timakin/bodyclose/passes/bodyclose" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := bodyclose.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(bodyclose.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/canonicalheader/canonicalheader.go b/pkg/golinters/canonicalheader/canonicalheader.go index bda1dfbd20d3..24e95f143e9d 100644 --- a/pkg/golinters/canonicalheader/canonicalheader.go +++ b/pkg/golinters/canonicalheader/canonicalheader.go @@ -2,18 +2,12 @@ package canonicalheader import ( "github.com/lasiar/canonicalheader" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := canonicalheader.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(canonicalheader.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/containedctx/containedctx.go b/pkg/golinters/containedctx/containedctx.go index 6bdb08350dd7..6d17b8e46fcf 100644 --- a/pkg/golinters/containedctx/containedctx.go +++ b/pkg/golinters/containedctx/containedctx.go @@ -2,18 +2,12 @@ package containedctx import ( "github.com/sivchari/containedctx" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := containedctx.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(containedctx.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/contextcheck/contextcheck.go b/pkg/golinters/contextcheck/contextcheck.go index 9d01fb7a2038..88c71d2d3eb2 100644 --- a/pkg/golinters/contextcheck/contextcheck.go +++ b/pkg/golinters/contextcheck/contextcheck.go @@ -2,7 +2,6 @@ package contextcheck import ( "github.com/kkHAIKE/contextcheck" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" "github.com/golangci/golangci-lint/v2/pkg/lint/linter" @@ -11,12 +10,10 @@ import ( func New() *goanalysis.Linter { analyzer := contextcheck.NewAnalyzer(contextcheck.Configuration{}) - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = contextcheck.NewRun(lintCtx.Packages, false) - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = contextcheck.NewRun(lintCtx.Packages, false) + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/copyloopvar/copyloopvar.go b/pkg/golinters/copyloopvar/copyloopvar.go index f6ca96f99567..9dc81de58af2 100644 --- a/pkg/golinters/copyloopvar/copyloopvar.go +++ b/pkg/golinters/copyloopvar/copyloopvar.go @@ -2,28 +2,22 @@ package copyloopvar import ( "github.com/karamaru-alpha/copyloopvar" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.CopyLoopVarSettings) *goanalysis.Linter { - a := copyloopvar.NewAnalyzer() + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - "check-alias": settings.CheckAlias, - }, + cfg = map[string]any{ + "check-alias": settings.CheckAlias, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(copyloopvar.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/cyclop/cyclop.go b/pkg/golinters/cyclop/cyclop.go index 41db272cd4e3..0a0e2dbc635b 100644 --- a/pkg/golinters/cyclop/cyclop.go +++ b/pkg/golinters/cyclop/cyclop.go @@ -2,37 +2,29 @@ package cyclop import ( "github.com/bkielbasa/cyclop/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.CyclopSettings) *goanalysis.Linter { - a := analyzer.NewAnalyzer() + cfg := map[string]any{} - var cfg map[string]map[string]any if settings != nil { - d := map[string]any{ - // Should be managed with `linters.exclusions.rules`. - "skipTests": false, - } + // Should be managed with `linters.exclusions.rules`. + cfg["skipTests"] = false if settings.MaxComplexity != 0 { - d["maxComplexity"] = settings.MaxComplexity + cfg["maxComplexity"] = settings.MaxComplexity } if settings.PackageAverage != 0 { - d["packageAverage"] = settings.PackageAverage + cfg["packageAverage"] = settings.PackageAverage } - - cfg = map[string]map[string]any{a.Name: d} } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/decorder/decorder.go b/pkg/golinters/decorder/decorder.go index 03a7853c27e2..a67bdfade155 100644 --- a/pkg/golinters/decorder/decorder.go +++ b/pkg/golinters/decorder/decorder.go @@ -4,15 +4,12 @@ import ( "strings" "gitlab.com/bosi/decorder" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.DecorderSettings) *goanalysis.Linter { - a := decorder.Analyzer - // disable all rules/checks by default cfg := map[string]any{ "ignore-underscore-vars": false, @@ -35,10 +32,8 @@ func New(settings *config.DecorderSettings) *goanalysis.Linter { cfg["disable-init-func-first-check"] = settings.DisableInitFuncFirstCheck } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - map[string]map[string]any{a.Name: cfg}, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(decorder.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/depguard/depguard.go b/pkg/golinters/depguard/depguard.go index ab0863d6a064..cc01f4f47ab5 100644 --- a/pkg/golinters/depguard/depguard.go +++ b/pkg/golinters/depguard/depguard.go @@ -4,22 +4,20 @@ import ( "strings" "github.com/OpenPeeDeeP/depguard/v2" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" - "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" "github.com/golangci/golangci-lint/v2/pkg/lint/linter" ) -func New(settings *config.DepGuardSettings, basePath string) *goanalysis.Linter { +func New(settings *config.DepGuardSettings, replacer *strings.Replacer) *goanalysis.Linter { conf := depguard.LinterSettings{} if settings != nil { for s, rule := range settings.Rules { var extendedPatterns []string for _, file := range rule.Files { - extendedPatterns = append(extendedPatterns, strings.ReplaceAll(file, internal.PlaceholderBasePath, basePath)) + extendedPatterns = append(extendedPatterns, replacer.Replace(file)) } list := &depguard.List{ @@ -42,17 +40,15 @@ func New(settings *config.DepGuardSettings, basePath string) *goanalysis.Linter } } - a := depguard.NewUncompiledAnalyzer(&conf) - - return goanalysis.NewLinter( - a.Analyzer.Name, - a.Analyzer.Doc, - []*analysis.Analyzer{a.Analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - err := a.Compile() - if err != nil { - lintCtx.Log.Errorf("create analyzer: %v", err) - } - }).WithLoadMode(goanalysis.LoadModeSyntax) + analyzer := depguard.NewUncompiledAnalyzer(&conf) + + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + err := analyzer.Compile() + if err != nil { + lintCtx.Log.Errorf("create analyzer: %v", err) + } + }). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/dogsled/dogsled.go b/pkg/golinters/dogsled/dogsled.go index 23d48ba57274..c5e872182cc7 100644 --- a/pkg/golinters/dogsled/dogsled.go +++ b/pkg/golinters/dogsled/dogsled.go @@ -11,24 +11,17 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -const linterName = "dogsled" - func New(settings *config.DogsledSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - return run(pass, settings.MaxBlankIdentifiers) - }, - Requires: []*analysis.Analyzer{inspect.Analyzer}, - } - - return goanalysis.NewLinter( - linterName, - "Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "dogsled", + Doc: "Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())", + Run: func(pass *analysis.Pass) (any, error) { + return run(pass, settings.MaxBlankIdentifiers) + }, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func run(pass *analysis.Pass, maxBlanks int) (any, error) { diff --git a/pkg/golinters/dupl/dupl.go b/pkg/golinters/dupl/dupl.go index 993bfd6f2326..0b6b3a162c2e 100644 --- a/pkg/golinters/dupl/dupl.go +++ b/pkg/golinters/dupl/dupl.go @@ -20,40 +20,36 @@ const linterName = "dupl" func New(settings *config.DuplSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runDupl(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Detects duplicate fragments of code.", + Run: func(pass *analysis.Pass) (any, error) { + issues, err := runDupl(pass, settings) + if err != nil { + return nil, err + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return goanalysis.NewLinter( - linterName, - "Detects duplicate fragments of code.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } -func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]goanalysis.Issue, error) { +func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]*goanalysis.Issue, error) { issues, err := duplAPI.Run(internal.GetGoFileNames(pass), settings.Threshold) if err != nil { return nil, err @@ -63,7 +59,7 @@ func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]goanalysis.I return nil, nil } - res := make([]goanalysis.Issue, 0, len(issues)) + res := make([]*goanalysis.Issue, 0, len(issues)) for _, i := range issues { toFilename, err := fsutils.ShortestRelPath(i.To.Filename(), "") @@ -74,7 +70,7 @@ func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]goanalysis.I dupl := fmt.Sprintf("%s:%d-%d", toFilename, i.To.LineStart(), i.To.LineEnd()) text := fmt.Sprintf("%d-%d lines are duplicate of %s", i.From.LineStart(), i.From.LineEnd(), - internal.FormatCode(dupl, nil)) + internal.FormatCode(dupl)) res = append(res, goanalysis.NewIssue(&result.Issue{ Pos: token.Position{ diff --git a/pkg/golinters/dupword/dupword.go b/pkg/golinters/dupword/dupword.go index 62851475f608..7b989bc22a8f 100644 --- a/pkg/golinters/dupword/dupword.go +++ b/pkg/golinters/dupword/dupword.go @@ -4,27 +4,24 @@ import ( "strings" "github.com/Abirdcfly/dupword" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.DupWordSettings) *goanalysis.Linter { - a := dupword.NewAnalyzer() + var cfg map[string]any - cfg := map[string]map[string]any{} if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "keyword": strings.Join(settings.Keywords, ","), "ignore": strings.Join(settings.Ignore, ","), } } - return goanalysis.NewLinter( - a.Name, - "checks for duplicate words in the source code", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(dupword.NewAnalyzer()). + WithDesc("Checks for duplicate words in the source code"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/durationcheck/durationcheck.go b/pkg/golinters/durationcheck/durationcheck.go index d3e74231f5b3..b6723fa12574 100644 --- a/pkg/golinters/durationcheck/durationcheck.go +++ b/pkg/golinters/durationcheck/durationcheck.go @@ -2,18 +2,12 @@ package durationcheck import ( "github.com/charithe/durationcheck" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := durationcheck.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(durationcheck.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck.go b/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck.go new file mode 100644 index 000000000000..c9df5038c064 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck.go @@ -0,0 +1,23 @@ +package embeddedstructfieldcheck + +import ( + "github.com/manuelarte/embeddedstructfieldcheck/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.EmbeddedStructFieldCheckSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.ForbidMutexName: settings.ForbidMutex, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck_integration_test.go b/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck_integration_test.go new file mode 100644 index 000000000000..ba4258467733 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck_integration_test.go @@ -0,0 +1,19 @@ +package embeddedstructfieldcheck + +import ( + "testing" + + "github.com/golangci/golangci-lint/v2/test/testshared/integration" +) + +func TestFromTestdata(t *testing.T) { + integration.RunTestdata(t) +} + +func TestFix(t *testing.T) { + integration.RunFix(t) +} + +func TestFixPathPrefix(t *testing.T) { + integration.RunFixPathPrefix(t) +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_comments.go b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_comments.go new file mode 100644 index 000000000000..8dd119ede62a --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_comments.go @@ -0,0 +1,27 @@ +//golangcitest:args -Eembeddedstructfieldcheck +package testdata + +import "time" + +type ValidStructWithSingleLineComments struct { + // time.Time Single line comment + time.Time + + // version Single line comment + version int +} + +type StructWithSingleLineComments struct { + // time.Time Single line comment + time.Time // want `there must be an empty line separating embedded fields from regular fields` + // version Single line comment + version int +} + +type StructWithMultiLineComments struct { + // time.Time Single line comment + time.Time // want `there must be an empty line separating embedded fields from regular fields` + // version Single line comment + // very long comment + version int +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_mutex.go b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_mutex.go new file mode 100644 index 000000000000..e0a586ef6f02 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_mutex.go @@ -0,0 +1,29 @@ +//golangcitest:args -Eembeddedstructfieldcheck +//golangcitest:config_path testdata/embeddedstructfieldcheck_mutex.yml +package testdata + +import "sync" + +type MutextEmbedded struct { + sync.Mutex // want `sync.Mutex should not be embedded` +} + +type MutextNotEmbedded struct { + mu sync.Mutex +} + +type PointerMutextEmbedded struct { + *sync.Mutex // want `sync.Mutex should not be embedded` +} + +type RWMutextEmbedded struct { + sync.RWMutex // want `sync.RWMutex should not be embedded` +} + +type RWMutextNotEmbedded struct { + mu sync.RWMutex +} + +type PointerRWMutextEmbedded struct { + *sync.RWMutex // want `sync.RWMutex should not be embedded` +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_mutex.yml b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_mutex.yml new file mode 100644 index 000000000000..ff5e68bc81e3 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_mutex.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + embeddedstructfieldcheck: + forbid-mutex: true diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_simple.go b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_simple.go new file mode 100644 index 000000000000..da13d29c95f7 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_simple.go @@ -0,0 +1,39 @@ +//golangcitest:args -Eembeddedstructfieldcheck +package testdata + +import ( + "context" + "time" +) + +type ValidStruct struct { + time.Time + + version int +} + +type NoSpaceStruct struct { + time.Time // want `there must be an empty line separating embedded fields from regular fields` + version int +} + +type NotSortedStruct struct { + version int + + time.Time // want `embedded fields should be listed before regular fields` +} + +type MixedEmbeddedAndNotEmbedded struct { + context.Context + + name string + + time.Time // want `embedded fields should be listed before regular fields` + + age int +} + +type EmbeddedWithPointers struct { + *time.Time // want `there must be an empty line separating embedded fields from regular fields` + version int +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_special_cases.go b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_special_cases.go new file mode 100644 index 000000000000..b9ae5f3e187c --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/embeddedstructfieldcheck_special_cases.go @@ -0,0 +1,11 @@ +//golangcitest:args -Eembeddedstructfieldcheck +package testdata + +import "time" + +func myFunction() { + type myType struct { + version int + time.Time // want `embedded fields should be listed before regular fields` + } +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/fix/in/comments.go b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/in/comments.go new file mode 100644 index 000000000000..5cd45dc171b7 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/in/comments.go @@ -0,0 +1,39 @@ +//golangcitest:args -Eembeddedstructfieldcheck +//golangcitest:expected_exitcode 0 +package testdata + +import "time" + +type ValidStructWithSingleLineComments struct { + // time.Time Single line comment + time.Time + + // version Single line comment + version int +} + +type StructWithSingleLineComments struct { + // time.Time Single line comment + time.Time // want `there must be an empty line separating embedded fields from regular fields` + + // version Single line comment + version int +} + +type StructWithMultiLineComments struct { + // time.Time Single line comment + time.Time // want `there must be an empty line separating embedded fields from regular fields` + + // version Single line comment + // very long comment + version int +} + +type A struct { + // comment + ValidStructWithSingleLineComments + // C is foo + StructWithSingleLineComments // want `there must be an empty line separating embedded fields from regular fields` + + D string +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/fix/in/simple.go b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/in/simple.go new file mode 100644 index 000000000000..578ddc0d170e --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/in/simple.go @@ -0,0 +1,23 @@ +//golangcitest:args -Eembeddedstructfieldcheck +//golangcitest:expected_exitcode 0 +package testdata + +import ( + "time" +) + +type ValidStruct struct { + time.Time + + version int +} + +type NoSpaceStruct struct { + time.Time // want `there must be an empty line separating embedded fields from regular fields` + version int +} + +type EmbeddedWithPointers struct { + *time.Time // want `there must be an empty line separating embedded fields from regular fields` + version int +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/fix/out/comments.go b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/out/comments.go new file mode 100644 index 000000000000..5cd45dc171b7 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/out/comments.go @@ -0,0 +1,39 @@ +//golangcitest:args -Eembeddedstructfieldcheck +//golangcitest:expected_exitcode 0 +package testdata + +import "time" + +type ValidStructWithSingleLineComments struct { + // time.Time Single line comment + time.Time + + // version Single line comment + version int +} + +type StructWithSingleLineComments struct { + // time.Time Single line comment + time.Time // want `there must be an empty line separating embedded fields from regular fields` + + // version Single line comment + version int +} + +type StructWithMultiLineComments struct { + // time.Time Single line comment + time.Time // want `there must be an empty line separating embedded fields from regular fields` + + // version Single line comment + // very long comment + version int +} + +type A struct { + // comment + ValidStructWithSingleLineComments + // C is foo + StructWithSingleLineComments // want `there must be an empty line separating embedded fields from regular fields` + + D string +} diff --git a/pkg/golinters/embeddedstructfieldcheck/testdata/fix/out/simple.go b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/out/simple.go new file mode 100644 index 000000000000..a35f19ff4a15 --- /dev/null +++ b/pkg/golinters/embeddedstructfieldcheck/testdata/fix/out/simple.go @@ -0,0 +1,25 @@ +//golangcitest:args -Eembeddedstructfieldcheck +//golangcitest:expected_exitcode 0 +package testdata + +import ( + "time" +) + +type ValidStruct struct { + time.Time + + version int +} + +type NoSpaceStruct struct { + time.Time // want `there must be an empty line separating embedded fields from regular fields` + + version int +} + +type EmbeddedWithPointers struct { + *time.Time // want `there must be an empty line separating embedded fields from regular fields` + + version int +} diff --git a/pkg/golinters/err113/err113.go b/pkg/golinters/err113/err113.go index 78ef99d6a1a9..d3b3a4c1cca7 100644 --- a/pkg/golinters/err113/err113.go +++ b/pkg/golinters/err113/err113.go @@ -2,18 +2,13 @@ package err113 import ( "github.com/Djarvur/go-err113" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := err113.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - "Go linter to check the errors handling expressions", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(err113.NewAnalyzer()). + WithDesc("Check errors handling expressions"). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/errcheck/errcheck.go b/pkg/golinters/errcheck/errcheck.go index 56d00c350b4f..6bd473845c3f 100644 --- a/pkg/golinters/errcheck/errcheck.go +++ b/pkg/golinters/errcheck/errcheck.go @@ -21,43 +21,42 @@ const linterName = "errcheck" func New(settings *config.ErrcheckSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue analyzer := &analysis.Analyzer{ Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, + Doc: "errcheck is a program for checking for unchecked errors in Go code. " + + "These unchecked errors can be critical bugs in some cases", + Run: goanalysis.DummyRun, } - return goanalysis.NewLinter( - linterName, - "errcheck is a program for checking for unchecked errors in Go code. "+ - "These unchecked errors can be critical bugs in some cases", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - checker := getChecker(settings) - checker.Tags = lintCtx.Cfg.Run.BuildTags + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + checker := getChecker(settings) + checker.Tags = lintCtx.Cfg.Run.BuildTags - analyzer.Run = func(pass *analysis.Pass) (any, error) { - issues := runErrCheck(lintCtx, pass, checker) + analyzer.Run = func(pass *analysis.Pass) (any, error) { + issues := runErrCheck(pass, checker, settings.Verbose) - if len(issues) == 0 { - return nil, nil - } + if len(issues) == 0 { + return nil, nil + } - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runErrCheck(lintCtx *linter.Context, pass *analysis.Pass, checker *errcheck.Checker) []goanalysis.Issue { +func runErrCheck(pass *analysis.Pass, checker *errcheck.Checker, verbose bool) []*goanalysis.Issue { pkg := &packages.Package{ Fset: pass.Fset, Syntax: pass.Files, @@ -70,15 +69,18 @@ func runErrCheck(lintCtx *linter.Context, pass *analysis.Pass, checker *errcheck return nil } - issues := make([]goanalysis.Issue, len(lintIssues.UncheckedErrors)) + issues := make([]*goanalysis.Issue, len(lintIssues.UncheckedErrors)) for i, err := range lintIssues.UncheckedErrors { text := "Error return value is not checked" if err.FuncName != "" { code := cmp.Or(err.SelectorName, err.FuncName) + if verbose { + code = err.FuncName + } - text = fmt.Sprintf("Error return value of %s is not checked", internal.FormatCode(code, lintCtx.Cfg)) + text = fmt.Sprintf("Error return value of %s is not checked", internal.FormatCode(code)) } issues[i] = goanalysis.NewIssue( diff --git a/pkg/golinters/errchkjson/errchkjson.go b/pkg/golinters/errchkjson/errchkjson.go index a705406e49f5..02510ab49901 100644 --- a/pkg/golinters/errchkjson/errchkjson.go +++ b/pkg/golinters/errchkjson/errchkjson.go @@ -2,30 +2,25 @@ package errchkjson import ( "github.com/breml/errchkjson" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.ErrChkJSONSettings) *goanalysis.Linter { - a := errchkjson.NewAnalyzer() - - cfg := map[string]map[string]any{} - cfg[a.Name] = map[string]any{ + cfg := map[string]any{ "omit-safe": true, } + if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "omit-safe": !settings.CheckErrorFreeEncoding, "report-no-exported": settings.ReportNoExported, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(errchkjson.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/errname/errname.go b/pkg/golinters/errname/errname.go index 36d6f12356fd..a66f3211f4e9 100644 --- a/pkg/golinters/errname/errname.go +++ b/pkg/golinters/errname/errname.go @@ -2,18 +2,12 @@ package errname import ( "github.com/Antonboom/errname/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := analyzer.New() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/errorlint/errorlint.go b/pkg/golinters/errorlint/errorlint.go index 7560bc0af90b..f32217796920 100644 --- a/pkg/golinters/errorlint/errorlint.go +++ b/pkg/golinters/errorlint/errorlint.go @@ -2,7 +2,6 @@ package errorlint import ( "github.com/polyfloyd/go-errorlint/errorlint" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -23,12 +22,10 @@ func New(settings *config.ErrorLintSettings) *goanalysis.Linter { } } - a := errorlint.NewAnalyzer(opts...) - - cfg := map[string]map[string]any{} + var cfg map[string]any if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "errorf": settings.Errorf, "errorf-multi": settings.ErrorfMulti, "asserts": settings.Asserts, @@ -36,13 +33,11 @@ func New(settings *config.ErrorLintSettings) *goanalysis.Linter { } } - return goanalysis.NewLinter( - a.Name, - "errorlint is a linter for that can be used to find code "+ - "that will cause problems with the error wrapping scheme introduced in Go 1.13.", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(errorlint.NewAnalyzer(opts...)). + WithDesc("Find code that can cause problems with the error wrapping scheme introduced in Go 1.13."). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } func toAllowPairs(data []config.ErrorLintAllowPair) []errorlint.AllowPair { diff --git a/pkg/golinters/exhaustive/exhaustive.go b/pkg/golinters/exhaustive/exhaustive.go index be77e54a4bc6..ec240739d69e 100644 --- a/pkg/golinters/exhaustive/exhaustive.go +++ b/pkg/golinters/exhaustive/exhaustive.go @@ -2,37 +2,31 @@ package exhaustive import ( "github.com/nishanths/exhaustive" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.ExhaustiveSettings) *goanalysis.Linter { - a := exhaustive.Analyzer + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - exhaustive.CheckFlag: settings.Check, - exhaustive.DefaultSignifiesExhaustiveFlag: settings.DefaultSignifiesExhaustive, - exhaustive.IgnoreEnumMembersFlag: settings.IgnoreEnumMembers, - exhaustive.IgnoreEnumTypesFlag: settings.IgnoreEnumTypes, - exhaustive.PackageScopeOnlyFlag: settings.PackageScopeOnly, - exhaustive.ExplicitExhaustiveMapFlag: settings.ExplicitExhaustiveMap, - exhaustive.ExplicitExhaustiveSwitchFlag: settings.ExplicitExhaustiveSwitch, - exhaustive.DefaultCaseRequiredFlag: settings.DefaultCaseRequired, - // Should be managed with `linters.exclusions.generated`. - exhaustive.CheckGeneratedFlag: true, - }, + cfg = map[string]any{ + exhaustive.CheckFlag: settings.Check, + exhaustive.DefaultSignifiesExhaustiveFlag: settings.DefaultSignifiesExhaustive, + exhaustive.IgnoreEnumMembersFlag: settings.IgnoreEnumMembers, + exhaustive.IgnoreEnumTypesFlag: settings.IgnoreEnumTypes, + exhaustive.PackageScopeOnlyFlag: settings.PackageScopeOnly, + exhaustive.ExplicitExhaustiveMapFlag: settings.ExplicitExhaustiveMap, + exhaustive.ExplicitExhaustiveSwitchFlag: settings.ExplicitExhaustiveSwitch, + exhaustive.DefaultCaseRequiredFlag: settings.DefaultCaseRequired, + // Should be managed with `linters.exclusions.generated`. + exhaustive.CheckGeneratedFlag: true, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(exhaustive.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/exhaustruct/exhaustruct.go b/pkg/golinters/exhaustruct/exhaustruct.go index 9b742129969d..290878e1c404 100644 --- a/pkg/golinters/exhaustruct/exhaustruct.go +++ b/pkg/golinters/exhaustruct/exhaustruct.go @@ -1,8 +1,7 @@ package exhaustruct import ( - "github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer" - "golang.org/x/tools/go/analysis" + exhaustruct "github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -11,20 +10,18 @@ import ( func New(settings *config.ExhaustructSettings) *goanalysis.Linter { var include, exclude []string + if settings != nil { include = settings.Include exclude = settings.Exclude } - a, err := analyzer.NewAnalyzer(include, exclude) + analyzer, err := exhaustruct.NewAnalyzer(include, exclude) if err != nil { internal.LinterLogger.Fatalf("exhaustruct configuration: %v", err) } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/exptostd/exptostd.go b/pkg/golinters/exptostd/exptostd.go index 731a4a0ccad7..dbd78dce91cb 100644 --- a/pkg/golinters/exptostd/exptostd.go +++ b/pkg/golinters/exptostd/exptostd.go @@ -2,18 +2,12 @@ package exptostd import ( "github.com/ldez/exptostd" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := exptostd.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(exptostd.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/exptostd/testdata/go.mod b/pkg/golinters/exptostd/testdata/go.mod index 5261142a3036..3bd4f2c04ce5 100644 --- a/pkg/golinters/exptostd/testdata/go.mod +++ b/pkg/golinters/exptostd/testdata/go.mod @@ -1,5 +1,5 @@ module exptostd -go 1.22.0 +go 1.23.0 -require golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 +require golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 diff --git a/pkg/golinters/exptostd/testdata/go.sum b/pkg/golinters/exptostd/testdata/go.sum index c487fae960b3..2fbef45b9043 100644 --- a/pkg/golinters/exptostd/testdata/go.sum +++ b/pkg/golinters/exptostd/testdata/go.sum @@ -1,2 +1,2 @@ -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= diff --git a/pkg/golinters/fatcontext/fatcontext.go b/pkg/golinters/fatcontext/fatcontext.go index 8f34064dc057..58933c660588 100644 --- a/pkg/golinters/fatcontext/fatcontext.go +++ b/pkg/golinters/fatcontext/fatcontext.go @@ -1,28 +1,23 @@ package fatcontext import ( - "github.com/Crocmagnon/fatcontext/pkg/analyzer" - "golang.org/x/tools/go/analysis" + "go.augendre.info/fatcontext/pkg/analyzer" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.FatcontextSettings) *goanalysis.Linter { - a := analyzer.NewAnalyzer() - - cfg := map[string]map[string]any{} + var cfg map[string]any if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ analyzer.FlagCheckStructPointers: settings.CheckStructPointers, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/forbidigo/forbidigo.go b/pkg/golinters/forbidigo/forbidigo.go index 45f9088fa97d..796faf3a6ef0 100644 --- a/pkg/golinters/forbidigo/forbidigo.go +++ b/pkg/golinters/forbidigo/forbidigo.go @@ -3,7 +3,7 @@ package forbidigo import ( "fmt" - "github.com/ashanbrown/forbidigo/forbidigo" + "github.com/ashanbrown/forbidigo/v2/forbidigo" "golang.org/x/tools/go/analysis" "gopkg.in/yaml.v3" @@ -15,28 +15,23 @@ import ( const linterName = "forbidigo" func New(settings *config.ForbidigoSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - err := runForbidigo(pass, settings) - if err != nil { - return nil, err - } - - return nil, nil - }, - } - // Without AnalyzeTypes, LoadModeSyntax is enough. // But we cannot make this depend on the settings and have to mirror the mode chosen in GetAllSupportedLinterConfigs, - // therefore we have to use LoadModeTypesInfo in all cases. - return goanalysis.NewLinter( - linterName, - "Forbids identifiers", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + // therefore, we have to use LoadModeTypesInfo in all cases. + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Forbids identifiers", + Run: func(pass *analysis.Pass) (any, error) { + err := runForbidigo(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } func runForbidigo(pass *analysis.Pass, settings *config.ForbidigoSettings) error { diff --git a/pkg/golinters/forcetypeassert/forcetypeassert.go b/pkg/golinters/forcetypeassert/forcetypeassert.go index e82355380c25..19a0e3450b37 100644 --- a/pkg/golinters/forcetypeassert/forcetypeassert.go +++ b/pkg/golinters/forcetypeassert/forcetypeassert.go @@ -2,18 +2,13 @@ package forcetypeassert import ( "github.com/gostaticanalysis/forcetypeassert" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := forcetypeassert.Analyzer - - return goanalysis.NewLinter( - a.Name, - "finds forced type assertions", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(forcetypeassert.Analyzer). + WithDesc("Find forced type assertions"). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/funcorder/funcorder.go b/pkg/golinters/funcorder/funcorder.go new file mode 100644 index 000000000000..06400753ebdb --- /dev/null +++ b/pkg/golinters/funcorder/funcorder.go @@ -0,0 +1,25 @@ +package funcorder + +import ( + "github.com/manuelarte/funcorder/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.FuncOrderSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.ConstructorCheckName: settings.Constructor, + analyzer.StructMethodCheckName: settings.StructMethod, + analyzer.AlphabeticalCheckName: settings.Alphabetical, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/golinters/funcorder/funcorder_integration_test.go b/pkg/golinters/funcorder/funcorder_integration_test.go new file mode 100644 index 000000000000..31ee6ec82d4b --- /dev/null +++ b/pkg/golinters/funcorder/funcorder_integration_test.go @@ -0,0 +1,11 @@ +package funcorder + +import ( + "testing" + + "github.com/golangci/golangci-lint/v2/test/testshared/integration" +) + +func TestFromTestdata(t *testing.T) { + integration.RunTestdata(t) +} diff --git a/pkg/golinters/funcorder/testdata/funcorder.go b/pkg/golinters/funcorder/testdata/funcorder.go new file mode 100644 index 000000000000..b9ae4e81fafa --- /dev/null +++ b/pkg/golinters/funcorder/testdata/funcorder.go @@ -0,0 +1,40 @@ +//golangcitest:args -Efuncorder +package testdata + +import "time" + +type MyStruct struct { + Name string +} + +func (m MyStruct) lenName() int { // want `unexported method "lenName" for struct "MyStruct" should be placed after the exported method "SetName"` + return len(m.Name) +} + +func (m MyStruct) GetName() string { + return m.Name +} + +func (m *MyStruct) SetName(name string) { + m.Name = name +} + +type MyStruct2 struct { + Name string +} + +func (m MyStruct2) GetName() string { + return m.Name +} + +func (m *MyStruct2) SetName(name string) { + m.Name = name +} + +func NewMyStruct2() *MyStruct2 { // want `constructor "NewMyStruct2" for struct "MyStruct2" should be placed before struct method "GetName"` + return &MyStruct2{Name: "John"} +} + +func NewTime() time.Time { + return time.Now() +} diff --git a/pkg/golinters/funcorder/testdata/funcorder_disable_constructor.go b/pkg/golinters/funcorder/testdata/funcorder_disable_constructor.go new file mode 100644 index 000000000000..d131d5dee356 --- /dev/null +++ b/pkg/golinters/funcorder/testdata/funcorder_disable_constructor.go @@ -0,0 +1,41 @@ +//golangcitest:args -Efuncorder +//golangcitest:config_path testdata/funcorder_disable_constructor.yml +package testdata + +import "time" + +type MyStruct struct { + Name string +} + +func (m MyStruct) lenName() int { // want `unexported method "lenName" for struct "MyStruct" should be placed after the exported method "SetName"` + return len(m.Name) +} + +func (m MyStruct) GetName() string { + return m.Name +} + +func (m *MyStruct) SetName(name string) { + m.Name = name +} + +type MyStruct2 struct { + Name string +} + +func (m MyStruct2) GetName() string { + return m.Name +} + +func (m *MyStruct2) SetName(name string) { + m.Name = name +} + +func NewMyStruct2() *MyStruct2 { + return &MyStruct2{Name: "John"} +} + +func NewTime() time.Time { + return time.Now() +} diff --git a/pkg/golinters/funcorder/testdata/funcorder_disable_constructor.yml b/pkg/golinters/funcorder/testdata/funcorder_disable_constructor.yml new file mode 100644 index 000000000000..df43fb02f4d4 --- /dev/null +++ b/pkg/golinters/funcorder/testdata/funcorder_disable_constructor.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + funcorder: + constructor: false diff --git a/pkg/golinters/funcorder/testdata/funcorder_struct_method.go b/pkg/golinters/funcorder/testdata/funcorder_struct_method.go new file mode 100644 index 000000000000..a44f980e8b9e --- /dev/null +++ b/pkg/golinters/funcorder/testdata/funcorder_struct_method.go @@ -0,0 +1,41 @@ +//golangcitest:args -Efuncorder +//golangcitest:config_path testdata/funcorder_struct_method.yml +package testdata + +import "time" + +type MyStruct struct { + Name string +} + +func (m MyStruct) lenName() int { + return len(m.Name) +} + +func (m MyStruct) GetName() string { + return m.Name +} + +func (m *MyStruct) SetName(name string) { + m.Name = name +} + +type MyStruct2 struct { + Name string +} + +func (m MyStruct2) GetName() string { + return m.Name +} + +func (m *MyStruct2) SetName(name string) { + m.Name = name +} + +func NewMyStruct2() *MyStruct2 { // want `constructor "NewMyStruct2" for struct "MyStruct2" should be placed before struct method "GetName"` + return &MyStruct2{Name: "John"} +} + +func NewTime() time.Time { + return time.Now() +} diff --git a/pkg/golinters/funcorder/testdata/funcorder_struct_method.yml b/pkg/golinters/funcorder/testdata/funcorder_struct_method.yml new file mode 100644 index 000000000000..70b27b44f9cd --- /dev/null +++ b/pkg/golinters/funcorder/testdata/funcorder_struct_method.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + funcorder: + struct-method: false diff --git a/pkg/golinters/funlen/funlen.go b/pkg/golinters/funlen/funlen.go index 541d4fd36041..6e0f93b51303 100644 --- a/pkg/golinters/funlen/funlen.go +++ b/pkg/golinters/funlen/funlen.go @@ -2,7 +2,6 @@ package funlen import ( "github.com/ultraware/funlen" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -22,12 +21,7 @@ func New(settings *config.FunlenSettings) *goanalysis.Linter { cfg.ignoreComments = settings.IgnoreComments } - a := funlen.NewAnalyzer(cfg.lineLimit, cfg.stmtLimit, cfg.ignoreComments) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(funlen.NewAnalyzer(cfg.lineLimit, cfg.stmtLimit, cfg.ignoreComments)). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/gci/gci.go b/pkg/golinters/gci/gci.go index 627a4e6849f2..4357a3b15fc1 100644 --- a/pkg/golinters/gci/gci.go +++ b/pkg/golinters/gci/gci.go @@ -1,8 +1,6 @@ package gci import ( - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" "github.com/golangci/golangci-lint/v2/pkg/goformatters" @@ -18,16 +16,13 @@ func New(settings *config.GciSettings) *goanalysis.Linter { internal.LinterLogger.Fatalf("%s: create analyzer: %v", linterName, err) } - a := goformatters.NewAnalyzer( - internal.LinterLogger.Child(linterName), - "Checks if code and import statements are formatted, with additional rules.", - formatter, - ) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(linterName), + "Check if code and import statements are formatted, with additional rules.", + formatter, + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/ginkgolinter/ginkgolinter.go b/pkg/golinters/ginkgolinter/ginkgolinter.go index f4521cdaf81f..519e968e5d8b 100644 --- a/pkg/golinters/ginkgolinter/ginkgolinter.go +++ b/pkg/golinters/ginkgolinter/ginkgolinter.go @@ -3,7 +3,6 @@ package ginkgolinter import ( "github.com/nunnatsa/ginkgolinter" "github.com/nunnatsa/ginkgolinter/types" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -29,12 +28,8 @@ func New(settings *config.GinkgoLinterSettings) *goanalysis.Linter { } } - a := ginkgolinter.NewAnalyzerWithConfig(cfg) - - return goanalysis.NewLinter( - a.Name, - "enforces standards of using ginkgo and gomega", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(ginkgolinter.NewAnalyzerWithConfig(cfg)). + WithDesc("enforces standards of using ginkgo and gomega"). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/ginkgolinter/testdata/go.mod b/pkg/golinters/ginkgolinter/testdata/go.mod index 90dc39e4cea8..078968acadbb 100644 --- a/pkg/golinters/ginkgolinter/testdata/go.mod +++ b/pkg/golinters/ginkgolinter/testdata/go.mod @@ -3,18 +3,19 @@ module ginkgolinter go 1.23.0 require ( - github.com/onsi/ginkgo/v2 v2.23.0 - github.com/onsi/gomega v1.36.2 + github.com/onsi/ginkgo/v2 v2.23.4 + github.com/onsi/gomega v1.37.0 ) require ( - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.30.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + golang.org/x/tools v0.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/golinters/ginkgolinter/testdata/go.sum b/pkg/golinters/ginkgolinter/testdata/go.sum index 724f093a7a0c..29f1ee9e9a59 100644 --- a/pkg/golinters/ginkgolinter/testdata/go.sum +++ b/pkg/golinters/ginkgolinter/testdata/go.sum @@ -1,32 +1,41 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ= -github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go b/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go index 97534848d802..71f4be8c41db 100644 --- a/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go +++ b/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go @@ -2,18 +2,12 @@ package gocheckcompilerdirectives import ( "4d63.com/gocheckcompilerdirectives/checkcompilerdirectives" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := checkcompilerdirectives.Analyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(checkcompilerdirectives.Analyzer()). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/gochecknoglobals/gochecknoglobals.go b/pkg/golinters/gochecknoglobals/gochecknoglobals.go index 8d850a2de59f..2fd3f3c3bee1 100644 --- a/pkg/golinters/gochecknoglobals/gochecknoglobals.go +++ b/pkg/golinters/gochecknoglobals/gochecknoglobals.go @@ -2,18 +2,13 @@ package gochecknoglobals import ( "4d63.com/gochecknoglobals/checknoglobals" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := checknoglobals.Analyzer() - - return goanalysis.NewLinter( - a.Name, - "Check that no global variables exist.", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(checknoglobals.Analyzer()). + WithDesc("Check that no global variables exist."). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/gochecknoinits/gochecknoinits.go b/pkg/golinters/gochecknoinits/gochecknoinits.go index b5fa6f0d4117..9158ee07da55 100644 --- a/pkg/golinters/gochecknoinits/gochecknoinits.go +++ b/pkg/golinters/gochecknoinits/gochecknoinits.go @@ -11,22 +11,15 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) -const linterName = "gochecknoinits" - func New() *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: run, - Requires: []*analysis.Analyzer{inspect.Analyzer}, - } - - return goanalysis.NewLinter( - linterName, - "Checks that no init functions are present in Go code", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "gochecknoinits", + Doc: "Checks that no init functions are present in Go code", + Run: run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func run(pass *analysis.Pass) (any, error) { @@ -47,7 +40,7 @@ func run(pass *analysis.Pass) (any, error) { fnName := funcDecl.Name.Name if fnName == "init" && funcDecl.Recv.NumFields() == 0 { - pass.Reportf(funcDecl.Pos(), "don't use %s function", internal.FormatCode(fnName, nil)) + pass.Reportf(funcDecl.Pos(), "don't use %s function", internal.FormatCode(fnName)) } }) diff --git a/pkg/golinters/gochecksumtype/gochecksumtype.go b/pkg/golinters/gochecksumtype/gochecksumtype.go index 78cbd574d20b..825975f14570 100644 --- a/pkg/golinters/gochecksumtype/gochecksumtype.go +++ b/pkg/golinters/gochecksumtype/gochecksumtype.go @@ -18,41 +18,37 @@ const linterName = "gochecksumtype" func New(settings *config.GoChecksumTypeSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: `Run exhaustiveness checks on Go "sum types"`, + Run: func(pass *analysis.Pass) (any, error) { + issues, err := runGoCheckSumType(pass, settings) + if err != nil { + return nil, err + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runGoCheckSumType(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - `Run exhaustiveness checks on Go "sum types"`, - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(_ *linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + }, + }). + WithIssuesReporter(func(_ *linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runGoCheckSumType(pass *analysis.Pass, settings *config.GoChecksumTypeSettings) ([]goanalysis.Issue, error) { - var resIssues []goanalysis.Issue +func runGoCheckSumType(pass *analysis.Pass, settings *config.GoChecksumTypeSettings) ([]*goanalysis.Issue, error) { + var resIssues []*goanalysis.Issue pkg := &packages.Package{ Fset: pass.Fset, diff --git a/pkg/golinters/gocognit/gocognit.go b/pkg/golinters/gocognit/gocognit.go index 689a70a12383..b17912c0a649 100644 --- a/pkg/golinters/gocognit/gocognit.go +++ b/pkg/golinters/gocognit/gocognit.go @@ -19,37 +19,33 @@ const linterName = "gocognit" func New(settings *config.GocognitSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue - analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runGocognit(pass, settings) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Computes and checks the cognitive complexity of functions", + Run: func(pass *analysis.Pass) (any, error) { + issues := runGocognit(pass, settings) - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + if len(issues) == 0 { + return nil, nil + } - return nil, nil - }, - } + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return goanalysis.NewLinter( - linterName, - "Computes and checks the cognitive complexity of functions", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } -func runGocognit(pass *analysis.Pass, settings *config.GocognitSettings) []goanalysis.Issue { +func runGocognit(pass *analysis.Pass, settings *config.GocognitSettings) []*goanalysis.Issue { var stats []gocognit.Stat for _, f := range pass.Files { stats = gocognit.ComplexityStats(f, pass.Fset, stats) @@ -62,7 +58,7 @@ func runGocognit(pass *analysis.Pass, settings *config.GocognitSettings) []goana return stats[i].Complexity > stats[j].Complexity }) - issues := make([]goanalysis.Issue, 0, len(stats)) + issues := make([]*goanalysis.Issue, 0, len(stats)) for _, s := range stats { if s.Complexity <= settings.MinComplexity { break // Break as the stats is already sorted from greatest to least @@ -71,7 +67,7 @@ func runGocognit(pass *analysis.Pass, settings *config.GocognitSettings) []goana issues = append(issues, goanalysis.NewIssue(&result.Issue{ Pos: s.Pos, Text: fmt.Sprintf("cognitive complexity %d of func %s is high (> %d)", - s.Complexity, internal.FormatCode(s.FuncName, nil), settings.MinComplexity), + s.Complexity, internal.FormatCode(s.FuncName), settings.MinComplexity), FromLinter: linterName, }, pass)) } diff --git a/pkg/golinters/goconst/goconst.go b/pkg/golinters/goconst/goconst.go index 26196f6929d6..b58d860c6eda 100644 --- a/pkg/golinters/goconst/goconst.go +++ b/pkg/golinters/goconst/goconst.go @@ -18,49 +18,47 @@ const linterName = "goconst" func New(settings *config.GoConstSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runGoconst(pass, settings) - if err != nil { - return nil, err - } + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Finds repeated strings that could be replaced by a constant", + Run: func(pass *analysis.Pass) (any, error) { + issues, err := runGoconst(pass, settings) + if err != nil { + return nil, err + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - if len(issues) == 0 { return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Finds repeated strings that could be replaced by a constant", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanalysis.Issue, error) { +func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]*goanalysis.Issue, error) { cfg := goconstAPI.Config{ - IgnoreStrings: settings.IgnoreStrings, - MatchWithConstants: settings.MatchWithConstants, - MinStringLength: settings.MinStringLen, - MinOccurrences: settings.MinOccurrencesCount, - ParseNumbers: settings.ParseNumbers, - NumberMin: settings.NumberMin, - NumberMax: settings.NumberMax, - ExcludeTypes: map[goconstAPI.Type]bool{}, + IgnoreStrings: settings.IgnoreStringValues, + MatchWithConstants: settings.MatchWithConstants, + MinStringLength: settings.MinStringLen, + MinOccurrences: settings.MinOccurrencesCount, + ParseNumbers: settings.ParseNumbers, + NumberMin: settings.NumberMin, + NumberMax: settings.NumberMax, + ExcludeTypes: map[goconstAPI.Type]bool{}, + FindDuplicates: settings.FindDuplicates, + EvalConstExpressions: settings.EvalConstExpressions, // Should be managed with `linters.exclusions.rules`. IgnoreTests: false, @@ -70,7 +68,7 @@ func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanal cfg.ExcludeTypes[goconstAPI.Call] = true } - lintIssues, err := goconstAPI.Run(pass.Files, pass.Fset, &cfg) + lintIssues, err := goconstAPI.Run(pass.Files, pass.Fset, pass.TypesInfo, &cfg) if err != nil { return nil, err } @@ -79,18 +77,33 @@ func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanal return nil, nil } - res := make([]goanalysis.Issue, 0, len(lintIssues)) - for _, i := range lintIssues { - text := fmt.Sprintf("string %s has %d occurrences", internal.FormatCode(i.Str, nil), i.OccurrencesCount) + res := make([]*goanalysis.Issue, 0, len(lintIssues)) + for i := range lintIssues { + issue := &lintIssues[i] + + var text string + + switch { + case issue.OccurrencesCount > 0: + text = fmt.Sprintf("string %s has %d occurrences", internal.FormatCode(issue.Str), issue.OccurrencesCount) + + if issue.MatchingConst == "" { + text += ", make it a constant" + } else { + text += fmt.Sprintf(", but such constant %s already exists", internal.FormatCode(issue.MatchingConst)) + } + + case issue.DuplicateConst != "": + text = fmt.Sprintf("This constant is a duplicate of %s at %s", + internal.FormatCode(issue.DuplicateConst), + issue.DuplicatePos.String()) - if i.MatchingConst == "" { - text += ", make it a constant" - } else { - text += fmt.Sprintf(", but such constant %s already exists", internal.FormatCode(i.MatchingConst, nil)) + default: + continue } res = append(res, goanalysis.NewIssue(&result.Issue{ - Pos: i.Pos, + Pos: issue.Pos, Text: text, FromLinter: linterName, }, pass)) diff --git a/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go new file mode 100644 index 000000000000..64a4c3e119eb --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.go @@ -0,0 +1,25 @@ +//golangcitest:args -Egoconst +//golangcitest:config_path testdata/goconst_eval_and_find_duplicates.yml +package testdata + +import "fmt" + +const ( + envPrefix = "FOO_" + EnvUser = envPrefix + "USER" + EnvPassword = envPrefix + "PASSWORD" +) + +const EnvUserFull = "FOO_USER" // want "This constant is a duplicate of `EnvUser` at .*goconst_eval_and_find_duplicates.go:9:16" + +const KiB = 1 << 10 + +func _() { + fmt.Println(envPrefix, EnvUser, EnvPassword, EnvUserFull) + + const kilobytes = 1024 // want "This constant is a duplicate of `KiB` at .*goconst_eval_and_find_duplicates.go:15:13" + fmt.Println(kilobytes) + + kib := 1024 + fmt.Println(kib) +} diff --git a/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.yml b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.yml new file mode 100644 index 000000000000..445d6b77263d --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_and_find_duplicates.yml @@ -0,0 +1,8 @@ +version: "2" + +linters: + settings: + goconst: + find-duplicates: true + eval-const-expressions: true + numbers: true diff --git a/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.go b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.go new file mode 100644 index 000000000000..4cc272945b43 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.go @@ -0,0 +1,29 @@ +//golangcitest:args -Egoconst +//golangcitest:config_path testdata/goconst_eval_const_expressions.yml +package testdata + +const ( + prefix = "example.com/" + API = prefix + "api" + Web = prefix + "web" +) + +const Full = "example.com/api" + +func _() { + a0 := "example.com/api" // want "string `example.com/api` has 3 occurrences, but such constant `API` already exists" + a1 := "example.com/api" + a2 := "example.com/api" + + _ = a0 + _ = a1 + _ = a2 + + b0 := "example.com/web" // want "string `example.com/web` has 3 occurrences, but such constant `Web` already exists" + b1 := "example.com/web" + b2 := "example.com/web" + + _ = b0 + _ = b1 + _ = b2 +} diff --git a/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.yml b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.yml new file mode 100644 index 000000000000..7c2303aef7d8 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_eval_const_expressions.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + goconst: + eval-const-expressions: true diff --git a/pkg/golinters/goconst/testdata/goconst_find_duplicates.go b/pkg/golinters/goconst/testdata/goconst_find_duplicates.go new file mode 100644 index 000000000000..a1605cfe6358 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_find_duplicates.go @@ -0,0 +1,29 @@ +//golangcitest:args -Egoconst +//golangcitest:config_path testdata/goconst_find_duplicates.yml +package testdata + +const SingleConst = "single constant" + +const ( + GroupedConst1 = "grouped constant" + GroupedConst2 = "another grouped" +) + +const ( + GroupedDuplicateConst1 = "grouped duplicate value" + GroupedDuplicateConst2 = "grouped duplicate value" // want "This constant is a duplicate of `GroupedDuplicateConst1` at .*goconst_find_duplicates.go:13:2" +) + +const DuplicateConst1 = "duplicate value" + +const DuplicateConst2 = "duplicate value" // want "This constant is a duplicate of `DuplicateConst1` at .*goconst_find_duplicates.go:17:7" + +const ( + SpecialDuplicateConst1 = "special\nvalue\twith\rchars" + SpecialDuplicateConst2 = "special\nvalue\twith\rchars" // want "This constant is a duplicate of `SpecialDuplicateConst1` at .*goconst_find_duplicates.go:22:2" +) + +func _() { + const DuplicateScopedConst1 = "duplicate scoped value" + const DuplicateScopedConst2 = "duplicate scoped value" // want "This constant is a duplicate of `DuplicateScopedConst1` at .*goconst_find_duplicates.go:27:8" +} diff --git a/pkg/golinters/goconst/testdata/goconst_find_duplicates.yml b/pkg/golinters/goconst/testdata/goconst_find_duplicates.yml new file mode 100644 index 000000000000..8a64450696e7 --- /dev/null +++ b/pkg/golinters/goconst/testdata/goconst_find_duplicates.yml @@ -0,0 +1,6 @@ +version: "2" + +linters: + settings: + goconst: + find-duplicates: true diff --git a/pkg/golinters/gocritic/gocritic.go b/pkg/golinters/gocritic/gocritic.go index 4fcd9b124385..cd7337590cfd 100644 --- a/pkg/golinters/gocritic/gocritic.go +++ b/pkg/golinters/gocritic/gocritic.go @@ -5,8 +5,6 @@ import ( "fmt" "go/ast" "go/types" - "maps" - "reflect" "runtime" "slices" "strings" @@ -19,7 +17,6 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" - "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" "github.com/golangci/golangci-lint/v2/pkg/lint/linter" "github.com/golangci/golangci-lint/v2/pkg/logutils" ) @@ -31,50 +28,39 @@ var ( isDebug = logutils.HaveDebugTag(logutils.DebugKeyGoCritic) ) -func New(settings *config.GoCriticSettings) *goanalysis.Linter { +func New(settings *config.GoCriticSettings, replacer *strings.Replacer) *goanalysis.Linter { wrapper := &goCriticWrapper{ sizes: types.SizesFor("gc", runtime.GOARCH), } - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - err := wrapper.run(pass) - if err != nil { - return nil, err - } - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - `Provides diagnostics that check for bugs, performance and style issues. + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: `Provides diagnostics that check for bugs, performance and style issues. Extensible without recompilation through dynamic rules. Dynamic rules are written declaratively with AST patterns, filters, report message and optional suggestion.`, - []*analysis.Analyzer{analyzer}, - nil, - ). + Run: func(pass *analysis.Pass) (any, error) { + err := wrapper.run(pass) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). WithContextSetter(func(context *linter.Context) { - wrapper.replacer = strings.NewReplacer( - internal.PlaceholderBasePath, context.Cfg.GetBasePath(), - ) - - wrapper.init(context.Log, settings) + wrapper.init(context.Log, settings, replacer) }). WithLoadMode(goanalysis.LoadModeTypesInfo) } type goCriticWrapper struct { settingsWrapper *settingsWrapper - replacer *strings.Replacer sizes types.Sizes once sync.Once } -func (w *goCriticWrapper) init(logger logutils.Log, settings *config.GoCriticSettings) { +func (w *goCriticWrapper) init(logger logutils.Log, settings *config.GoCriticSettings, replacer *strings.Replacer) { if settings == nil { return } @@ -86,11 +72,9 @@ func (w *goCriticWrapper) init(logger logutils.Log, settings *config.GoCriticSet } }) - settingsWrapper := newSettingsWrapper(settings, logger) - settingsWrapper.InferEnabledChecks() - // Validate must be after InferEnabledChecks, not before. - // Because it uses gathered information about tags set and finally enabled checks. - if err := settingsWrapper.Validate(); err != nil { + settingsWrapper := newSettingsWrapper(logger, settings, replacer) + + if err := settingsWrapper.Load(); err != nil { logger.Fatalf("%s: invalid settings: %s", linterName, err) } @@ -113,7 +97,19 @@ func (w *goCriticWrapper) run(pass *analysis.Pass) error { linterCtx.SetPackageInfo(pass.TypesInfo, pass.Pkg) - runOnPackage(pass, enabledCheckers, pass.Files) + needFileInfo := slices.ContainsFunc(enabledCheckers, func(c *gocriticlinter.Checker) bool { + // Related to https://github.com/go-critic/go-critic/blob/440ff466685b41e67d231a1c4a8f5e093374ee93/checkers/importShadow_checker.go#L23 + return strings.EqualFold(c.Info.Name, "importShadow") + }) + + for _, f := range pass.Files { + if needFileInfo { + // Related to https://github.com/go-critic/go-critic/blob/440ff466685b41e67d231a1c4a8f5e093374ee93/checkers/importShadow_checker.go#L23 + linterCtx.SetFileInfo(f.Name.Name, f) + } + + runOnFile(pass, f, enabledCheckers) + } return nil } @@ -127,7 +123,8 @@ func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context continue } - if err := w.configureCheckerInfo(info, allLowerCasedParams); err != nil { + err := w.settingsWrapper.setCheckerParams(info, allLowerCasedParams) + if err != nil { return nil, err } @@ -142,65 +139,6 @@ func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context return enabledCheckers, nil } -func (w *goCriticWrapper) configureCheckerInfo( - info *gocriticlinter.CheckerInfo, - allLowerCasedParams map[string]config.GoCriticCheckSettings, -) error { - params := allLowerCasedParams[strings.ToLower(info.Name)] - if params == nil { // no config for this checker - return nil - } - - // To lowercase info param keys here because golangci-lint's config parser lowercases all strings. - infoParams := normalizeMap(info.Params) - for k, p := range params { - v, ok := infoParams[k] - if ok { - v.Value = w.normalizeCheckerParamsValue(p) - continue - } - - // param `k` isn't supported - if len(info.Params) == 0 { - return fmt.Errorf("checker %s config param %s doesn't exist: checker doesn't have params", - info.Name, k) - } - - supportedKeys := slices.Sorted(maps.Keys(info.Params)) - - return fmt.Errorf("checker %s config param %s doesn't exist, all existing: %s", - info.Name, k, supportedKeys) - } - - return nil -} - -// normalizeCheckerParamsValue normalizes value types. -// go-critic asserts that CheckerParam.Value has some specific types, -// but the file parsers (TOML, YAML, JSON) don't create the same representation for raw type. -// then we have to convert value types into the expected value types. -// Maybe in the future, this kind of conversion will be done in go-critic itself. -func (w *goCriticWrapper) normalizeCheckerParamsValue(p any) any { - rv := reflect.ValueOf(p) - switch rv.Type().Kind() { - case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: - return int(rv.Int()) - case reflect.Bool: - return rv.Bool() - case reflect.String: - // Perform variable substitution. - return w.replacer.Replace(rv.String()) - default: - return p - } -} - -func runOnPackage(pass *analysis.Pass, checks []*gocriticlinter.Checker, files []*ast.File) { - for _, f := range files { - runOnFile(pass, f, checks) - } -} - func runOnFile(pass *analysis.Pass, f *ast.File, checks []*gocriticlinter.Checker) { for _, c := range checks { // All checkers are expected to use *lint.Context @@ -226,335 +164,3 @@ func runOnFile(pass *analysis.Pass, f *ast.File, checks []*gocriticlinter.Checke } } } - -type goCriticChecks[T any] map[string]T - -func (m goCriticChecks[T]) has(name string) bool { - _, ok := m[name] - return ok -} - -type settingsWrapper struct { - *config.GoCriticSettings - - logger logutils.Log - - allCheckers []*gocriticlinter.CheckerInfo - - allChecks goCriticChecks[struct{}] - allChecksByTag goCriticChecks[[]string] - allTagsSorted []string - inferredEnabledChecks goCriticChecks[struct{}] - - // *LowerCased fields are used for GoCriticSettings.SettingsPerCheck validation only. - - allChecksLowerCased goCriticChecks[struct{}] - inferredEnabledChecksLowerCased goCriticChecks[struct{}] -} - -func newSettingsWrapper(settings *config.GoCriticSettings, logger logutils.Log) *settingsWrapper { - allCheckers := gocriticlinter.GetCheckersInfo() - - allChecks := make(goCriticChecks[struct{}], len(allCheckers)) - allChecksLowerCased := make(goCriticChecks[struct{}], len(allCheckers)) - allChecksByTag := make(goCriticChecks[[]string]) - for _, checker := range allCheckers { - allChecks[checker.Name] = struct{}{} - allChecksLowerCased[strings.ToLower(checker.Name)] = struct{}{} - - for _, tag := range checker.Tags { - allChecksByTag[tag] = append(allChecksByTag[tag], checker.Name) - } - } - - allTagsSorted := slices.Sorted(maps.Keys(allChecksByTag)) - - return &settingsWrapper{ - GoCriticSettings: settings, - logger: logger, - allCheckers: allCheckers, - allChecks: allChecks, - allChecksLowerCased: allChecksLowerCased, - allChecksByTag: allChecksByTag, - allTagsSorted: allTagsSorted, - inferredEnabledChecks: make(goCriticChecks[struct{}]), - inferredEnabledChecksLowerCased: make(goCriticChecks[struct{}]), - } -} - -func (s *settingsWrapper) IsCheckEnabled(name string) bool { - return s.inferredEnabledChecks.has(name) -} - -func (s *settingsWrapper) GetLowerCasedParams() map[string]config.GoCriticCheckSettings { - return normalizeMap(s.SettingsPerCheck) -} - -// InferEnabledChecks tries to be consistent with (lintersdb.Manager).build. -func (s *settingsWrapper) InferEnabledChecks() { - s.debugChecksInitialState() - - enabledByDefaultChecks, disabledByDefaultChecks := s.buildEnabledAndDisabledByDefaultChecks() - - debugChecksListf(enabledByDefaultChecks, "Enabled by default") - debugChecksListf(disabledByDefaultChecks, "Disabled by default") - - enabledChecks := make(goCriticChecks[struct{}]) - - if s.EnableAll { - enabledChecks = make(goCriticChecks[struct{}], len(s.allCheckers)) - for _, info := range s.allCheckers { - enabledChecks[info.Name] = struct{}{} - } - } else if !s.DisableAll { - // enable-all/disable-all revokes the default settings. - enabledChecks = make(goCriticChecks[struct{}], len(enabledByDefaultChecks)) - for _, check := range enabledByDefaultChecks { - enabledChecks[check] = struct{}{} - } - } - - if len(s.EnabledTags) != 0 { - enabledFromTags := s.expandTagsToChecks(s.EnabledTags) - - debugChecksListf(enabledFromTags, "Enabled by config tags %s", s.EnabledTags) - - for _, check := range enabledFromTags { - enabledChecks[check] = struct{}{} - } - } - - if len(s.EnabledChecks) != 0 { - debugChecksListf(s.EnabledChecks, "Enabled by config") - - for _, check := range s.EnabledChecks { - if enabledChecks.has(check) { - s.logger.Warnf("%s: no need to enable check %q: it's already enabled", linterName, check) - continue - } - enabledChecks[check] = struct{}{} - } - } - - if len(s.DisabledTags) != 0 { - disabledFromTags := s.expandTagsToChecks(s.DisabledTags) - - debugChecksListf(disabledFromTags, "Disabled by config tags %s", s.DisabledTags) - - for _, check := range disabledFromTags { - delete(enabledChecks, check) - } - } - - if len(s.DisabledChecks) != 0 { - debugChecksListf(s.DisabledChecks, "Disabled by config") - - for _, check := range s.DisabledChecks { - if !enabledChecks.has(check) { - s.logger.Warnf("%s: no need to disable check %q: it's already disabled", linterName, check) - continue - } - delete(enabledChecks, check) - } - } - - s.inferredEnabledChecks = enabledChecks - s.inferredEnabledChecksLowerCased = normalizeMap(s.inferredEnabledChecks) - - s.debugChecksFinalState() -} - -func (s *settingsWrapper) buildEnabledAndDisabledByDefaultChecks() (enabled, disabled []string) { - for _, info := range s.allCheckers { - if enabledByDef := isEnabledByDefaultGoCriticChecker(info); enabledByDef { - enabled = append(enabled, info.Name) - } else { - disabled = append(disabled, info.Name) - } - } - return enabled, disabled -} - -func (s *settingsWrapper) expandTagsToChecks(tags []string) []string { - var checks []string - for _, tag := range tags { - checks = append(checks, s.allChecksByTag[tag]...) - } - return checks -} - -func (s *settingsWrapper) debugChecksInitialState() { - if !isDebug { - return - } - - debugf("All gocritic existing tags and checks:") - for _, tag := range s.allTagsSorted { - debugChecksListf(s.allChecksByTag[tag], " tag %q", tag) - } -} - -func (s *settingsWrapper) debugChecksFinalState() { - if !isDebug { - return - } - - var enabledChecks []string - var disabledChecks []string - - for _, checker := range s.allCheckers { - check := checker.Name - if s.inferredEnabledChecks.has(check) { - enabledChecks = append(enabledChecks, check) - } else { - disabledChecks = append(disabledChecks, check) - } - } - - debugChecksListf(enabledChecks, "Final used") - - if len(disabledChecks) == 0 { - debugf("All checks are enabled") - } else { - debugChecksListf(disabledChecks, "Final not used") - } -} - -// Validate tries to be consistent with (lintersdb.Validator).validateEnabledDisabledLintersConfig. -func (s *settingsWrapper) Validate() error { - for _, v := range []func() error{ - s.validateOptionsCombinations, - s.validateCheckerTags, - s.validateCheckerNames, - s.validateDisabledAndEnabledAtOneMoment, - s.validateAtLeastOneCheckerEnabled, - } { - if err := v(); err != nil { - return err - } - } - return nil -} - -func (s *settingsWrapper) validateOptionsCombinations() error { - if s.EnableAll { - if s.DisableAll { - return errors.New("enable-all and disable-all options must not be combined") - } - - if len(s.EnabledTags) != 0 { - return errors.New("enable-all and enabled-tags options must not be combined") - } - - if len(s.EnabledChecks) != 0 { - return errors.New("enable-all and enabled-checks options must not be combined") - } - } - - if s.DisableAll { - if len(s.DisabledTags) != 0 { - return errors.New("disable-all and disabled-tags options must not be combined") - } - - if len(s.DisabledChecks) != 0 { - return errors.New("disable-all and disabled-checks options must not be combined") - } - - if len(s.EnabledTags) == 0 && len(s.EnabledChecks) == 0 { - return errors.New("all checks were disabled, but no one check was enabled: at least one must be enabled") - } - } - - return nil -} - -func (s *settingsWrapper) validateCheckerTags() error { - for _, tag := range s.EnabledTags { - if !s.allChecksByTag.has(tag) { - return fmt.Errorf("enabled tag %q doesn't exist, see %s's documentation", tag, linterName) - } - } - - for _, tag := range s.DisabledTags { - if !s.allChecksByTag.has(tag) { - return fmt.Errorf("disabled tag %q doesn't exist, see %s's documentation", tag, linterName) - } - } - - return nil -} - -func (s *settingsWrapper) validateCheckerNames() error { - for _, check := range s.EnabledChecks { - if !s.allChecks.has(check) { - return fmt.Errorf("enabled check %q doesn't exist, see %s's documentation", check, linterName) - } - } - - for _, check := range s.DisabledChecks { - if !s.allChecks.has(check) { - return fmt.Errorf("disabled check %q doesn't exist, see %s documentation", check, linterName) - } - } - - for check := range s.SettingsPerCheck { - lcName := strings.ToLower(check) - if !s.allChecksLowerCased.has(lcName) { - return fmt.Errorf("invalid check settings: check %q doesn't exist, see %s documentation", check, linterName) - } - if !s.inferredEnabledChecksLowerCased.has(lcName) { - s.logger.Warnf("%s: settings were provided for disabled check %q", check, linterName) - } - } - - return nil -} - -func (s *settingsWrapper) validateDisabledAndEnabledAtOneMoment() error { - for _, tag := range s.DisabledTags { - if slices.Contains(s.EnabledTags, tag) { - return fmt.Errorf("tag %q disabled and enabled at one moment", tag) - } - } - - for _, check := range s.DisabledChecks { - if slices.Contains(s.EnabledChecks, check) { - return fmt.Errorf("check %q disabled and enabled at one moment", check) - } - } - - return nil -} - -func (s *settingsWrapper) validateAtLeastOneCheckerEnabled() error { - if len(s.inferredEnabledChecks) == 0 { - return errors.New("eventually all checks were disabled: at least one must be enabled") - } - return nil -} - -func normalizeMap[ValueT any](in map[string]ValueT) map[string]ValueT { - ret := make(map[string]ValueT, len(in)) - for k, v := range in { - ret[strings.ToLower(k)] = v - } - return ret -} - -func isEnabledByDefaultGoCriticChecker(info *gocriticlinter.CheckerInfo) bool { - // https://github.com/go-critic/go-critic/blob/5b67cfd487ae9fe058b4b19321901b3131810f65/cmd/gocritic/check.go#L342-L345 - return !info.HasTag(gocriticlinter.ExperimentalTag) && - !info.HasTag(gocriticlinter.OpinionatedTag) && - !info.HasTag(gocriticlinter.PerformanceTag) && - !info.HasTag(gocriticlinter.SecurityTag) -} - -func debugChecksListf(checks []string, format string, args ...any) { - if !isDebug { - return - } - - v := slices.Sorted(slices.Values(checks)) - - debugf("%s checks (%d): %s", fmt.Sprintf(format, args...), len(checks), strings.Join(v, ", ")) -} diff --git a/pkg/golinters/gocritic/gocritic_settings.go b/pkg/golinters/gocritic/gocritic_settings.go new file mode 100644 index 000000000000..e3267eeec46b --- /dev/null +++ b/pkg/golinters/gocritic/gocritic_settings.go @@ -0,0 +1,431 @@ +package gocritic + +import ( + "errors" + "fmt" + "maps" + "reflect" + "slices" + "strings" + + gocriticlinter "github.com/go-critic/go-critic/linter" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type settingsWrapper struct { + *config.GoCriticSettings + + replacer *strings.Replacer + + logger logutils.Log + + allCheckers []*gocriticlinter.CheckerInfo + + allChecks goCriticChecks[struct{}] + allChecksByTag goCriticChecks[[]string] + allTagsSorted []string + inferredEnabledChecks goCriticChecks[struct{}] + + // *LowerCased fields are used for GoCriticSettings.SettingsPerCheck validation only. + + allChecksLowerCased goCriticChecks[struct{}] + inferredEnabledChecksLowerCased goCriticChecks[struct{}] +} + +func newSettingsWrapper(logger logutils.Log, settings *config.GoCriticSettings, replacer *strings.Replacer) *settingsWrapper { + allCheckers := gocriticlinter.GetCheckersInfo() + + allChecks := make(goCriticChecks[struct{}], len(allCheckers)) + allChecksLowerCased := make(goCriticChecks[struct{}], len(allCheckers)) + allChecksByTag := make(goCriticChecks[[]string]) + + for _, checker := range allCheckers { + allChecks[checker.Name] = struct{}{} + allChecksLowerCased[strings.ToLower(checker.Name)] = struct{}{} + + for _, tag := range checker.Tags { + allChecksByTag[tag] = append(allChecksByTag[tag], checker.Name) + } + } + + return &settingsWrapper{ + GoCriticSettings: settings, + replacer: replacer, + logger: logger, + + allCheckers: allCheckers, + allChecks: allChecks, + allChecksByTag: allChecksByTag, + allTagsSorted: slices.Sorted(maps.Keys(allChecksByTag)), + inferredEnabledChecks: make(goCriticChecks[struct{}]), + + allChecksLowerCased: allChecksLowerCased, + inferredEnabledChecksLowerCased: make(goCriticChecks[struct{}]), + } +} + +func (s *settingsWrapper) IsCheckEnabled(name string) bool { + return s.inferredEnabledChecks.has(name) +} + +func (s *settingsWrapper) GetLowerCasedParams() map[string]config.GoCriticCheckSettings { + return normalizeMap(s.SettingsPerCheck) +} + +func (s *settingsWrapper) Load() error { + s.inferEnabledChecks() + + // validate must be after inferEnabledChecks, not before. + // Because it uses gathered information about tags set and finally enabled checks. + return s.validate() +} + +func (s *settingsWrapper) inferEnabledChecks() { + s.debugChecksInitialState() + + enabledByDefaultChecks, disabledByDefaultChecks := s.buildEnabledAndDisabledByDefaultChecks() + + debugChecksListf(enabledByDefaultChecks, "Enabled by default") + debugChecksListf(disabledByDefaultChecks, "Disabled by default") + + var enabledChecks goCriticChecks[struct{}] + + switch { + case s.DisableAll: + // disable-all revokes the default settings. + enabledChecks = make(goCriticChecks[struct{}]) + + case s.EnableAll: + // enable-all revokes the default settings. + enabledChecks = make(goCriticChecks[struct{}], len(s.allCheckers)) + + for _, info := range s.allCheckers { + enabledChecks[info.Name] = struct{}{} + } + + default: + enabledChecks = make(goCriticChecks[struct{}], len(enabledByDefaultChecks)) + + for _, check := range enabledByDefaultChecks { + enabledChecks[check] = struct{}{} + } + } + + if len(s.EnabledTags) > 0 { + enabledFromTags := s.expandTagsToChecks(s.EnabledTags) + + debugChecksListf(enabledFromTags, "Enabled by config tags %s", s.EnabledTags) + + for _, check := range enabledFromTags { + enabledChecks[check] = struct{}{} + } + } + + if len(s.EnabledChecks) > 0 { + debugChecksListf(s.EnabledChecks, "Enabled by config") + + for _, check := range s.EnabledChecks { + if enabledChecks.has(check) { + s.logger.Warnf("%s: no need to enable check %q: it's already enabled", linterName, check) + continue + } + + enabledChecks[check] = struct{}{} + } + } + + if len(s.DisabledTags) > 0 { + disabledFromTags := s.expandTagsToChecks(s.DisabledTags) + + debugChecksListf(disabledFromTags, "Disabled by config tags %s", s.DisabledTags) + + for _, check := range disabledFromTags { + delete(enabledChecks, check) + } + } + + if len(s.DisabledChecks) > 0 { + debugChecksListf(s.DisabledChecks, "Disabled by config") + + for _, check := range s.DisabledChecks { + if !enabledChecks.has(check) { + s.logger.Warnf("%s: no need to disable check %q: it's already disabled", linterName, check) + continue + } + + delete(enabledChecks, check) + } + } + + s.inferredEnabledChecks = enabledChecks + s.inferredEnabledChecksLowerCased = normalizeMap(s.inferredEnabledChecks) + + s.debugChecksFinalState() +} + +func (s *settingsWrapper) buildEnabledAndDisabledByDefaultChecks() (enabled, disabled []string) { + for _, info := range s.allCheckers { + if isEnabledByDefaultGoCriticChecker(info) { + enabled = append(enabled, info.Name) + } else { + disabled = append(disabled, info.Name) + } + } + + return enabled, disabled +} + +func (s *settingsWrapper) expandTagsToChecks(tags []string) []string { + var checks []string + + for _, tag := range tags { + checks = append(checks, s.allChecksByTag[tag]...) + } + + return checks +} + +func (s *settingsWrapper) setCheckerParams( + info *gocriticlinter.CheckerInfo, + allLowerCasedParams map[string]config.GoCriticCheckSettings, +) error { + params := allLowerCasedParams[strings.ToLower(info.Name)] + if params == nil { // no config for this checker + return nil + } + + // To lowercase info param keys here because golangci-lint's config parser lowercases all strings. + infoParams := normalizeMap(info.Params) + for k, p := range params { + v, ok := infoParams[k] + if ok { + v.Value = s.normalizeCheckerParamsValue(p) + continue + } + + // param `k` isn't supported + if len(info.Params) == 0 { + return fmt.Errorf("checker %s config param %s doesn't exist: checker doesn't have params", + info.Name, k) + } + + return fmt.Errorf("checker %s config param %s doesn't exist, all existing: %s", + info.Name, k, slices.Sorted(maps.Keys(info.Params))) + } + + return nil +} + +func (s *settingsWrapper) debugChecksInitialState() { + if !isDebug { + return + } + + debugf("All gocritic existing tags and checks:") + + for _, tag := range s.allTagsSorted { + debugChecksListf(s.allChecksByTag[tag], " tag %q", tag) + } +} + +func (s *settingsWrapper) debugChecksFinalState() { + if !isDebug { + return + } + + var enabledChecks []string + var disabledChecks []string + + for _, checker := range s.allCheckers { + if s.IsCheckEnabled(checker.Name) { + enabledChecks = append(enabledChecks, checker.Name) + } else { + disabledChecks = append(disabledChecks, checker.Name) + } + } + + debugChecksListf(enabledChecks, "Final used") + + if len(disabledChecks) == 0 { + debugf("All checks are enabled") + } else { + debugChecksListf(disabledChecks, "Final not used") + } +} + +// normalizeCheckerParamsValue normalizes value types. +// go-critic asserts that CheckerParam.Value has some specific types, +// but the file parsers (TOML, YAML, JSON) don't create the same representation for raw type. +// then we have to convert value types into the expected value types. +// Maybe in the future, this kind of conversion will be done in go-critic itself. +func (s *settingsWrapper) normalizeCheckerParamsValue(p any) any { + rv := reflect.ValueOf(p) + + switch rv.Type().Kind() { + case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: + return int(rv.Int()) + + case reflect.Bool: + return rv.Bool() + + case reflect.String: + // Perform variable substitution. + return s.replacer.Replace(rv.String()) + + default: + return p + } +} + +// validate tries to be consistent with (lintersdb.Validator).validateEnabledDisabledLintersConfig. +func (s *settingsWrapper) validate() error { + for _, v := range []func() error{ + s.validateOptionsCombinations, + s.validateCheckerTags, + s.validateCheckerNames, + s.validateDisabledAndEnabledAtOneMoment, + s.validateAtLeastOneCheckerEnabled, + } { + if err := v(); err != nil { + return err + } + } + return nil +} + +func (s *settingsWrapper) validateOptionsCombinations() error { + if s.EnableAll && s.DisableAll { + return errors.New("enable-all and disable-all options must not be combined") + } + + switch { + case s.EnableAll: + if len(s.EnabledTags) > 0 { + return errors.New("enable-all and enabled-tags options must not be combined") + } + + if len(s.EnabledChecks) > 0 { + return errors.New("enable-all and enabled-checks options must not be combined") + } + + case s.DisableAll: + if len(s.DisabledTags) > 0 { + return errors.New("disable-all and disabled-tags options must not be combined") + } + + if len(s.DisabledChecks) > 0 { + return errors.New("disable-all and disabled-checks options must not be combined") + } + + if len(s.EnabledTags) == 0 && len(s.EnabledChecks) == 0 { + return errors.New("all checks were disabled, but no one check was enabled: at least one must be enabled") + } + } + + return nil +} + +func (s *settingsWrapper) validateCheckerTags() error { + for _, tag := range s.EnabledTags { + if !s.allChecksByTag.has(tag) { + return fmt.Errorf("enabled tag %q doesn't exist, see %s's documentation", tag, linterName) + } + } + + for _, tag := range s.DisabledTags { + if !s.allChecksByTag.has(tag) { + return fmt.Errorf("disabled tag %q doesn't exist, see %s's documentation", tag, linterName) + } + } + + return nil +} + +func (s *settingsWrapper) validateCheckerNames() error { + for _, check := range s.EnabledChecks { + if !s.allChecks.has(check) { + return fmt.Errorf("enabled check %q doesn't exist, see %s's documentation", check, linterName) + } + } + + for _, check := range s.DisabledChecks { + if !s.allChecks.has(check) { + return fmt.Errorf("disabled check %q doesn't exist, see %s documentation", check, linterName) + } + } + + for check := range s.SettingsPerCheck { + lcName := strings.ToLower(check) + + if !s.allChecksLowerCased.has(lcName) { + return fmt.Errorf("invalid check settings: check %q doesn't exist, see %s documentation", check, linterName) + } + + if !s.inferredEnabledChecksLowerCased.has(lcName) { + s.logger.Warnf("%s: settings were provided for disabled check %q", check, linterName) + } + } + + return nil +} + +func (s *settingsWrapper) validateDisabledAndEnabledAtOneMoment() error { + for _, tag := range s.DisabledTags { + if slices.Contains(s.EnabledTags, tag) { + return fmt.Errorf("tag %q disabled and enabled at one moment", tag) + } + } + + for _, check := range s.DisabledChecks { + if slices.Contains(s.EnabledChecks, check) { + return fmt.Errorf("check %q disabled and enabled at one moment", check) + } + } + + return nil +} + +func (s *settingsWrapper) validateAtLeastOneCheckerEnabled() error { + if len(s.inferredEnabledChecks) == 0 { + return errors.New("eventually all checks were disabled: at least one must be enabled") + } + + return nil +} + +type goCriticChecks[T any] map[string]T + +func (m goCriticChecks[T]) has(name string) bool { + _, ok := m[name] + return ok +} + +func debugChecksListf(checks []string, format string, args ...any) { + if !isDebug { + return + } + + v := slices.Sorted(slices.Values(checks)) + + debugf("%s checks (%d): %s", fmt.Sprintf(format, args...), len(checks), strings.Join(v, ", ")) +} + +func normalizeMap[ValueT any](in map[string]ValueT) map[string]ValueT { + ret := make(map[string]ValueT, len(in)) + + for k, v := range in { + ret[strings.ToLower(k)] = v + } + + return ret +} + +func isEnabledByDefaultGoCriticChecker(info *gocriticlinter.CheckerInfo) bool { + // https://github.com/go-critic/go-critic/blob/5b67cfd487ae9fe058b4b19321901b3131810f65/cmd/gocritic/check.go#L342-L345 + return !info.HasTag(gocriticlinter.ExperimentalTag) && + !info.HasTag(gocriticlinter.OpinionatedTag) && + !info.HasTag(gocriticlinter.PerformanceTag) && + !info.HasTag(gocriticlinter.SecurityTag) +} diff --git a/pkg/golinters/gocritic/gocritic_test.go b/pkg/golinters/gocritic/gocritic_settings_test.go similarity index 61% rename from pkg/golinters/gocritic/gocritic_test.go rename to pkg/golinters/gocritic/gocritic_settings_test.go index b742afc9de53..cbb26922c27f 100644 --- a/pkg/golinters/gocritic/gocritic_test.go +++ b/pkg/golinters/gocritic/gocritic_settings_test.go @@ -16,14 +16,15 @@ import ( ) // https://go-critic.com/overview.html -func Test_settingsWrapper_InferEnabledChecks(t *testing.T) { +func Test_settingsWrapper_inferEnabledChecks(t *testing.T) { err := checkers.InitEmbeddedRules() require.NoError(t, err) allCheckersInfo := gocriticlinter.GetCheckersInfo() - allChecksByTag := make(map[string][]string) - allChecks := make([]string, 0, len(allCheckersInfo)) + allChecksByTag := make(map[string]Slicer) + allChecks := make(Slicer, 0, len(allCheckersInfo)) + for _, checker := range allCheckersInfo { allChecks = append(allChecks, checker.Name) for _, tag := range checker.Tags { @@ -31,169 +32,160 @@ func Test_settingsWrapper_InferEnabledChecks(t *testing.T) { } } - enabledByDefaultChecks := make([]string, 0, len(allCheckersInfo)) + enabledByDefaultChecks := make(Slicer, 0, len(allCheckersInfo)) + for _, info := range allCheckersInfo { if isEnabledByDefaultGoCriticChecker(info) { enabledByDefaultChecks = append(enabledByDefaultChecks, info.Name) } } - t.Logf("enabled by default checks:\n%s", strings.Join(enabledByDefaultChecks, "\n")) - insert := func(in []string, toInsert ...string) []string { - return slices.Concat(in, toInsert) - } - - remove := func(in []string, toRemove ...string) []string { - result := slices.Clone(in) - for _, v := range toRemove { - if i := slices.Index(result, v); i != -1 { - result = slices.Delete(result, i, i+1) - } - } - return result - } - - uniq := func(in []string) []string { - return slices.Compact(slices.Sorted(slices.Values(in))) - } + t.Logf("enabled by default checks:\n%s", strings.Join(enabledByDefaultChecks, "\n")) - cases := []struct { + testCases := []struct { name string - sett *config.GoCriticSettings + settings *config.GoCriticSettings expectedEnabledChecks []string }{ { name: "no configuration", - sett: &config.GoCriticSettings{}, + settings: &config.GoCriticSettings{}, expectedEnabledChecks: enabledByDefaultChecks, }, { name: "enable checks", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"assignOp", "badCall", "emptyDecl"}, }, - expectedEnabledChecks: insert(enabledByDefaultChecks, "emptyDecl"), + expectedEnabledChecks: enabledByDefaultChecks.add("emptyDecl"), }, { name: "disable checks", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledChecks: []string{"assignOp", "emptyDecl"}, }, - expectedEnabledChecks: remove(enabledByDefaultChecks, "assignOp"), + expectedEnabledChecks: enabledByDefaultChecks.remove("assignOp"), }, { name: "enable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledTags: []string{"style", "experimental"}, }, - expectedEnabledChecks: uniq(insert(insert( - enabledByDefaultChecks, - allChecksByTag["style"]...), - allChecksByTag["experimental"]...)), + expectedEnabledChecks: enabledByDefaultChecks. + add(allChecksByTag["style"]...). + add(allChecksByTag["experimental"]...). + uniq(), }, { name: "disable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledTags: []string{"diagnostic"}, }, - expectedEnabledChecks: remove(enabledByDefaultChecks, allChecksByTag["diagnostic"]...), + expectedEnabledChecks: enabledByDefaultChecks.remove(allChecksByTag["diagnostic"]...), }, { name: "enable checks disable checks", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"badCall", "badLock"}, DisabledChecks: []string{"assignOp", "badSorting"}, }, - expectedEnabledChecks: insert(remove(enabledByDefaultChecks, "assignOp"), "badLock"), + expectedEnabledChecks: enabledByDefaultChecks. + remove("assignOp"). + add("badLock"), }, { name: "enable checks enable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"badCall", "badLock", "hugeParam"}, EnabledTags: []string{"diagnostic"}, }, - expectedEnabledChecks: uniq(insert(insert(enabledByDefaultChecks, - allChecksByTag["diagnostic"]...), - "hugeParam")), + expectedEnabledChecks: enabledByDefaultChecks. + add(allChecksByTag["diagnostic"]...). + add("hugeParam"). + uniq(), }, { name: "enable checks disable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"badCall", "badLock", "boolExprSimplify", "hugeParam"}, DisabledTags: []string{"style", "diagnostic"}, }, - expectedEnabledChecks: insert(remove(remove(enabledByDefaultChecks, - allChecksByTag["style"]...), - allChecksByTag["diagnostic"]...), - "hugeParam"), + expectedEnabledChecks: enabledByDefaultChecks. + remove(allChecksByTag["style"]...). + remove(allChecksByTag["diagnostic"]...). + add("hugeParam"), }, { name: "enable all checks via tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledTags: []string{"diagnostic", "experimental", "opinionated", "performance", "style"}, }, expectedEnabledChecks: allChecks, }, { name: "disable checks enable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledChecks: []string{"assignOp", "badCall", "badLock", "hugeParam"}, EnabledTags: []string{"style", "diagnostic"}, }, - expectedEnabledChecks: remove(uniq(insert(insert(enabledByDefaultChecks, - allChecksByTag["style"]...), - allChecksByTag["diagnostic"]...)), - "assignOp", "badCall", "badLock"), + expectedEnabledChecks: enabledByDefaultChecks. + add(allChecksByTag["style"]...). + add(allChecksByTag["diagnostic"]...). + uniq(). + remove("assignOp", "badCall", "badLock"), }, { name: "disable checks disable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledChecks: []string{"badCall", "badLock", "codegenComment", "hugeParam"}, DisabledTags: []string{"style"}, }, - expectedEnabledChecks: remove(remove(enabledByDefaultChecks, - allChecksByTag["style"]...), - "badCall", "codegenComment"), + expectedEnabledChecks: enabledByDefaultChecks. + remove(allChecksByTag["style"]...). + remove("badCall", "codegenComment"), }, { name: "enable tags disable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledTags: []string{"experimental"}, DisabledTags: []string{"style"}, }, - expectedEnabledChecks: remove(uniq(insert(enabledByDefaultChecks, - allChecksByTag["experimental"]...)), - allChecksByTag["style"]...), + expectedEnabledChecks: enabledByDefaultChecks. + add(allChecksByTag["experimental"]...). + uniq(). + remove(allChecksByTag["style"]...), }, { name: "enable checks disable checks enable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"badCall", "badLock", "boolExprSimplify", "indexAlloc", "hugeParam"}, DisabledChecks: []string{"deprecatedComment", "typeSwitchVar"}, EnabledTags: []string{"experimental"}, }, - expectedEnabledChecks: remove(uniq(insert(insert(enabledByDefaultChecks, - allChecksByTag["experimental"]...), - "indexAlloc", "hugeParam")), - "deprecatedComment", "typeSwitchVar"), + expectedEnabledChecks: enabledByDefaultChecks. + add(allChecksByTag["experimental"]...). + add("indexAlloc", "hugeParam"). + uniq(). + remove("deprecatedComment", "typeSwitchVar"), }, { name: "enable checks disable checks enable tags disable tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"badCall", "badCond", "badLock", "indexAlloc", "hugeParam"}, DisabledChecks: []string{"deprecatedComment", "typeSwitchVar"}, EnabledTags: []string{"experimental"}, DisabledTags: []string{"performance"}, }, - expectedEnabledChecks: remove(remove(uniq(insert(insert(enabledByDefaultChecks, - allChecksByTag["experimental"]...), - "badCond")), - allChecksByTag["performance"]...), - "deprecatedComment", "typeSwitchVar"), + expectedEnabledChecks: enabledByDefaultChecks. + add(allChecksByTag["experimental"]...). + add("badCond"). + uniq(). + remove(allChecksByTag["performance"]...). + remove("deprecatedComment", "typeSwitchVar"), }, { name: "enable single tag only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisableAll: true, EnabledTags: []string{"experimental"}, }, @@ -201,31 +193,35 @@ func Test_settingsWrapper_InferEnabledChecks(t *testing.T) { }, { name: "enable two tags only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisableAll: true, EnabledTags: []string{"experimental", "performance"}, }, - expectedEnabledChecks: uniq(insert(allChecksByTag["experimental"], allChecksByTag["performance"]...)), + expectedEnabledChecks: allChecksByTag["experimental"]. + add(allChecksByTag["performance"]...). + uniq(), }, { name: "disable single tag only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, DisabledTags: []string{"style"}, }, - expectedEnabledChecks: remove(allChecks, allChecksByTag["style"]...), + expectedEnabledChecks: allChecks.remove(allChecksByTag["style"]...), }, { name: "disable two tags only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, DisabledTags: []string{"style", "diagnostic"}, }, - expectedEnabledChecks: remove(remove(allChecks, allChecksByTag["style"]...), allChecksByTag["diagnostic"]...), + expectedEnabledChecks: allChecks. + remove(allChecksByTag["style"]...). + remove(allChecksByTag["diagnostic"]...), }, { name: "enable some checks only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisableAll: true, EnabledChecks: []string{"deferInLoop", "dupImport", "ifElseChain", "mapKey"}, }, @@ -233,55 +229,60 @@ func Test_settingsWrapper_InferEnabledChecks(t *testing.T) { }, { name: "disable some checks only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, DisabledChecks: []string{"deferInLoop", "dupImport", "ifElseChain", "mapKey"}, }, - expectedEnabledChecks: remove(allChecks, "deferInLoop", "dupImport", "ifElseChain", "mapKey"), + expectedEnabledChecks: allChecks. + remove("deferInLoop", "dupImport", "ifElseChain", "mapKey"), }, { name: "enable single tag and some checks from another tag only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisableAll: true, EnabledTags: []string{"experimental"}, EnabledChecks: []string{"importShadow"}, }, - expectedEnabledChecks: insert(allChecksByTag["experimental"], "importShadow"), + expectedEnabledChecks: allChecksByTag["experimental"].add("importShadow"), }, { name: "disable single tag and some checks from another tag only", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, DisabledTags: []string{"experimental"}, DisabledChecks: []string{"importShadow"}, }, - expectedEnabledChecks: remove(remove(allChecks, allChecksByTag["experimental"]...), "importShadow"), + expectedEnabledChecks: allChecks. + remove(allChecksByTag["experimental"]...). + remove("importShadow"), }, } - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { t.Parallel() - lg := logutils.NewStderrLog("Test_goCriticSettingsWrapper_InferEnabledChecks") - wr := newSettingsWrapper(tt.sett, lg) + lg := logutils.NewStderrLog(t.Name()) + wr := newSettingsWrapper(lg, test.settings, nil) + + wr.inferEnabledChecks() + + assert.ElementsMatch(t, test.expectedEnabledChecks, slices.Collect(maps.Keys(wr.inferredEnabledChecks))) - wr.InferEnabledChecks() - assert.ElementsMatch(t, tt.expectedEnabledChecks, slices.Collect(maps.Keys(wr.inferredEnabledChecks))) - assert.NoError(t, wr.Validate()) + assert.NoError(t, wr.validate()) }) } } -func Test_settingsWrapper_Validate(t *testing.T) { - cases := []struct { +func Test_settingsWrapper_Load(t *testing.T) { + testCases := []struct { name string - sett *config.GoCriticSettings + settings *config.GoCriticSettings expectedErr bool }{ { name: "combine enable-all and disable-all", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, DisableAll: true, }, @@ -289,7 +290,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "combine enable-all and enabled-tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, EnabledTags: []string{"experimental"}, }, @@ -297,7 +298,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "combine enable-all and enabled-checks", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, EnabledChecks: []string{"dupImport"}, }, @@ -305,7 +306,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "combine disable-all and disabled-tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisableAll: true, DisabledTags: []string{"style"}, }, @@ -313,7 +314,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "combine disable-all and disable-checks", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisableAll: true, DisabledChecks: []string{"appendAssign"}, }, @@ -321,42 +322,42 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "disable-all and no one check enabled", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisableAll: true, }, expectedErr: true, }, { name: "unknown enabled tag", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledTags: []string{"diagnostic", "go-proverbs"}, }, expectedErr: true, }, { name: "unknown disabled tag", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledTags: []string{"style", "go-proverbs"}, }, expectedErr: true, }, { name: "unknown enabled check", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"appendAssign", "noExitAfterDefer", "underef"}, }, expectedErr: true, }, { name: "unknown disabled check", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledChecks: []string{"dupSubExpr", "noExitAfterDefer", "returnAfterHttpError"}, }, expectedErr: true, }, { name: "settings for unknown check", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ SettingsPerCheck: map[string]config.GoCriticCheckSettings{ "captLocall": {"paramsOnly": false}, "unnamedResult": {"checkExported": true}, @@ -366,7 +367,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "settings for disabled check", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledChecks: []string{"elseif"}, SettingsPerCheck: map[string]config.GoCriticCheckSettings{ "elseif": {"skipBalanced": true}, @@ -376,7 +377,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "settings by lower-cased checker name", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"tooManyResultsChecker"}, SettingsPerCheck: map[string]config.GoCriticCheckSettings{ "toomanyresultschecker": {"maxResults": 3}, @@ -387,7 +388,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "enabled and disabled at one moment check", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledChecks: []string{"appendAssign", "codegenComment", "underef"}, DisabledChecks: []string{"elseif", "underef"}, }, @@ -395,7 +396,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "enabled and disabled at one moment tag", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledTags: []string{"performance", "style"}, DisabledTags: []string{"style", "diagnostic"}, }, @@ -403,14 +404,14 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "disable all checks via tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ DisabledTags: []string{"diagnostic", "experimental", "opinionated", "performance", "style"}, }, expectedErr: true, }, { name: "enable-all and disable all checks via tags", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnableAll: true, DisabledTags: []string{"diagnostic", "experimental", "opinionated", "performance", "style"}, }, @@ -418,7 +419,7 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, { name: "valid configuration", - sett: &config.GoCriticSettings{ + settings: &config.GoCriticSettings{ EnabledTags: []string{"performance"}, DisabledChecks: []string{"dupImport", "ifElseChain", "octalLiteral", "whyNoLint"}, SettingsPerCheck: map[string]config.GoCriticCheckSettings{ @@ -430,17 +431,15 @@ func Test_settingsWrapper_Validate(t *testing.T) { }, } - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { t.Parallel() - lg := logutils.NewStderrLog("Test_goCriticSettingsWrapper_Validate") - wr := newSettingsWrapper(tt.sett, lg) + lg := logutils.NewStderrLog(t.Name()) + wr := newSettingsWrapper(lg, test.settings, nil) - wr.InferEnabledChecks() - - err := wr.Validate() - if tt.expectedErr { + err := wr.Load() + if test.expectedErr { if assert.Error(t, err) { t.Log(err) } @@ -450,3 +449,25 @@ func Test_settingsWrapper_Validate(t *testing.T) { }) } } + +type Slicer []string + +func (s Slicer) add(toAdd ...string) Slicer { + return slices.Concat(s, toAdd) +} + +func (s Slicer) remove(toRemove ...string) Slicer { + result := slices.Clone(s) + + for _, v := range toRemove { + if i := slices.Index(result, v); i != -1 { + result = slices.Delete(result, i, i+1) + } + } + + return result +} + +func (s Slicer) uniq() Slicer { + return slices.Compact(slices.Sorted(slices.Values(s))) +} diff --git a/pkg/golinters/gocritic/testdata/gocritic.yml b/pkg/golinters/gocritic/testdata/gocritic.yml index 5c90af7d6f78..e64cb2e54406 100644 --- a/pkg/golinters/gocritic/testdata/gocritic.yml +++ b/pkg/golinters/gocritic/testdata/gocritic.yml @@ -14,7 +14,7 @@ linters: sizeThreshold: 24 ruleguard: failOn: dsl,import - rules: '${base-path}/ruleguard/preferWriteString.go,${base-path}/ruleguard/stringsSimplify.go' + rules: '${base-path}/ruleguard/preferWriteString.go,${config-path}/ruleguard/stringsSimplify.go' run: relative-path-mode: cfg diff --git a/pkg/golinters/gocritic/testdata/gocritic_importShadow.go b/pkg/golinters/gocritic/testdata/gocritic_importShadow.go new file mode 100644 index 000000000000..5f0242ba5a99 --- /dev/null +++ b/pkg/golinters/gocritic/testdata/gocritic_importShadow.go @@ -0,0 +1,17 @@ +//golangcitest:args -Egocritic +//golangcitest:config_path testdata/gocritic_inportShadow.yml +package testdata + +import ( + "fmt" + "path/filepath" +) + +func Bar() { + filepath.Join("a", "b") +} + +func foo() { + filepath := "foo.txt" // want "importShadow: shadow of imported package 'filepath'" + fmt.Printf("File path: %s\n", filepath) +} diff --git a/pkg/golinters/gocritic/testdata/gocritic_inportShadow.yml b/pkg/golinters/gocritic/testdata/gocritic_inportShadow.yml new file mode 100644 index 000000000000..14a2192e72b9 --- /dev/null +++ b/pkg/golinters/gocritic/testdata/gocritic_inportShadow.yml @@ -0,0 +1,8 @@ +version: "2" + +linters: + settings: + gocritic: + disable-all: true + enabled-checks: + - importShadow diff --git a/pkg/golinters/gocyclo/gocyclo.go b/pkg/golinters/gocyclo/gocyclo.go index 05691695d2aa..de0374607c06 100644 --- a/pkg/golinters/gocyclo/gocyclo.go +++ b/pkg/golinters/gocyclo/gocyclo.go @@ -18,37 +18,33 @@ const linterName = "gocyclo" func New(settings *config.GoCycloSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runGoCyclo(pass, settings) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Computes and checks the cyclomatic complexity of functions", + Run: func(pass *analysis.Pass) (any, error) { + issues := runGoCyclo(pass, settings) - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + if len(issues) == 0 { + return nil, nil + } - return nil, nil - }, - } + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return goanalysis.NewLinter( - linterName, - "Computes and checks the cyclomatic complexity of functions", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } -func runGoCyclo(pass *analysis.Pass, settings *config.GoCycloSettings) []goanalysis.Issue { +func runGoCyclo(pass *analysis.Pass, settings *config.GoCycloSettings) []*goanalysis.Issue { var stats gocyclo.Stats for _, f := range pass.Files { stats = gocyclo.AnalyzeASTFile(f, pass.Fset, stats) @@ -59,11 +55,11 @@ func runGoCyclo(pass *analysis.Pass, settings *config.GoCycloSettings) []goanaly stats = stats.SortAndFilter(-1, settings.MinComplexity) - issues := make([]goanalysis.Issue, 0, len(stats)) + issues := make([]*goanalysis.Issue, 0, len(stats)) for _, s := range stats { text := fmt.Sprintf("cyclomatic complexity %d of func %s is high (> %d)", - s.Complexity, internal.FormatCode(s.FuncName, nil), settings.MinComplexity) + s.Complexity, internal.FormatCode(s.FuncName), settings.MinComplexity) issues = append(issues, goanalysis.NewIssue(&result.Issue{ Pos: s.Pos, diff --git a/pkg/golinters/godot/godot.go b/pkg/golinters/godot/godot.go index 04e86211de33..e83495128e4c 100644 --- a/pkg/golinters/godot/godot.go +++ b/pkg/golinters/godot/godot.go @@ -10,8 +10,6 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -const linterName = "godot" - func New(settings *config.GodotSettings) *goanalysis.Linter { var dotSettings godot.Settings @@ -26,25 +24,20 @@ func New(settings *config.GodotSettings) *goanalysis.Linter { dotSettings.Scope = cmp.Or(dotSettings.Scope, godot.DeclScope) - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - err := runGodot(pass, dotSettings) - if err != nil { - return nil, err - } - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Check if comments end in a period", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "godot", + Doc: "Check if comments end in a period", + Run: func(pass *analysis.Pass) (any, error) { + err := runGodot(pass, dotSettings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func runGodot(pass *analysis.Pass, settings godot.Settings) error { diff --git a/pkg/golinters/godot/testdata/fix/in/godot.go b/pkg/golinters/godot/testdata/fix/in/godot.go index 13b8da1c0ea9..d662c7ca53de 100644 --- a/pkg/golinters/godot/testdata/fix/in/godot.go +++ b/pkg/golinters/godot/testdata/fix/in/godot.go @@ -11,3 +11,10 @@ func godot(a, b int) int { // Nothing to do here return a + b } + +// Foo Lorem ipsum dolor sit amet, consectetur adipiscing elit. +// Aenean rhoncus odio enim, et pulvinar libero ultrices quis. +// Nulla at erat tellus. Maecenas id dapibus velit, ut porttitor ipsum +func Foo() { + // nothing to do here +} diff --git a/pkg/golinters/godot/testdata/fix/out/godot.go b/pkg/golinters/godot/testdata/fix/out/godot.go index 6960f06c044c..11d633e280c1 100644 --- a/pkg/golinters/godot/testdata/fix/out/godot.go +++ b/pkg/golinters/godot/testdata/fix/out/godot.go @@ -11,3 +11,10 @@ func godot(a, b int) int { // Nothing to do here return a + b } + +// Foo Lorem ipsum dolor sit amet, consectetur adipiscing elit. +// Aenean rhoncus odio enim, et pulvinar libero ultrices quis. +// Nulla at erat tellus. Maecenas id dapibus velit, ut porttitor ipsum. +func Foo() { + // nothing to do here +} diff --git a/pkg/golinters/godot/testdata/godot.go b/pkg/golinters/godot/testdata/godot.go index 93a904894691..c81134687b2a 100644 --- a/pkg/golinters/godot/testdata/godot.go +++ b/pkg/golinters/godot/testdata/godot.go @@ -7,3 +7,12 @@ package testdata func Godot() { // nothing to do here } + +// want +4 "Comment should end in a period" + +// Foo Lorem ipsum dolor sit amet, consectetur adipiscing elit. +// Aenean rhoncus odio enim, et pulvinar libero ultrices quis. +// Nulla at erat tellus. Maecenas id dapibus velit, ut porttitor ipsum +func Foo() { + // nothing to do here +} diff --git a/pkg/golinters/godox/godox.go b/pkg/golinters/godox/godox.go index e734c691b3da..8ab144e754a1 100644 --- a/pkg/golinters/godox/godox.go +++ b/pkg/golinters/godox/godox.go @@ -11,23 +11,16 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -const linterName = "godox" - func New(settings *config.GodoxSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - return run(pass, settings), nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Detects usage of FIXME, TODO and other keywords inside comments", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "godox", + Doc: "Detects usage of FIXME, TODO and other keywords inside comments", + Run: func(pass *analysis.Pass) (any, error) { + return run(pass, settings), nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func run(pass *analysis.Pass, settings *config.GodoxSettings) error { diff --git a/pkg/golinters/gofmt/gofmt.go b/pkg/golinters/gofmt/gofmt.go index 63b690018ecd..04de51efc0f1 100644 --- a/pkg/golinters/gofmt/gofmt.go +++ b/pkg/golinters/gofmt/gofmt.go @@ -1,8 +1,6 @@ package gofmt import ( - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" "github.com/golangci/golangci-lint/v2/pkg/goformatters" @@ -10,19 +8,14 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) -const linterName = "gofmt" - func New(settings *config.GoFmtSettings) *goanalysis.Linter { - a := goformatters.NewAnalyzer( - internal.LinterLogger.Child(linterName), - "Checks if the code is formatted according to 'gofmt' command.", - gofmtbase.New(settings), - ) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(gofmtbase.Name), + "Check if the code is formatted according to 'gofmt' command.", + gofmtbase.New(settings), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/gofumpt/gofumpt.go b/pkg/golinters/gofumpt/gofumpt.go index d799be7a39fd..1ee7c833a321 100644 --- a/pkg/golinters/gofumpt/gofumpt.go +++ b/pkg/golinters/gofumpt/gofumpt.go @@ -1,8 +1,6 @@ package gofumpt import ( - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" "github.com/golangci/golangci-lint/v2/pkg/goformatters" @@ -10,19 +8,14 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) -const linterName = "gofumpt" - func New(settings *config.GoFumptSettings) *goanalysis.Linter { - a := goformatters.NewAnalyzer( - internal.LinterLogger.Child(linterName), - "Checks if code and import statements are formatted, with additional rules.", - gofumptbase.New(settings, settings.LangVersion), - ) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(gofumptbase.Name), + "Check if code and import statements are formatted, with additional rules.", + gofumptbase.New(settings, settings.LangVersion), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/goheader/goheader.go b/pkg/golinters/goheader/goheader.go index 491e54a7819c..0634dbd4288f 100644 --- a/pkg/golinters/goheader/goheader.go +++ b/pkg/golinters/goheader/goheader.go @@ -9,40 +9,34 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" - "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) const linterName = "goheader" -func New(settings *config.GoHeaderSettings, basePath string) *goanalysis.Linter { +func New(settings *config.GoHeaderSettings, replacer *strings.Replacer) *goanalysis.Linter { conf := &goheader.Configuration{} if settings != nil { conf = &goheader.Configuration{ Values: settings.Values, Template: settings.Template, - TemplatePath: strings.ReplaceAll(settings.TemplatePath, internal.PlaceholderBasePath, basePath), + TemplatePath: replacer.Replace(settings.TemplatePath), } } - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - err := runGoHeader(pass, conf) - if err != nil { - return nil, err - } - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Checks if file header matches to pattern", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Check if file header matches to pattern", + Run: func(pass *analysis.Pass) (any, error) { + err := runGoHeader(pass, conf) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func runGoHeader(pass *analysis.Pass, conf *goheader.Configuration) error { diff --git a/pkg/golinters/goimports/goimports.go b/pkg/golinters/goimports/goimports.go index 3aa8cde56a94..b3b9b5800b8d 100644 --- a/pkg/golinters/goimports/goimports.go +++ b/pkg/golinters/goimports/goimports.go @@ -1,8 +1,6 @@ package goimports import ( - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" "github.com/golangci/golangci-lint/v2/pkg/goformatters" @@ -10,19 +8,14 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) -const linterName = "goimports" - func New(settings *config.GoImportsSettings) *goanalysis.Linter { - a := goformatters.NewAnalyzer( - internal.LinterLogger.Child(linterName), - "Checks if the code and import statements are formatted according to the 'goimports' command.", - goimportsbase.New(settings), - ) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(goimportsbase.Name), + "Checks if the code and import statements are formatted according to the 'goimports' command.", + goimportsbase.New(settings), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/golines/golines.go b/pkg/golinters/golines/golines.go index 0b3acc53bb40..0a32971dee1d 100644 --- a/pkg/golinters/golines/golines.go +++ b/pkg/golinters/golines/golines.go @@ -1,8 +1,6 @@ package golines import ( - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" "github.com/golangci/golangci-lint/v2/pkg/goformatters" @@ -10,19 +8,14 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) -const linterName = "golines" - func New(settings *config.GoLinesSettings) *goanalysis.Linter { - a := goformatters.NewAnalyzer( - internal.LinterLogger.Child(linterName), - "Checks if code is formatted, and fixes long lines", - golinesbase.New(settings), - ) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(golinesbase.Name), + "Checks if code is formatted, and fixes long lines", + golinesbase.New(settings), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/gomoddirectives/gomoddirectives.go b/pkg/golinters/gomoddirectives/gomoddirectives.go index 86f94e2560ea..dd6656fb6cb6 100644 --- a/pkg/golinters/gomoddirectives/gomoddirectives.go +++ b/pkg/golinters/gomoddirectives/gomoddirectives.go @@ -17,7 +17,7 @@ import ( const linterName = "gomoddirectives" func New(settings *config.GoModDirectivesSettings) *goanalysis.Linter { - var issues []goanalysis.Issue + var issues []*goanalysis.Issue var once sync.Once var opts gomoddirectives.Options @@ -50,38 +50,37 @@ func New(settings *config.GoModDirectivesSettings) *goanalysis.Linter { } analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, + Name: linterName, + Doc: "Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.", Run: goanalysis.DummyRun, } - return goanalysis.NewLinter( - linterName, - "Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = func(pass *analysis.Pass) (any, error) { - once.Do(func() { - results, err := gomoddirectives.AnalyzePass(pass, opts) - if err != nil { - lintCtx.Log.Warnf("running %s failed: %s: "+ - "if you are not using go modules it is suggested to disable this linter", linterName, err) - return - } + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = func(pass *analysis.Pass) (any, error) { + once.Do(func() { + results, err := gomoddirectives.AnalyzePass(pass, opts) + if err != nil { + lintCtx.Log.Warnf("running %s failed: %s: "+ + "if you are not using go modules it is suggested to disable this linter", linterName, err) + return + } - for _, p := range results { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - FromLinter: linterName, - Pos: p.Start, - Text: p.Reason, - }, pass)) - } - }) + for _, p := range results { + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + FromLinter: linterName, + Pos: p.Start, + Text: p.Reason, + }, pass)) + } + }) - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return issues - }).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return issues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/gomodguard/gomodguard.go b/pkg/golinters/gomodguard/gomodguard.go index e38a6c9b90e4..7d16f57b3a5c 100644 --- a/pkg/golinters/gomodguard/gomodguard.go +++ b/pkg/golinters/gomodguard/gomodguard.go @@ -13,15 +13,10 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/result" ) -const ( - name = "gomodguard" - desc = "Allow and block list linter for direct Go module dependencies. " + - "This is different from depguard where there are different block " + - "types for example version constraints and module recommendations." -) +const linterName = "gomodguard" func New(settings *config.GoModGuardSettings) *goanalysis.Linter { - var issues []goanalysis.Issue + var issues []*goanalysis.Issue var mu sync.Mutex processorCfg := &gomodguard.Configuration{} @@ -54,41 +49,41 @@ func New(settings *config.GoModGuardSettings) *goanalysis.Linter { } analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, + Name: linterName, + Doc: "Allow and blocklist linter for direct Go module dependencies. " + + "This is different from depguard where there are different block " + + "types for example version constraints and module recommendations.", + Run: goanalysis.DummyRun, } - return goanalysis.NewLinter( - name, - desc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - processor, err := gomodguard.NewProcessor(processorCfg) - if err != nil { - lintCtx.Log.Warnf("running gomodguard failed: %s: if you are not using go modules "+ - "it is suggested to disable this linter", err) - return - } + return goanalysis.NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + processor, err := gomodguard.NewProcessor(processorCfg) + if err != nil { + lintCtx.Log.Warnf("running gomodguard failed: %s: if you are not using go modules "+ + "it is suggested to disable this linter", err) + return + } - analyzer.Run = func(pass *analysis.Pass) (any, error) { - gomodguardIssues := processor.ProcessFiles(internal.GetGoFileNames(pass)) + analyzer.Run = func(pass *analysis.Pass) (any, error) { + gomodguardIssues := processor.ProcessFiles(internal.GetGoFileNames(pass)) - mu.Lock() - defer mu.Unlock() + mu.Lock() + defer mu.Unlock() - for _, gomodguardIssue := range gomodguardIssues { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - FromLinter: name, - Pos: gomodguardIssue.Position, - Text: gomodguardIssue.Reason, - }, pass)) - } + for _, gomodguardIssue := range gomodguardIssues { + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + FromLinter: linterName, + Pos: gomodguardIssue.Position, + Text: gomodguardIssue.Reason, + }, pass)) + } - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return issues - }).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return issues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/gomodguard/testdata/go.mod b/pkg/golinters/gomodguard/testdata/go.mod index ab174ed19807..c5512cba7f95 100644 --- a/pkg/golinters/gomodguard/testdata/go.mod +++ b/pkg/golinters/gomodguard/testdata/go.mod @@ -1,8 +1,8 @@ module gomodguard -go 1.22.0 +go 1.23.0 require ( - golang.org/x/mod v0.22.0 + golang.org/x/mod v0.24.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/pkg/golinters/gomodguard/testdata/go.sum b/pkg/golinters/gomodguard/testdata/go.sum index 7c483c93b9e0..5dce74976ef5 100644 --- a/pkg/golinters/gomodguard/testdata/go.sum +++ b/pkg/golinters/gomodguard/testdata/go.sum @@ -1,5 +1,7 @@ golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/golinters/goprintffuncname/goprintffuncname.go b/pkg/golinters/goprintffuncname/goprintffuncname.go index b1436347806c..a56dce8e05df 100644 --- a/pkg/golinters/goprintffuncname/goprintffuncname.go +++ b/pkg/golinters/goprintffuncname/goprintffuncname.go @@ -2,18 +2,12 @@ package goprintffuncname import ( "github.com/golangci/go-printf-func-name/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := analyzer.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/gosec/gosec.go b/pkg/golinters/gosec/gosec.go index 95b445e87038..66d229295a3f 100644 --- a/pkg/golinters/gosec/gosec.go +++ b/pkg/golinters/gosec/gosec.go @@ -26,7 +26,7 @@ const linterName = "gosec" func New(settings *config.GoSecSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue conf := gosec.NewConfig() @@ -50,37 +50,36 @@ func New(settings *config.GoSecSettings) *goanalysis.Linter { analyzer := &analysis.Analyzer{ Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, + Doc: "Inspects source code for security problems", Run: goanalysis.DummyRun, } - return goanalysis.NewLinter( - linterName, - "Inspects source code for security problems", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = func(pass *analysis.Pass) (any, error) { - // The `gosecAnalyzer` is here because of concurrency issue. - gosecAnalyzer := gosec.NewAnalyzer(conf, true, false, false, settings.Concurrency, logger) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = func(pass *analysis.Pass) (any, error) { + // The `gosecAnalyzer` is here because of concurrency issue. + gosecAnalyzer := gosec.NewAnalyzer(conf, true, false, false, settings.Concurrency, logger) - gosecAnalyzer.LoadRules(ruleDefinitions.RulesInfo()) - gosecAnalyzer.LoadAnalyzers(analyzerDefinitions.AnalyzersInfo()) + gosecAnalyzer.LoadRules(ruleDefinitions.RulesInfo()) + gosecAnalyzer.LoadAnalyzers(analyzerDefinitions.AnalyzersInfo()) - issues := runGoSec(lintCtx, pass, settings, gosecAnalyzer) + issues := runGoSec(lintCtx, pass, settings, gosecAnalyzer) - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runGoSec(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoSecSettings, analyzer *gosec.Analyzer) []goanalysis.Issue { +func runGoSec(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoSecSettings, analyzer *gosec.Analyzer) []*goanalysis.Issue { pkg := &packages.Package{ Fset: pass.Fset, Syntax: pass.Files, @@ -108,7 +107,7 @@ func runGoSec(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoS secIssues = filterIssues(secIssues, severity, confidence) - issues := make([]goanalysis.Issue, 0, len(secIssues)) + issues := make([]*goanalysis.Issue, 0, len(secIssues)) for _, i := range secIssues { text := fmt.Sprintf("%s: %s", i.RuleID, i.What) diff --git a/pkg/golinters/gosmopolitan/gosmopolitan.go b/pkg/golinters/gosmopolitan/gosmopolitan.go index 6c574403f694..76261abe1450 100644 --- a/pkg/golinters/gosmopolitan/gosmopolitan.go +++ b/pkg/golinters/gosmopolitan/gosmopolitan.go @@ -4,18 +4,16 @@ import ( "strings" "github.com/xen0n/gosmopolitan" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.GosmopolitanSettings) *goanalysis.Linter { - a := gosmopolitan.NewAnalyzer() + var cfg map[string]any - cfg := map[string]map[string]any{} if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "allowtimelocal": settings.AllowTimeLocal, "escapehatches": strings.Join(settings.EscapeHatches, ","), "watchforscripts": strings.Join(settings.WatchForScripts, ","), @@ -25,10 +23,8 @@ func New(settings *config.GosmopolitanSettings) *goanalysis.Linter { } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(gosmopolitan.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/govet/govet.go b/pkg/golinters/govet/govet.go index 3ffdc22ebb2a..e4de5b0f4459 100644 --- a/pkg/golinters/govet/govet.go +++ b/pkg/golinters/govet/govet.go @@ -24,6 +24,8 @@ import ( "golang.org/x/tools/go/analysis/passes/fieldalignment" "golang.org/x/tools/go/analysis/passes/findcall" "golang.org/x/tools/go/analysis/passes/framepointer" + "golang.org/x/tools/go/analysis/passes/hostport" + "golang.org/x/tools/go/analysis/passes/httpmux" "golang.org/x/tools/go/analysis/passes/httpresponse" "golang.org/x/tools/go/analysis/passes/ifaceassert" _ "golang.org/x/tools/go/analysis/passes/inspect" // unused internal analyzer @@ -77,6 +79,8 @@ var ( fieldalignment.Analyzer, findcall.Analyzer, framepointer.Analyzer, + hostport.Analyzer, + httpmux.Analyzer, httpresponse.Analyzer, ifaceassert.Analyzer, loopclosure.Analyzer, diff --git a/pkg/golinters/govet/govet_test.go b/pkg/golinters/govet/govet_test.go index ec7072795f74..794ef6ece9db 100644 --- a/pkg/golinters/govet/govet_test.go +++ b/pkg/golinters/govet/govet_test.go @@ -18,7 +18,7 @@ import ( func TestGovet(t *testing.T) { // Checking that every default analyzer is in "all analyzers" list. - checkList := append([]*analysis.Analyzer{}, defaultAnalyzers...) + checkList := slices.Clone(defaultAnalyzers) checkList = append(checkList, shadow.Analyzer) // special case, used in analyzersFromConfig for _, defaultAnalyzer := range checkList { diff --git a/pkg/golinters/grouper/grouper.go b/pkg/golinters/grouper/grouper.go index 853e2d3e7f70..ed3601617d9a 100644 --- a/pkg/golinters/grouper/grouper.go +++ b/pkg/golinters/grouper/grouper.go @@ -2,18 +2,16 @@ package grouper import ( grouper "github.com/leonklingele/grouper/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.GrouperSettings) *goanalysis.Linter { - a := grouper.New() + var cfg map[string]any - cfg := map[string]map[string]any{} if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "const-require-single-const": settings.ConstRequireSingleConst, "const-require-grouping": settings.ConstRequireGrouping, "import-require-single-import": settings.ImportRequireSingleImport, @@ -24,11 +22,9 @@ func New(settings *config.GrouperSettings) *goanalysis.Linter { "var-require-grouping": settings.VarRequireGrouping, } } - - return goanalysis.NewLinter( - a.Name, - "Analyze expression groups.", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(grouper.New()). + WithDesc("Analyze expression groups."). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/iface/iface.go b/pkg/golinters/iface/iface.go index a3c2816d4385..0a4a38abc931 100644 --- a/pkg/golinters/iface/iface.go +++ b/pkg/golinters/iface/iface.go @@ -5,6 +5,7 @@ import ( "github.com/uudashr/iface/identical" "github.com/uudashr/iface/opaque" + "github.com/uudashr/iface/unexported" "github.com/uudashr/iface/unused" "golang.org/x/tools/go/analysis" @@ -28,9 +29,10 @@ func New(settings *config.IfaceSettings) *goanalysis.Linter { func analyzersFromSettings(settings *config.IfaceSettings) []*analysis.Analyzer { allAnalyzers := map[string]*analysis.Analyzer{ - "identical": identical.Analyzer, - "unused": unused.Analyzer, - "opaque": opaque.Analyzer, + "identical": identical.Analyzer, + "unused": unused.Analyzer, + "opaque": opaque.Analyzer, + "unexported": unexported.Analyzer, } if settings == nil || len(settings.Enable) == 0 { diff --git a/pkg/golinters/iface/testdata/iface_all.go b/pkg/golinters/iface/testdata/iface_all.go index 3a6f912a1d2a..3dd95cdc24bf 100644 --- a/pkg/golinters/iface/testdata/iface_all.go +++ b/pkg/golinters/iface/testdata/iface_all.go @@ -6,11 +6,11 @@ import "fmt" // identical -type Pinger interface { // want "identical: interface Pinger contains identical methods or type constraints from another interface, causing redundancy" +type Pinger interface { // want "identical: interface 'Pinger' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } -type Healthcheck interface { // want "identical: interface Healthcheck contains identical methods or type constraints from another interface, causing redundancy" +type Healthcheck interface { // want "identical: interface 'Healthcheck' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } @@ -28,7 +28,7 @@ func (s server) Serve() error { return nil } -func NewServer(addr string) Server { // want "opaque: NewServer function return Server interface at the 1st result, abstract a single concrete implementation of \\*server" +func NewServer(addr string) Server { // want "opaque: 'NewServer' function return 'Server' interface at the 1st result, abstract a single concrete implementation of '\\*server'" return &server{addr: addr} } @@ -39,7 +39,7 @@ type User struct { Name string } -type UserRepository interface { // want "unused: interface UserRepository is declared but not used within the package" +type UserRepository interface { // want "unused: interface 'UserRepository' is declared but not used within the package" UserOf(id string) (*User, error) } diff --git a/pkg/golinters/iface/testdata/iface_cgo.go b/pkg/golinters/iface/testdata/iface_cgo.go index 43ef0216a036..16a9944854f0 100644 --- a/pkg/golinters/iface/testdata/iface_cgo.go +++ b/pkg/golinters/iface/testdata/iface_cgo.go @@ -24,11 +24,11 @@ func _() { // identical -type Pinger interface { // want "identical: interface Pinger contains identical methods or type constraints from another interface, causing redundancy" +type Pinger interface { // want "identical: interface 'Pinger' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } -type Healthcheck interface { // want "identical: interface Healthcheck contains identical methods or type constraints from another interface, causing redundancy" +type Healthcheck interface { // want "identical: interface 'Healthcheck' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } diff --git a/pkg/golinters/iface/testdata/iface_default.go b/pkg/golinters/iface/testdata/iface_default.go index 34117389738b..d0344b36c58f 100644 --- a/pkg/golinters/iface/testdata/iface_default.go +++ b/pkg/golinters/iface/testdata/iface_default.go @@ -5,11 +5,11 @@ import "fmt" // identical -type Pinger interface { // want "identical: interface Pinger contains identical methods or type constraints from another interface, causing redundancy" +type Pinger interface { // want "identical: interface 'Pinger' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } -type Healthcheck interface { // want "identical: interface Healthcheck contains identical methods or type constraints from another interface, causing redundancy" +type Healthcheck interface { // want "identical: interface 'Healthcheck' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } diff --git a/pkg/golinters/iface/testdata/iface_identical.go b/pkg/golinters/iface/testdata/iface_identical.go index 821aff7bd41e..c8a2de4818bb 100644 --- a/pkg/golinters/iface/testdata/iface_identical.go +++ b/pkg/golinters/iface/testdata/iface_identical.go @@ -6,11 +6,11 @@ import "fmt" // identical -type Pinger interface { // want "identical: interface Pinger contains identical methods or type constraints from another interface, causing redundancy" +type Pinger interface { // want "identical: interface 'Pinger' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } -type Healthcheck interface { // want "identical: interface Healthcheck contains identical methods or type constraints from another interface, causing redundancy" +type Healthcheck interface { // want "identical: interface 'Healthcheck' contains identical methods or type constraints with another interface, causing redundancy" Ping() error } diff --git a/pkg/golinters/iface/testdata/iface_opaque.go b/pkg/golinters/iface/testdata/iface_opaque.go index b7ebeddc600f..8610a3fa05c1 100644 --- a/pkg/golinters/iface/testdata/iface_opaque.go +++ b/pkg/golinters/iface/testdata/iface_opaque.go @@ -28,7 +28,7 @@ func (s server) Serve() error { return nil } -func NewServer(addr string) Server { // want "opaque: NewServer function return Server interface at the 1st result, abstract a single concrete implementation of \\*server" +func NewServer(addr string) Server { // want "opaque: 'NewServer' function return 'Server' interface at the 1st result, abstract a single concrete implementation of '\\*server'" return &server{addr: addr} } diff --git a/pkg/golinters/iface/testdata/iface_unexported.go b/pkg/golinters/iface/testdata/iface_unexported.go new file mode 100644 index 000000000000..01a4f210f9f7 --- /dev/null +++ b/pkg/golinters/iface/testdata/iface_unexported.go @@ -0,0 +1,84 @@ +//golangcitest:args -Eiface +//golangcitest:config_path testdata/iface_unexported.yml +package testdata + +import "fmt" + +// identical + +type Pinger interface { + Ping() error +} + +type Healthcheck interface { + Ping() error +} + +// opaque + +type Server interface { + Serve() error +} + +type server struct { + addr string +} + +func (s server) Serve() error { + return nil +} + +func NewServer(addr string) Server { + return &server{addr: addr} +} + +// unused + +type User struct { + ID string + Name string +} + +type UserRepository interface { + UserOf(id string) (*User, error) +} + +type UserRepositorySQL struct { +} + +func (r *UserRepositorySQL) UserOf(id string) (*User, error) { + return nil, nil +} + +type Granter interface { + Grant(permission string) error +} + +func AllowAll(g Granter) error { + return g.Grant("all") +} + +type Allower interface { + Allow(permission string) error +} + +func Allow(x any) { + _ = x.(Allower) + fmt.Println("allow") +} + +// unexported + +type unexportedReader interface { + Read([]byte) (int, error) +} + +func ReadAll(r unexportedReader) ([]byte, error) { // want "unexported interface 'unexportedReader' used as parameter in exported function 'ReadAll'" + buf := make([]byte, 1024) + _, err := r.Read(buf) + return buf, err +} + +func NewUnexportedReader() unexportedReader { // want "unexported interface 'unexportedReader' used as return value in exported function 'NewUnexportedReader'" + return nil // stub +} diff --git a/pkg/golinters/iface/testdata/iface_unexported.yml b/pkg/golinters/iface/testdata/iface_unexported.yml new file mode 100644 index 000000000000..cc0a84c0aa1e --- /dev/null +++ b/pkg/golinters/iface/testdata/iface_unexported.yml @@ -0,0 +1,7 @@ +version: "2" + +linters: + settings: + iface: + enable: + - unexported diff --git a/pkg/golinters/iface/testdata/iface_unused.go b/pkg/golinters/iface/testdata/iface_unused.go index b75fdc8964c6..58e5ffdbaf25 100644 --- a/pkg/golinters/iface/testdata/iface_unused.go +++ b/pkg/golinters/iface/testdata/iface_unused.go @@ -6,11 +6,11 @@ import "fmt" // identical -type Pinger interface { // want "unused: interface Pinger is declared but not used within the package" +type Pinger interface { // want "unused: interface 'Pinger' is declared but not used within the package" Ping() error } -type Healthcheck interface { // want "unused: interface Healthcheck is declared but not used within the package" +type Healthcheck interface { // want "unused: interface 'Healthcheck' is declared but not used within the package" Ping() error } @@ -39,7 +39,7 @@ type User struct { Name string } -type UserRepository interface { // want "unused: interface UserRepository is declared but not used within the package" +type UserRepository interface { // want "unused: interface 'UserRepository' is declared but not used within the package" UserOf(id string) (*User, error) } diff --git a/pkg/golinters/importas/importas.go b/pkg/golinters/importas/importas.go index a86db68ce04e..fa7a54300e29 100644 --- a/pkg/golinters/importas/importas.go +++ b/pkg/golinters/importas/importas.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/julz/importas" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -16,55 +15,53 @@ import ( func New(settings *config.ImportAsSettings) *goanalysis.Linter { analyzer := importas.Analyzer - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - if settings == nil { - return - } - if len(settings.Alias) == 0 { - lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") - } - - if err := analyzer.Flags.Set("no-unaliased", strconv.FormatBool(settings.NoUnaliased)); err != nil { - lintCtx.Log.Errorf("failed to parse configuration: %v", err) - } - - if err := analyzer.Flags.Set("no-extra-aliases", strconv.FormatBool(settings.NoExtraAliases)); err != nil { - lintCtx.Log.Errorf("failed to parse configuration: %v", err) - } - - uniqPackages := make(map[string]config.ImportAsAlias) - uniqAliases := make(map[string]config.ImportAsAlias) - for _, a := range settings.Alias { - if a.Pkg == "" { - lintCtx.Log.Errorf("invalid configuration, empty package: pkg=%s alias=%s", a.Pkg, a.Alias) - continue + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + if settings == nil { + return } - - if v, ok := uniqPackages[a.Pkg]; ok { - lintCtx.Log.Errorf("invalid configuration, multiple aliases for the same package: pkg=%s aliases=[%s,%s]", a.Pkg, a.Alias, v.Alias) - } else { - uniqPackages[a.Pkg] = a + if len(settings.Alias) == 0 { + lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") } - // Skips the duplication check when: - // - the alias is empty. - // - the alias is a regular expression replacement pattern (ie. contains `$`). - v, ok := uniqAliases[a.Alias] - if ok && a.Alias != "" && !strings.Contains(a.Alias, "$") { - lintCtx.Log.Errorf("invalid configuration, multiple packages with the same alias: alias=%s packages=[%s,%s]", a.Alias, a.Pkg, v.Pkg) - } else { - uniqAliases[a.Alias] = a + if err := analyzer.Flags.Set("no-unaliased", strconv.FormatBool(settings.NoUnaliased)); err != nil { + lintCtx.Log.Errorf("failed to parse configuration: %v", err) } - err := analyzer.Flags.Set("alias", fmt.Sprintf("%s:%s", a.Pkg, a.Alias)) - if err != nil { + if err := analyzer.Flags.Set("no-extra-aliases", strconv.FormatBool(settings.NoExtraAliases)); err != nil { lintCtx.Log.Errorf("failed to parse configuration: %v", err) } - } - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + + uniqPackages := make(map[string]config.ImportAsAlias) + uniqAliases := make(map[string]config.ImportAsAlias) + for _, a := range settings.Alias { + if a.Pkg == "" { + lintCtx.Log.Errorf("invalid configuration, empty package: pkg=%s alias=%s", a.Pkg, a.Alias) + continue + } + + if v, ok := uniqPackages[a.Pkg]; ok { + lintCtx.Log.Errorf("invalid configuration, multiple aliases for the same package: pkg=%s aliases=[%s,%s]", a.Pkg, a.Alias, v.Alias) + } else { + uniqPackages[a.Pkg] = a + } + + // Skips the duplication check when: + // - the alias is empty. + // - the alias is a regular expression replacement pattern (ie. contains `$`). + v, ok := uniqAliases[a.Alias] + if ok && a.Alias != "" && !strings.Contains(a.Alias, "$") { + lintCtx.Log.Errorf("invalid configuration, multiple packages with the same alias: alias=%s packages=[%s,%s]", a.Alias, a.Pkg, v.Pkg) + } else { + uniqAliases[a.Alias] = a + } + + err := analyzer.Flags.Set("alias", fmt.Sprintf("%s:%s", a.Pkg, a.Alias)) + if err != nil { + lintCtx.Log.Errorf("failed to parse configuration: %v", err) + } + } + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/inamedparam/inamedparam.go b/pkg/golinters/inamedparam/inamedparam.go index 0a67c970deca..ecb6f7e5024f 100644 --- a/pkg/golinters/inamedparam/inamedparam.go +++ b/pkg/golinters/inamedparam/inamedparam.go @@ -2,29 +2,22 @@ package inamedparam import ( "github.com/macabu/inamedparam" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.INamedParamSettings) *goanalysis.Linter { - a := inamedparam.Analyzer - - var cfg map[string]map[string]any + var cfg map[string]any if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - "skip-single-param": settings.SkipSingleParam, - }, + cfg = map[string]any{ + "skip-single-param": settings.SkipSingleParam, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(inamedparam.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/ineffassign/ineffassign.go b/pkg/golinters/ineffassign/ineffassign.go index bbe01ba1f37a..2c0119f1032f 100644 --- a/pkg/golinters/ineffassign/ineffassign.go +++ b/pkg/golinters/ineffassign/ineffassign.go @@ -2,18 +2,13 @@ package ineffassign import ( "github.com/gordonklaus/ineffassign/pkg/ineffassign" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := ineffassign.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Detects when assignments to existing variables are not used", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(ineffassign.Analyzer). + WithDesc("Detects when assignments to existing variables are not used"). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/interfacebloat/interfacebloat.go b/pkg/golinters/interfacebloat/interfacebloat.go index fbafb3ac7343..f2e187423278 100644 --- a/pkg/golinters/interfacebloat/interfacebloat.go +++ b/pkg/golinters/interfacebloat/interfacebloat.go @@ -2,28 +2,22 @@ package interfacebloat import ( "github.com/sashamelentyev/interfacebloat/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.InterfaceBloatSettings) *goanalysis.Linter { - a := analyzer.New() + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - analyzer.InterfaceMaxMethodsFlag: settings.Max, - }, + cfg = map[string]any{ + analyzer.InterfaceMaxMethodsFlag: settings.Max, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/internal/commons.go b/pkg/golinters/internal/commons.go index ebc211902dc8..d19c1fd45082 100644 --- a/pkg/golinters/internal/commons.go +++ b/pkg/golinters/internal/commons.go @@ -4,6 +4,3 @@ import "github.com/golangci/golangci-lint/v2/pkg/logutils" // LinterLogger must be use only when the context logger is not available. var LinterLogger = logutils.NewStderrLog(logutils.DebugKeyLinter) - -// PlaceholderBasePath used inside linters to evaluate relative paths. -const PlaceholderBasePath = "${base-path}" diff --git a/pkg/golinters/internal/util.go b/pkg/golinters/internal/util.go index 2e5fb29f91c9..86137cf66081 100644 --- a/pkg/golinters/internal/util.go +++ b/pkg/golinters/internal/util.go @@ -6,11 +6,10 @@ import ( "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -func FormatCode(code string, _ *config.Config) string { +func FormatCode(code string) string { if strings.Contains(code, "`") { return code // TODO: properly escape or remove } diff --git a/pkg/golinters/intrange/intrange.go b/pkg/golinters/intrange/intrange.go index c75be9b63446..1ff02964cbe5 100644 --- a/pkg/golinters/intrange/intrange.go +++ b/pkg/golinters/intrange/intrange.go @@ -2,18 +2,12 @@ package intrange import ( "github.com/ckaznocha/intrange" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := intrange.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(intrange.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/ireturn/ireturn.go b/pkg/golinters/ireturn/ireturn.go index 44c28700b370..b9cce0001842 100644 --- a/pkg/golinters/ireturn/ireturn.go +++ b/pkg/golinters/ireturn/ireturn.go @@ -4,28 +4,24 @@ import ( "strings" "github.com/butuzov/ireturn/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.IreturnSettings) *goanalysis.Linter { - a := analyzer.NewAnalyzer() + var cfg map[string]any - cfg := map[string]map[string]any{} if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "allow": strings.Join(settings.Allow, ","), "reject": strings.Join(settings.Reject, ","), "nonolint": true, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/lll/lll.go b/pkg/golinters/lll/lll.go index eb435baa754c..c8e6717dea82 100644 --- a/pkg/golinters/lll/lll.go +++ b/pkg/golinters/lll/lll.go @@ -15,30 +15,23 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -const linterName = "lll" - const goCommentDirectivePrefix = "//go:" func New(settings *config.LllSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - err := runLll(pass, settings) - if err != nil { - return nil, err - } - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Reports long lines", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "lll", + Doc: "Reports long lines", + Run: func(pass *analysis.Pass) (any, error) { + err := runLll(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func runLll(pass *analysis.Pass, settings *config.LllSettings) error { diff --git a/pkg/golinters/loggercheck/loggercheck.go b/pkg/golinters/loggercheck/loggercheck.go index a5dd4da48cd6..b9a6efa75fad 100644 --- a/pkg/golinters/loggercheck/loggercheck.go +++ b/pkg/golinters/loggercheck/loggercheck.go @@ -2,7 +2,6 @@ package loggercheck import ( "github.com/timonwong/loggercheck" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -37,11 +36,7 @@ func New(settings *config.LoggerCheckSettings) *goanalysis.Linter { } } - analyzer := loggercheck.NewAnalyzer(opts...) - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(loggercheck.NewAnalyzer(opts...)). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/loggercheck/testdata/go.mod b/pkg/golinters/loggercheck/testdata/go.mod index 985fff765d4b..0df788c08b62 100644 --- a/pkg/golinters/loggercheck/testdata/go.mod +++ b/pkg/golinters/loggercheck/testdata/go.mod @@ -4,7 +4,7 @@ go 1.21.0 require ( github.com/go-kit/log v0.2.1 - github.com/go-logr/logr v1.4.2 + github.com/go-logr/logr v1.4.3 go.uber.org/zap v1.27.0 k8s.io/klog/v2 v2.130.1 ) diff --git a/pkg/golinters/loggercheck/testdata/go.sum b/pkg/golinters/loggercheck/testdata/go.sum index 5a316ccca990..dd912496e496 100644 --- a/pkg/golinters/loggercheck/testdata/go.sum +++ b/pkg/golinters/loggercheck/testdata/go.sum @@ -4,8 +4,8 @@ github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= diff --git a/pkg/golinters/maintidx/maintidx.go b/pkg/golinters/maintidx/maintidx.go index 4e541f888dfa..f2076c8ab030 100644 --- a/pkg/golinters/maintidx/maintidx.go +++ b/pkg/golinters/maintidx/maintidx.go @@ -2,29 +2,22 @@ package maintidx import ( "github.com/yagipy/maintidx" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.MaintIdxSettings) *goanalysis.Linter { - analyzer := maintidx.Analyzer - - cfg := map[string]map[string]any{ - analyzer.Name: {"under": 20}, + cfg := map[string]any{ + "under": 20, } if settings != nil { - cfg[analyzer.Name] = map[string]any{ - "under": settings.Under, - } + cfg["under"] = settings.Under } - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(maintidx.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/makezero/makezero.go b/pkg/golinters/makezero/makezero.go index 04b4fe93dadf..5ee298d99f4e 100644 --- a/pkg/golinters/makezero/makezero.go +++ b/pkg/golinters/makezero/makezero.go @@ -3,35 +3,28 @@ package makezero import ( "fmt" - "github.com/ashanbrown/makezero/makezero" + "github.com/ashanbrown/makezero/v2/makezero" "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -const linterName = "makezero" - func New(settings *config.MakezeroSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - err := runMakeZero(pass, settings) - if err != nil { - return nil, err - } - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Finds slice declarations with non-zero initial length", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "makezero", + Doc: "Find slice declarations with non-zero initial length", + Run: func(pass *analysis.Pass) (any, error) { + err := runMakeZero(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } func runMakeZero(pass *analysis.Pass, settings *config.MakezeroSettings) error { diff --git a/pkg/golinters/mirror/mirror.go b/pkg/golinters/mirror/mirror.go index 9badb0c1ed68..07cfe25e4e44 100644 --- a/pkg/golinters/mirror/mirror.go +++ b/pkg/golinters/mirror/mirror.go @@ -2,29 +2,22 @@ package mirror import ( "github.com/butuzov/mirror" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := mirror.NewAnalyzer() - // mirror only lints test files if the `--with-tests` flag is passed, // so we pass the `with-tests` flag as true to the analyzer before running it. // This can be turned off by using the regular golangci-lint flags such as `--tests` or `--skip-files` // or can be disabled per linter via exclude rules. // (see https://github.com/golangci/golangci-lint/issues/2527#issuecomment-1023707262) - linterCfg := map[string]map[string]any{ - a.Name: { - "with-tests": true, - }, + cfg := map[string]any{ + "with-tests": true, } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - linterCfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(mirror.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/misspell/misspell.go b/pkg/golinters/misspell/misspell.go index 9a170c9537b7..cbf378505b47 100644 --- a/pkg/golinters/misspell/misspell.go +++ b/pkg/golinters/misspell/misspell.go @@ -23,27 +23,22 @@ func New(settings *config.MisspellSettings) *goanalysis.Linter { internal.LinterLogger.Fatalf("%s: %v", linterName, err) } - a := &analysis.Analyzer{ - Name: linterName, - Doc: "Finds commonly misspelled English words", - Run: func(pass *analysis.Pass) (any, error) { - for _, file := range pass.Files { - err := runMisspellOnFile(pass, file, replacer, settings.Mode) - if err != nil { - return nil, err + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Finds commonly misspelled English words", + Run: func(pass *analysis.Pass) (any, error) { + for _, file := range pass.Files { + err := runMisspellOnFile(pass, file, replacer, settings.Mode) + if err != nil { + return nil, err + } } - } - return nil, nil - }, - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func createMisspellReplacer(settings *config.MisspellSettings) (*misspell.Replacer, error) { diff --git a/pkg/golinters/mnd/mnd.go b/pkg/golinters/mnd/mnd.go index 744186bc3e63..07174c899f57 100644 --- a/pkg/golinters/mnd/mnd.go +++ b/pkg/golinters/mnd/mnd.go @@ -2,19 +2,15 @@ package mnd import ( mnd "github.com/tommy-muehle/go-mnd/v2" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.MndSettings) *goanalysis.Linter { - return newMND(mnd.Analyzer, settings, nil) -} + cfg := map[string]any{} -func newMND(a *analysis.Analyzer, settings *config.MndSettings, linterCfg map[string]map[string]any) *goanalysis.Linter { - if len(linterCfg) == 0 && settings != nil { - cfg := make(map[string]any) + if settings != nil { if len(settings.Checks) > 0 { cfg["checks"] = settings.Checks } @@ -27,16 +23,11 @@ func newMND(a *analysis.Analyzer, settings *config.MndSettings, linterCfg map[st if len(settings.IgnoredFunctions) > 0 { cfg["ignored-functions"] = settings.IgnoredFunctions } - - linterCfg = map[string]map[string]any{ - a.Name: cfg, - } } - return goanalysis.NewLinter( - a.Name, - "An analyzer to detect magic numbers.", - []*analysis.Analyzer{a}, - linterCfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(mnd.Analyzer). + WithDesc("An analyzer to detect magic numbers."). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/mnd/testdata/mnd_custom.go b/pkg/golinters/mnd/testdata/mnd_custom.go new file mode 100644 index 000000000000..75530516b3ab --- /dev/null +++ b/pkg/golinters/mnd/testdata/mnd_custom.go @@ -0,0 +1,24 @@ +//golangcitest:args -Emnd +//golangcitest:config_path testdata/mnd_custom.yml +package testdata + +import ( + "log" + "net/http" + "time" +) + +func Mnd() { + c := &http.Client{ + Timeout: 5 * time.Second, + } + + res, err := c.Get("https://www.google.com") + if err != nil { + log.Fatal(err) + } + defer res.Body.Close() + if res.StatusCode != 200 { // want "Magic number: 200, in detected" + log.Println("Something went wrong") + } +} diff --git a/pkg/golinters/mnd/testdata/mnd_custom.yml b/pkg/golinters/mnd/testdata/mnd_custom.yml new file mode 100644 index 000000000000..7987bf91019e --- /dev/null +++ b/pkg/golinters/mnd/testdata/mnd_custom.yml @@ -0,0 +1,7 @@ +version: "2" + +linters: + settings: + mnd: + ignored-numbers: + - '5' diff --git a/pkg/golinters/musttag/musttag.go b/pkg/golinters/musttag/musttag.go index 030707327b7f..d17df9c2b8d9 100644 --- a/pkg/golinters/musttag/musttag.go +++ b/pkg/golinters/musttag/musttag.go @@ -2,7 +2,6 @@ package musttag import ( "go-simpler.org/musttag" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -21,9 +20,7 @@ func New(settings *config.MustTagSettings) *goanalysis.Linter { } } - a := musttag.New(funcs...) - return goanalysis. - NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). + NewLinterFromAnalyzer(musttag.New(funcs...)). WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/nakedret/nakedret.go b/pkg/golinters/nakedret/nakedret.go index 1b278872e612..90053a1aab98 100644 --- a/pkg/golinters/nakedret/nakedret.go +++ b/pkg/golinters/nakedret/nakedret.go @@ -2,24 +2,20 @@ package nakedret import ( "github.com/alexkohler/nakedret/v2" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.NakedretSettings) *goanalysis.Linter { - var maxLines uint + cfg := &nakedret.NakedReturnRunner{} + if settings != nil { - maxLines = settings.MaxFuncLines + // SkipTestFiles is intentionally ignored => should be managed with `linters.exclusions.rules`. + cfg.MaxLength = settings.MaxFuncLines } - a := nakedret.NakedReturnAnalyzer(maxLines, false) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(nakedret.NakedReturnAnalyzer(cfg)). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/nestif/nestif.go b/pkg/golinters/nestif/nestif.go index 1a6b55cafc22..e5823723c83a 100644 --- a/pkg/golinters/nestif/nestif.go +++ b/pkg/golinters/nestif/nestif.go @@ -8,25 +8,18 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -const linterName = "nestif" - func New(settings *config.NestifSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - runNestIf(pass, settings) - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Reports deeply nested if statements", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "nestif", + Doc: "Reports deeply nested if statements", + Run: func(pass *analysis.Pass) (any, error) { + runNestIf(pass, settings) + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func runNestIf(pass *analysis.Pass, settings *config.NestifSettings) { diff --git a/pkg/golinters/nilerr/nilerr.go b/pkg/golinters/nilerr/nilerr.go index 9345b945be11..fa5dcdc259fc 100644 --- a/pkg/golinters/nilerr/nilerr.go +++ b/pkg/golinters/nilerr/nilerr.go @@ -2,18 +2,13 @@ package nilerr import ( "github.com/gostaticanalysis/nilerr" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := nilerr.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Finds the code that returns nil even if it checks that the error is not nil.", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(nilerr.Analyzer). + WithDesc("Find the code that returns nil even if it checks that the error is not nil."). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/nilnesserr/nilnesserr.go b/pkg/golinters/nilnesserr/nilnesserr.go index b54992e29bb5..95eaf94abe25 100644 --- a/pkg/golinters/nilnesserr/nilnesserr.go +++ b/pkg/golinters/nilnesserr/nilnesserr.go @@ -2,22 +2,18 @@ package nilnesserr import ( "github.com/alingse/nilnesserr" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) func New() *goanalysis.Linter { - a, err := nilnesserr.NewAnalyzer(nilnesserr.LinterSetting{}) + analyzer, err := nilnesserr.NewAnalyzer(nilnesserr.LinterSetting{}) if err != nil { internal.LinterLogger.Fatalf("nilnesserr: create analyzer: %v", err) } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/nilnil/nilnil.go b/pkg/golinters/nilnil/nilnil.go index 5f42e24c96fc..4936a6b84c8f 100644 --- a/pkg/golinters/nilnil/nilnil.go +++ b/pkg/golinters/nilnil/nilnil.go @@ -2,33 +2,28 @@ package nilnil import ( "github.com/Antonboom/nilnil/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.NilNilSettings) *goanalysis.Linter { - a := analyzer.New() + var cfg map[string]any - cfg := make(map[string]map[string]any) if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "detect-opposite": settings.DetectOpposite, } if b := settings.OnlyTwo; b != nil { - cfg[a.Name]["only-two"] = *b + cfg["only-two"] = *b } if len(settings.CheckedTypes) != 0 { - cfg[a.Name]["checked-types"] = settings.CheckedTypes + cfg["checked-types"] = settings.CheckedTypes } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ). + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/nlreturn/nlreturn.go b/pkg/golinters/nlreturn/nlreturn.go index ce2130c52c81..7b7ab745ad7b 100644 --- a/pkg/golinters/nlreturn/nlreturn.go +++ b/pkg/golinters/nlreturn/nlreturn.go @@ -2,26 +2,22 @@ package nlreturn import ( "github.com/ssgreg/nlreturn/v2/pkg/nlreturn" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.NlreturnSettings) *goanalysis.Linter { - a := nlreturn.NewAnalyzer() + var cfg map[string]any - cfg := map[string]map[string]any{} if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "block-size": settings.BlockSize, } } - - return goanalysis.NewLinter( - a.Name, - "nlreturn checks for a new line before return and branch statements to increase code clarity", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(nlreturn.NewAnalyzer()). + WithDesc("Checks for a new line before return and branch statements to increase code clarity"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/noctx/noctx.go b/pkg/golinters/noctx/noctx.go index b0c5f9b50040..c3e5be104262 100644 --- a/pkg/golinters/noctx/noctx.go +++ b/pkg/golinters/noctx/noctx.go @@ -2,18 +2,13 @@ package noctx import ( "github.com/sonatard/noctx" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := noctx.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Finds sending http request without context.Context", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(noctx.Analyzer). + WithDesc("Detects function and method with missing usage of context.Context"). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/noctx/testdata/noctx.go b/pkg/golinters/noctx/testdata/noctx.go index 8b077a566206..8a34443e2029 100644 --- a/pkg/golinters/noctx/testdata/noctx.go +++ b/pkg/golinters/noctx/testdata/noctx.go @@ -3,73 +3,58 @@ package testdata import ( "context" + "database/sql" "net/http" ) var newRequestPkg = http.NewRequest -func Noctx() { - const url = "http://example.com" +func _() { + const url = "https://example.com" + cli := &http.Client{} ctx := context.Background() - http.Get(url) // want `net/http\.Get must not be called` - _ = http.Get // OK - f := http.Get // OK - f(url) // want `net/http\.Get must not be called` - - http.Head(url) // want `net/http\.Head must not be called` - http.Post(url, "", nil) // want `net/http\.Post must not be called` - http.PostForm(url, nil) // want `net/http\.PostForm must not be called` - - cli.Get(url) // want `\(\*net/http\.Client\)\.Get must not be called` - _ = cli.Get // OK - m := cli.Get // OK - m(url) // want `\(\*net/http\.Client\)\.Get must not be called` - - cli.Head(url) // want `\(\*net/http\.Client\)\.Head must not be called` - cli.Post(url, "", nil) // want `\(\*net/http\.Client\)\.Post must not be called` - cli.PostForm(url, nil) // want `\(\*net/http\.Client\)\.PostForm must not be called` - req, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` cli.Do(req) req2, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) // OK cli.Do(req2) - req3, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req3, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req3 = req3.WithContext(ctx) cli.Do(req3) f2 := func(req *http.Request, ctx context.Context) *http.Request { return req } - req4, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req4, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req4 = f2(req4, ctx) - req41, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req41, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req41 = req41.WithContext(ctx) req41 = f2(req41, ctx) newRequest := http.NewRequest - req5, _ := newRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req5, _ := newRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` cli.Do(req5) - req51, _ := newRequest(http.MethodPost, url, nil) // OK + req51, _ := newRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req51 = req51.WithContext(ctx) cli.Do(req51) - req52, _ := newRequestPkg(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req52, _ := newRequestPkg(http.MethodPost, url, nil) // TODO: false negative `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` cli.Do(req52) type MyRequest = http.Request f3 := func(req *MyRequest, ctx context.Context) *MyRequest { return req } - req6, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req6, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req6 = f3(req6, ctx) - req61, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req61, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req61 = req61.WithContext(ctx) req61 = f3(req61, ctx) @@ -77,22 +62,22 @@ func Noctx() { f4 := func(req *MyRequest2, ctx context.Context) *MyRequest2 { return req } - req7, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req7, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req71 := MyRequest2(*req7) f4(&req71, ctx) - req72, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req72, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req72 = req72.WithContext(ctx) req73 := MyRequest2(*req7) f4(&req73, ctx) req8, _ := func() (*http.Request, error) { - return http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + return http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` }() cli.Do(req8) req82, _ := func() (*http.Request, error) { - req82, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req82, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req82 = req82.WithContext(ctx) return req82, nil }() @@ -101,34 +86,99 @@ func Noctx() { f5 := func(req, req2 *http.Request, ctx context.Context) (*http.Request, *http.Request) { return req, req2 } - req9, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req9, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req9, _ = f5(req9, req9, ctx) - req91, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req91, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req91 = req91.WithContext(ctx) req9, _ = f5(req91, req91, ctx) - req10, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req11, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req10, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req11, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req10, req11 = f5(req10, req11, ctx) - req101, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req111, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req101, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req111, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req111 = req111.WithContext(ctx) req101, req111 = f5(req101, req111, ctx) func() (*http.Request, *http.Request) { - req12, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req13, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req12, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req13, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` return req12, req13 }() func() (*http.Request, *http.Request) { - req14, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req15, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req14, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req15, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req15 = req15.WithContext(ctx) return req14, req15 }() + + req121, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req121.AddCookie(&http.Cookie{Name: "k", Value: "v"}) + req121 = req121.WithContext(context.WithValue(req121.Context(), struct{}{}, 0)) + cli.Do(req121) +} + +func _() { + const url = "http://example.com" + cli := &http.Client{} + + http.Get(url) // want `net/http\.Get must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + _ = http.Get // OK + f := http.Get // OK + f(url) // want `net/http\.Get must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + + http.Head(url) // want `net/http\.Head must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + http.Post(url, "", nil) // want `net/http\.Post must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + http.PostForm(url, nil) // want `net/http\.PostForm must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + + cli.Get(url) // want `\(\*net/http\.Client\)\.Get must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + _ = cli.Get // OK + m := cli.Get // OK + m(url) // want `\(\*net/http\.Client\)\.Get must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + + cli.Head(url) // want `\(\*net/http\.Client\)\.Head must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + cli.Post(url, "", nil) // want `\(\*net/http\.Client\)\.Post must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + cli.PostForm(url, nil) // want `\(\*net/http\.Client\)\.PostForm must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` } +func _() { + ctx := context.Background() + + db, _ := sql.Open("noctx", "noctx://") + + db.Exec("select * from testdata") // want `\(\*database/sql\.DB\)\.Exec must not be called. use \(\*database/sql\.DB\)\.ExecContext` + db.ExecContext(ctx, "select * from testdata") + + db.Ping() // want `\(\*database/sql\.DB\)\.Ping must not be called. use \(\*database/sql\.DB\)\.PingContext` + db.PingContext(ctx) + + db.Prepare("select * from testdata") // want `\(\*database/sql\.DB\)\.Prepare must not be called. use \(\*database/sql\.DB\)\.PrepareContext` + db.PrepareContext(ctx, "select * from testdata") + + db.Query("select * from testdata") // want `\(\*database/sql\.DB\)\.Query must not be called. use \(\*database/sql\.DB\)\.QueryContext` + db.QueryContext(ctx, "select * from testdata") + + db.QueryRow("select * from testdata") // want `\(\*database/sql\.DB\)\.QueryRow must not be called. use \(\*database/sql\.DB\)\.QueryRowContext` + db.QueryRowContext(ctx, "select * from testdata") + + // transactions + + tx, _ := db.Begin() + tx.Exec("select * from testdata") // want `\(\*database/sql\.Tx\)\.Exec must not be called. use \(\*database/sql\.Tx\)\.ExecContext` + tx.ExecContext(ctx, "select * from testdata") + + tx.Prepare("select * from testdata") // want `\(\*database/sql\.Tx\)\.Prepare must not be called. use \(\*database/sql\.Tx\)\.PrepareContext` + tx.PrepareContext(ctx, "select * from testdata") + + tx.Query("select * from testdata") // want `\(\*database/sql\.Tx\)\.Query must not be called. use \(\*database/sql\.Tx\)\.QueryContext` + tx.QueryContext(ctx, "select * from testdata") + + tx.QueryRow("select * from testdata") // want `\(\*database/sql\.Tx\)\.QueryRow must not be called. use \(\*database/sql\.Tx\)\.QueryRowContext` + tx.QueryRowContext(ctx, "select * from testdata") + + _ = tx.Commit() +} diff --git a/pkg/golinters/noctx/testdata/noctx_cgo.go b/pkg/golinters/noctx/testdata/noctx_cgo.go index 64f5ea6c0d49..63b15477d8c3 100644 --- a/pkg/golinters/noctx/testdata/noctx_cgo.go +++ b/pkg/golinters/noctx/testdata/noctx_cgo.go @@ -13,6 +13,7 @@ import "C" import ( "context" + "database/sql" "net/http" "unsafe" ) @@ -26,67 +27,51 @@ func _() { var newRequestPkg = http.NewRequest func _() { - const url = "http://example.com" + const url = "https://example.com" + cli := &http.Client{} ctx := context.Background() - http.Get(url) // want `net/http\.Get must not be called` - _ = http.Get // OK - f := http.Get // OK - f(url) // want `net/http\.Get must not be called` - - http.Head(url) // want `net/http\.Head must not be called` - http.Post(url, "", nil) // want `net/http\.Post must not be called` - http.PostForm(url, nil) // want `net/http\.PostForm must not be called` - cli.Get(url) // want `\(\*net/http\.Client\)\.Get must not be called` - _ = cli.Get // OK - m := cli.Get // OK - m(url) // want `\(\*net/http\.Client\)\.Get must not be called` - - cli.Head(url) // want `\(\*net/http\.Client\)\.Head must not be called` - cli.Post(url, "", nil) // want `\(\*net/http\.Client\)\.Post must not be called` - cli.PostForm(url, nil) // want `\(\*net/http\.Client\)\.PostForm must not be called` - - req, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` cli.Do(req) req2, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) // OK cli.Do(req2) - req3, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req3, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req3 = req3.WithContext(ctx) cli.Do(req3) f2 := func(req *http.Request, ctx context.Context) *http.Request { return req } - req4, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req4, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req4 = f2(req4, ctx) - req41, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req41, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req41 = req41.WithContext(ctx) req41 = f2(req41, ctx) newRequest := http.NewRequest - req5, _ := newRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req5, _ := newRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` cli.Do(req5) - req51, _ := newRequest(http.MethodPost, url, nil) // OK + req51, _ := newRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req51 = req51.WithContext(ctx) cli.Do(req51) - req52, _ := newRequestPkg(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req52, _ := newRequestPkg(http.MethodPost, url, nil) // TODO: false negative `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` cli.Do(req52) type MyRequest = http.Request f3 := func(req *MyRequest, ctx context.Context) *MyRequest { return req } - req6, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req6, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req6 = f3(req6, ctx) - req61, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req61, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req61 = req61.WithContext(ctx) req61 = f3(req61, ctx) @@ -94,22 +79,22 @@ func _() { f4 := func(req *MyRequest2, ctx context.Context) *MyRequest2 { return req } - req7, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req7, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req71 := MyRequest2(*req7) f4(&req71, ctx) - req72, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req72, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req72 = req72.WithContext(ctx) req73 := MyRequest2(*req7) f4(&req73, ctx) req8, _ := func() (*http.Request, error) { - return http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + return http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` }() cli.Do(req8) req82, _ := func() (*http.Request, error) { - req82, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req82, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req82 = req82.WithContext(ctx) return req82, nil }() @@ -118,33 +103,99 @@ func _() { f5 := func(req, req2 *http.Request, ctx context.Context) (*http.Request, *http.Request) { return req, req2 } - req9, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req9, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req9, _ = f5(req9, req9, ctx) - req91, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req91, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req91 = req91.WithContext(ctx) req9, _ = f5(req91, req91, ctx) - req10, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req11, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req10, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req11, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req10, req11 = f5(req10, req11, ctx) - req101, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req111, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req101, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req111, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req111 = req111.WithContext(ctx) req101, req111 = f5(req101, req111, ctx) func() (*http.Request, *http.Request) { - req12, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req13, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req12, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req13, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` return req12, req13 }() func() (*http.Request, *http.Request) { - req14, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` - req15, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req14, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req15, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` req15 = req15.WithContext(ctx) return req14, req15 }() + + req121, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\.NewRequest must not be called. use net/http\.NewRequestWithContext` + req121.AddCookie(&http.Cookie{Name: "k", Value: "v"}) + req121 = req121.WithContext(context.WithValue(req121.Context(), struct{}{}, 0)) + cli.Do(req121) +} + +func _() { + const url = "http://example.com" + cli := &http.Client{} + + http.Get(url) // want `net/http\.Get must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + _ = http.Get // OK + f := http.Get // OK + f(url) // want `net/http\.Get must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + + http.Head(url) // want `net/http\.Head must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + http.Post(url, "", nil) // want `net/http\.Post must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + http.PostForm(url, nil) // want `net/http\.PostForm must not be called. use net/http\.NewRequestWithContext and \(\*net/http.Client\)\.Do\(\*http.Request\)` + + cli.Get(url) // want `\(\*net/http\.Client\)\.Get must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + _ = cli.Get // OK + m := cli.Get // OK + m(url) // want `\(\*net/http\.Client\)\.Get must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + + cli.Head(url) // want `\(\*net/http\.Client\)\.Head must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + cli.Post(url, "", nil) // want `\(\*net/http\.Client\)\.Post must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` + cli.PostForm(url, nil) // want `\(\*net/http\.Client\)\.PostForm must not be called. use \(\*net/http.Client\)\.Do\(\*http.Request\)` +} + +func _() { + ctx := context.Background() + + db, _ := sql.Open("noctx", "noctx://") + + db.Exec("select * from testdata") // want `\(\*database/sql\.DB\)\.Exec must not be called. use \(\*database/sql\.DB\)\.ExecContext` + db.ExecContext(ctx, "select * from testdata") + + db.Ping() // want `\(\*database/sql\.DB\)\.Ping must not be called. use \(\*database/sql\.DB\)\.PingContext` + db.PingContext(ctx) + + db.Prepare("select * from testdata") // want `\(\*database/sql\.DB\)\.Prepare must not be called. use \(\*database/sql\.DB\)\.PrepareContext` + db.PrepareContext(ctx, "select * from testdata") + + db.Query("select * from testdata") // want `\(\*database/sql\.DB\)\.Query must not be called. use \(\*database/sql\.DB\)\.QueryContext` + db.QueryContext(ctx, "select * from testdata") + + db.QueryRow("select * from testdata") // want `\(\*database/sql\.DB\)\.QueryRow must not be called. use \(\*database/sql\.DB\)\.QueryRowContext` + db.QueryRowContext(ctx, "select * from testdata") + + // transactions + + tx, _ := db.Begin() + tx.Exec("select * from testdata") // want `\(\*database/sql\.Tx\)\.Exec must not be called. use \(\*database/sql\.Tx\)\.ExecContext` + tx.ExecContext(ctx, "select * from testdata") + + tx.Prepare("select * from testdata") // want `\(\*database/sql\.Tx\)\.Prepare must not be called. use \(\*database/sql\.Tx\)\.PrepareContext` + tx.PrepareContext(ctx, "select * from testdata") + + tx.Query("select * from testdata") // want `\(\*database/sql\.Tx\)\.Query must not be called. use \(\*database/sql\.Tx\)\.QueryContext` + tx.QueryContext(ctx, "select * from testdata") + + tx.QueryRow("select * from testdata") // want `\(\*database/sql\.Tx\)\.QueryRow must not be called. use \(\*database/sql\.Tx\)\.QueryRowContext` + tx.QueryRowContext(ctx, "select * from testdata") + + _ = tx.Commit() } diff --git a/pkg/golinters/noinlineerr/noinlineerr.go b/pkg/golinters/noinlineerr/noinlineerr.go new file mode 100644 index 000000000000..4f9f82eb4d0c --- /dev/null +++ b/pkg/golinters/noinlineerr/noinlineerr.go @@ -0,0 +1,13 @@ +package noinlineerr + +import ( + "github.com/AlwxSin/noinlineerr" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(noinlineerr.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/golinters/noinlineerr/noinlineerr_integration_test.go b/pkg/golinters/noinlineerr/noinlineerr_integration_test.go new file mode 100644 index 000000000000..3b14450932a1 --- /dev/null +++ b/pkg/golinters/noinlineerr/noinlineerr_integration_test.go @@ -0,0 +1,19 @@ +package noinlineerr + +import ( + "testing" + + "github.com/golangci/golangci-lint/v2/test/testshared/integration" +) + +func TestFromTestdata(t *testing.T) { + integration.RunTestdata(t) +} + +func TestFix(t *testing.T) { + integration.RunFix(t) +} + +func TestFixPathPrefix(t *testing.T) { + integration.RunFixPathPrefix(t) +} diff --git a/pkg/golinters/noinlineerr/testdata/fix/in/noinlineerr.go b/pkg/golinters/noinlineerr/testdata/fix/in/noinlineerr.go new file mode 100644 index 000000000000..62c90bd98017 --- /dev/null +++ b/pkg/golinters/noinlineerr/testdata/fix/in/noinlineerr.go @@ -0,0 +1,59 @@ +//golangcitest:args -Enoinlineerr +//golangcitest:expected_exitcode 0 +package testdata + +type MyAliasErr error + +type MyCustomError struct{} + +func (mc *MyCustomError) Error() string { + return "error" +} + +func doSomething() error { + return nil +} + +func doSmthManyArgs(a, b, c, d int) error { + return nil +} + +func doSmthMultipleReturn() (bool, error) { + return false, nil +} + +func doMyAliasErr() MyAliasErr { + return nil +} + +func doMyCustomErr() *MyCustomError { + return &MyCustomError{} +} + +func invalid() error { + err := doSomething() + if err != nil { + return err + } + + err = doSmthManyArgs(0, + 0, + 0, + 0, + ) + if err != nil { + return err + } + + err = doMyAliasErr() + if err != nil { + return err + } + + err = doMyCustomErr() + if err != nil { + return err + } + + return nil +} diff --git a/pkg/golinters/noinlineerr/testdata/fix/out/noinlineerr.go b/pkg/golinters/noinlineerr/testdata/fix/out/noinlineerr.go new file mode 100644 index 000000000000..62c90bd98017 --- /dev/null +++ b/pkg/golinters/noinlineerr/testdata/fix/out/noinlineerr.go @@ -0,0 +1,59 @@ +//golangcitest:args -Enoinlineerr +//golangcitest:expected_exitcode 0 +package testdata + +type MyAliasErr error + +type MyCustomError struct{} + +func (mc *MyCustomError) Error() string { + return "error" +} + +func doSomething() error { + return nil +} + +func doSmthManyArgs(a, b, c, d int) error { + return nil +} + +func doSmthMultipleReturn() (bool, error) { + return false, nil +} + +func doMyAliasErr() MyAliasErr { + return nil +} + +func doMyCustomErr() *MyCustomError { + return &MyCustomError{} +} + +func invalid() error { + err := doSomething() + if err != nil { + return err + } + + err = doSmthManyArgs(0, + 0, + 0, + 0, + ) + if err != nil { + return err + } + + err = doMyAliasErr() + if err != nil { + return err + } + + err = doMyCustomErr() + if err != nil { + return err + } + + return nil +} diff --git a/pkg/golinters/noinlineerr/testdata/noinlineerr.go b/pkg/golinters/noinlineerr/testdata/noinlineerr.go new file mode 100644 index 000000000000..3bf739b7d1c3 --- /dev/null +++ b/pkg/golinters/noinlineerr/testdata/noinlineerr.go @@ -0,0 +1,87 @@ +//golangcitest:args -Enoinlineerr +package testdata + +import ( + "fmt" + "strconv" +) + +type MyAliasErr error + +type MyCustomError struct {} + +func (mc *MyCustomError) Error() string { + return "error" +} + +func doSomething() error { + return nil +} + +func doSmthManyArgs(a, b, c, d int) error { + return nil +} + +func doSmthMultipleReturn() (bool, error) { + return false, nil +} + +func doMyAliasErr() MyAliasErr { + return nil +} + +func doMyCustomErr() *MyCustomError { + return &MyCustomError{} +} + +func valid() error { + err := doSomething() // ok + if err != nil { + return err + } + + err = doSmthManyArgs(0, 0, 0, 0) // ok + if err != nil { + return err + } + + _, err = doSmthMultipleReturn() // ok + if err != nil { + return err + } + + if ok, _ := strconv.ParseBool("1"); ok { + fmt.Println("ok") + } + + return nil +} + +func invalid() error { + if err := doSomething(); err != nil { // want "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" + return err + } + + if err := doSmthManyArgs(0, // want "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" + 0, + 0, + 0, + ); err != nil { + return err + } + + if _, err := doSmthMultipleReturn(); err != nil { // want "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" + _ = false + return err + } + + if err := doMyAliasErr(); err != nil { // want "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" + return err + } + + if err := doMyCustomErr(); err != nil { // want "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" + return err + } + + return nil +} diff --git a/pkg/golinters/nolintlint/internal/nolintlint.go b/pkg/golinters/nolintlint/internal/nolintlint.go index 2be7c5c144ea..a20161405f1c 100644 --- a/pkg/golinters/nolintlint/internal/nolintlint.go +++ b/pkg/golinters/nolintlint/internal/nolintlint.go @@ -55,8 +55,8 @@ var ( ) //nolint:funlen,gocyclo // the function is going to be refactored in the future -func (l Linter) Run(pass *analysis.Pass) ([]goanalysis.Issue, error) { - var issues []goanalysis.Issue +func (l Linter) Run(pass *analysis.Pass) ([]*goanalysis.Issue, error) { + var issues []*goanalysis.Issue for _, file := range pass.Files { for _, c := range file.Comments { diff --git a/pkg/golinters/nolintlint/internal/nolintlint_test.go b/pkg/golinters/nolintlint/internal/nolintlint_test.go index 788d6b5a84dd..b534fbf89511 100644 --- a/pkg/golinters/nolintlint/internal/nolintlint_test.go +++ b/pkg/golinters/nolintlint/internal/nolintlint_test.go @@ -19,7 +19,7 @@ func TestLinter_Run(t *testing.T) { needs Needs excludes []string contents string - expected []result.Issue + expected []*result.Issue }{ { desc: "when no explanation is provided", @@ -36,7 +36,7 @@ func foo() { other() //nolintother } `, - expected: []result.Issue{ + expected: []*result.Issue{ { FromLinter: "nolintlint", Text: "directive `//nolint` should provide explanation such as `//nolint // this is why`", @@ -69,7 +69,7 @@ func foo() { //nolint:dupl func foo() {} `, - expected: []result.Issue{{ + expected: []*result.Issue{{ FromLinter: "nolintlint", Text: "directive `//nolint:dupl` should provide explanation such as `//nolint:dupl // this is why`", Pos: token.Position{Filename: "testing.go", Offset: 47, Line: 5, Column: 1}, @@ -97,7 +97,7 @@ func foo() { bad() //nolint // because } `, - expected: []result.Issue{ + expected: []*result.Issue{ { FromLinter: "nolintlint", Text: "directive `//nolint` should mention specific linter such as `//nolint:my-linter`", @@ -120,7 +120,7 @@ func foo() { good() //nolint } `, - expected: []result.Issue{ + expected: []*result.Issue{ { FromLinter: "nolintlint", Text: "directive `// nolint` should be written without leading space as `//nolint`", @@ -158,7 +158,7 @@ func foo() { good() //nolint: linter1, linter2 } `, - expected: []result.Issue{{ + expected: []*result.Issue{{ FromLinter: "nolintlint", Text: "directive `//nolint:linter1 linter2` should match `//nolint[:] [// ]`", Pos: token.Position{Filename: "testing.go", Offset: 71, Line: 5, Column: 9}, @@ -183,7 +183,7 @@ func foo() { bad() //nolint } `, - expected: []result.Issue{{ + expected: []*result.Issue{{ FromLinter: "nolintlint", Text: "directive `//nolint` is unused", Pos: token.Position{Filename: "testing.go", Offset: 34, Line: 4, Column: 9}, @@ -205,7 +205,7 @@ func foo() { bad() //nolint:somelinter } `, - expected: []result.Issue{{ + expected: []*result.Issue{{ FromLinter: "nolintlint", Text: "directive `//nolint:somelinter` is unused for linter \"somelinter\"", Pos: token.Position{Filename: "testing.go", Offset: 34, Line: 4, Column: 9}, @@ -229,7 +229,7 @@ func foo() { bad() } `, - expected: []result.Issue{{ + expected: []*result.Issue{{ FromLinter: "nolintlint", Text: "directive `//nolint:somelinter` is unused for linter \"somelinter\"", Pos: token.Position{Filename: "testing.go", Offset: 13, Line: 3, Column: 1}, @@ -252,7 +252,7 @@ func foo() { bad() //nolint:linter1,linter2 } `, - expected: []result.Issue{ + expected: []*result.Issue{ { FromLinter: "nolintlint", Text: "directive `//nolint:linter1,linter2` is unused for linter \"linter1\"", @@ -289,7 +289,7 @@ func foo() { analysisIssues, err := linter.Run(pass) require.NoError(t, err) - var issues []result.Issue + var issues []*result.Issue for _, i := range analysisIssues { issues = append(issues, i.Issue) } diff --git a/pkg/golinters/nolintlint/nolintlint.go b/pkg/golinters/nolintlint/nolintlint.go index f19b8324c295..6f3d373063f8 100644 --- a/pkg/golinters/nolintlint/nolintlint.go +++ b/pkg/golinters/nolintlint/nolintlint.go @@ -17,7 +17,7 @@ const LinterName = nolintlint.LinterName func New(settings *config.NoLintLintSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue var needs nolintlint.Needs if settings.RequireExplanation { @@ -35,33 +35,29 @@ func New(settings *config.NoLintLintSettings) *goanalysis.Linter { internal.LinterLogger.Fatalf("%s: create analyzer: %v", nolintlint.LinterName, err) } - analyzer := &analysis.Analyzer{ - Name: nolintlint.LinterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := lnt.Run(pass) - if err != nil { - return nil, fmt.Errorf("linter failed to run: %w", err) - } + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: nolintlint.LinterName, + Doc: "Reports ill-formed or insufficient nolint directives", + Run: func(pass *analysis.Pass) (any, error) { + issues, err := lnt.Run(pass) + if err != nil { + return nil, fmt.Errorf("linter failed to run: %w", err) + } - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + if len(issues) == 0 { + return nil, nil + } - return nil, nil - }, - } + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return goanalysis.NewLinter( - nolintlint.LinterName, - "Reports ill-formed or insufficient nolint directives", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/nonamedreturns/nonamedreturns.go b/pkg/golinters/nonamedreturns/nonamedreturns.go index 91354f6a4492..4149ef818e20 100644 --- a/pkg/golinters/nonamedreturns/nonamedreturns.go +++ b/pkg/golinters/nonamedreturns/nonamedreturns.go @@ -2,28 +2,22 @@ package nonamedreturns import ( "github.com/firefart/nonamedreturns/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.NoNamedReturnsSettings) *goanalysis.Linter { - a := analyzer.Analyzer + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - analyzer.FlagReportErrorInDefer: settings.ReportErrorInDefer, - }, + cfg = map[string]any{ + analyzer.FlagReportErrorInDefer: settings.ReportErrorInDefer, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/nosprintfhostport/nosprintfhostport.go b/pkg/golinters/nosprintfhostport/nosprintfhostport.go index cca70680cf6c..f8ca26b738c9 100644 --- a/pkg/golinters/nosprintfhostport/nosprintfhostport.go +++ b/pkg/golinters/nosprintfhostport/nosprintfhostport.go @@ -2,18 +2,12 @@ package nosprintfhostport import ( "github.com/stbenjam/no-sprintf-host-port/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := analyzer.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/paralleltest/paralleltest.go b/pkg/golinters/paralleltest/paralleltest.go index 8c811ca511af..f3eac2e05afb 100644 --- a/pkg/golinters/paralleltest/paralleltest.go +++ b/pkg/golinters/paralleltest/paralleltest.go @@ -2,33 +2,28 @@ package paralleltest import ( "github.com/kunwardeep/paralleltest/pkg/paralleltest" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.ParallelTestSettings) *goanalysis.Linter { - a := paralleltest.NewAnalyzer() + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil { - d := map[string]any{ + cfg = map[string]any{ "i": settings.IgnoreMissing, "ignoremissingsubtests": settings.IgnoreMissingSubtests, } if config.IsGoGreaterThanOrEqual(settings.Go, "1.22") { - d["ignoreloopVar"] = true + cfg["ignoreloopVar"] = true } - - cfg = map[string]map[string]any{a.Name: d} } - return goanalysis.NewLinter( - a.Name, - "Detects missing usage of t.Parallel() method in your Go test", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(paralleltest.NewAnalyzer()). + WithDesc("Detects missing usage of t.Parallel() method in your Go test"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/paralleltest/testdata/paralleltest_cgo.go b/pkg/golinters/paralleltest/testdata/paralleltest_cgo.go deleted file mode 100644 index e961d17bf042..000000000000 --- a/pkg/golinters/paralleltest/testdata/paralleltest_cgo.go +++ /dev/null @@ -1,25 +0,0 @@ -//golangcitest:args -Eparalleltest -package testdata - -/* - #include - #include - - void myprint(char* s) { - printf("%d\n", s); - } -*/ -import "C" - -import ( - "testing" - "unsafe" -) - -func _() { - cs := C.CString("Hello from stdio\n") - C.myprint(cs) - C.free(unsafe.Pointer(cs)) -} - -func TestFunctionMissingCallToParallel(t *testing.T) {} // want "Function TestFunctionMissingCallToParallel missing the call to method parallel" diff --git a/pkg/golinters/paralleltest/testdata/paralleltest_custom.go b/pkg/golinters/paralleltest/testdata/paralleltest_custom_test.go similarity index 86% rename from pkg/golinters/paralleltest/testdata/paralleltest_custom.go rename to pkg/golinters/paralleltest/testdata/paralleltest_custom_test.go index c03b0996e70f..efd68f14241e 100644 --- a/pkg/golinters/paralleltest/testdata/paralleltest_custom.go +++ b/pkg/golinters/paralleltest/testdata/paralleltest_custom_test.go @@ -1,5 +1,5 @@ //golangcitest:args -Eparalleltest -//golangcitest:config_path testdata/paralleltest_custom.yml +//golangcitest:config_path testdata/paralleltest_custom_test.yml //golangcitest:expected_exitcode 0 package testdata diff --git a/pkg/golinters/paralleltest/testdata/paralleltest_custom.yml b/pkg/golinters/paralleltest/testdata/paralleltest_custom_test.yml similarity index 100% rename from pkg/golinters/paralleltest/testdata/paralleltest_custom.yml rename to pkg/golinters/paralleltest/testdata/paralleltest_custom_test.yml diff --git a/pkg/golinters/paralleltest/testdata/paralleltest.go b/pkg/golinters/paralleltest/testdata/paralleltest_test.go similarity index 100% rename from pkg/golinters/paralleltest/testdata/paralleltest.go rename to pkg/golinters/paralleltest/testdata/paralleltest_test.go diff --git a/pkg/golinters/perfsprint/perfsprint.go b/pkg/golinters/perfsprint/perfsprint.go index f870ee00115a..9684c27c6639 100644 --- a/pkg/golinters/perfsprint/perfsprint.go +++ b/pkg/golinters/perfsprint/perfsprint.go @@ -2,41 +2,36 @@ package perfsprint import ( "github.com/catenacyber/perfsprint/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.PerfSprintSettings) *goanalysis.Linter { - a := analyzer.New() - - cfg := map[string]map[string]any{ - a.Name: {"fiximports": false}, + cfg := map[string]any{ + "fiximports": false, } if settings != nil { // NOTE: The option `ignore-tests` is not handled because it should be managed with `linters.exclusions.rules` - cfg[a.Name]["integer-format"] = settings.IntegerFormat - cfg[a.Name]["int-conversion"] = settings.IntConversion + cfg["integer-format"] = settings.IntegerFormat + cfg["int-conversion"] = settings.IntConversion - cfg[a.Name]["error-format"] = settings.ErrorFormat - cfg[a.Name]["err-error"] = settings.ErrError - cfg[a.Name]["errorf"] = settings.ErrorF + cfg["error-format"] = settings.ErrorFormat + cfg["err-error"] = settings.ErrError + cfg["errorf"] = settings.ErrorF - cfg[a.Name]["string-format"] = settings.StringFormat - cfg[a.Name]["sprintf1"] = settings.SprintF1 - cfg[a.Name]["strconcat"] = settings.StrConcat + cfg["string-format"] = settings.StringFormat + cfg["sprintf1"] = settings.SprintF1 + cfg["strconcat"] = settings.StrConcat - cfg[a.Name]["bool-format"] = settings.BoolFormat - cfg[a.Name]["hex-format"] = settings.HexFormat + cfg["bool-format"] = settings.BoolFormat + cfg["hex-format"] = settings.HexFormat } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/prealloc/prealloc.go b/pkg/golinters/prealloc/prealloc.go index 1ceba6007ce0..c750df990459 100644 --- a/pkg/golinters/prealloc/prealloc.go +++ b/pkg/golinters/prealloc/prealloc.go @@ -11,25 +11,18 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) -const linterName = "prealloc" - func New(settings *config.PreallocSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - runPreAlloc(pass, settings) - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Finds slice declarations that could potentially be pre-allocated", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "prealloc", + Doc: "Find slice declarations that could potentially be pre-allocated", + Run: func(pass *analysis.Pass) (any, error) { + runPreAlloc(pass, settings) + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func runPreAlloc(pass *analysis.Pass, settings *config.PreallocSettings) { @@ -38,7 +31,7 @@ func runPreAlloc(pass *analysis.Pass, settings *config.PreallocSettings) { for _, hint := range hints { pass.Report(analysis.Diagnostic{ Pos: hint.Pos, - Message: fmt.Sprintf("Consider pre-allocating %s", internal.FormatCode(hint.DeclaredSliceName, nil)), + Message: fmt.Sprintf("Consider pre-allocating %s", internal.FormatCode(hint.DeclaredSliceName)), }) } } diff --git a/pkg/golinters/predeclared/predeclared.go b/pkg/golinters/predeclared/predeclared.go index 9bde9d2f3baa..8f2be53c4fc1 100644 --- a/pkg/golinters/predeclared/predeclared.go +++ b/pkg/golinters/predeclared/predeclared.go @@ -4,25 +4,23 @@ import ( "strings" "github.com/nishanths/predeclared/passes/predeclared" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.PredeclaredSettings) *goanalysis.Linter { - a := predeclared.Analyzer + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - predeclared.IgnoreFlag: strings.Join(settings.Ignore, ","), - predeclared.QualifiedFlag: settings.Qualified, - }, + cfg = map[string]any{ + predeclared.IgnoreFlag: strings.Join(settings.Ignore, ","), + predeclared.QualifiedFlag: settings.Qualified, } } - return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, cfg). + return goanalysis. + NewLinterFromAnalyzer(predeclared.Analyzer). + WithConfig(cfg). WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/promlinter/promlinter.go b/pkg/golinters/promlinter/promlinter.go index ab2c9c569dea..491409f4ef7a 100644 --- a/pkg/golinters/promlinter/promlinter.go +++ b/pkg/golinters/promlinter/promlinter.go @@ -17,7 +17,7 @@ const linterName = "promlinter" func New(settings *config.PromlinterSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue var promSettings promlinter.Setting if settings != nil { @@ -27,42 +27,38 @@ func New(settings *config.PromlinterSettings) *goanalysis.Linter { } } - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runPromLinter(pass, promSettings) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Check Prometheus metrics naming via promlint", + Run: func(pass *analysis.Pass) (any, error) { + issues := runPromLinter(pass, promSettings) - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + if len(issues) == 0 { + return nil, nil + } - return nil, nil - }, - } + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return goanalysis.NewLinter( - linterName, - "Check Prometheus metrics naming via promlint", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } -func runPromLinter(pass *analysis.Pass, promSettings promlinter.Setting) []goanalysis.Issue { +func runPromLinter(pass *analysis.Pass, promSettings promlinter.Setting) []*goanalysis.Issue { lintIssues := promlinter.RunLint(pass.Fset, pass.Files, promSettings) if len(lintIssues) == 0 { return nil } - issues := make([]goanalysis.Issue, len(lintIssues)) + issues := make([]*goanalysis.Issue, len(lintIssues)) for k, i := range lintIssues { issue := result.Issue{ Pos: i.Pos, diff --git a/pkg/golinters/protogetter/protogetter.go b/pkg/golinters/protogetter/protogetter.go index c13c98af5792..bee5da263915 100644 --- a/pkg/golinters/protogetter/protogetter.go +++ b/pkg/golinters/protogetter/protogetter.go @@ -2,7 +2,6 @@ package protogetter import ( "github.com/ghostiam/protogetter" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -10,6 +9,7 @@ import ( func New(settings *config.ProtoGetterSettings) *goanalysis.Linter { var cfg protogetter.Config + if settings != nil { cfg = protogetter.Config{ SkipGeneratedBy: settings.SkipGeneratedBy, @@ -19,12 +19,7 @@ func New(settings *config.ProtoGetterSettings) *goanalysis.Linter { } } - a := protogetter.NewAnalyzer(&cfg) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(protogetter.NewAnalyzer(&cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/protogetter/testdata/go.mod b/pkg/golinters/protogetter/testdata/go.mod index 04826463206b..ac7bf891a2f6 100644 --- a/pkg/golinters/protogetter/testdata/go.mod +++ b/pkg/golinters/protogetter/testdata/go.mod @@ -1,15 +1,15 @@ module protogetter -go 1.22.0 +go 1.23.0 require ( - google.golang.org/grpc v1.71.0 - google.golang.org/protobuf v1.36.5 + google.golang.org/grpc v1.72.2 + google.golang.org/protobuf v1.36.6 ) require ( - golang.org/x/net v0.34.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect ) diff --git a/pkg/golinters/protogetter/testdata/go.sum b/pkg/golinters/protogetter/testdata/go.sum index 387f3d99eb4c..88c148026714 100644 --- a/pkg/golinters/protogetter/testdata/go.sum +++ b/pkg/golinters/protogetter/testdata/go.sum @@ -20,15 +20,15 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= +google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= +google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= diff --git a/pkg/golinters/reassign/reassign.go b/pkg/golinters/reassign/reassign.go index 7d9f84285b89..35e661cae84b 100644 --- a/pkg/golinters/reassign/reassign.go +++ b/pkg/golinters/reassign/reassign.go @@ -5,28 +5,22 @@ import ( "strings" "github.com/curioswitch/go-reassign" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.ReassignSettings) *goanalysis.Linter { - a := reassign.NewAnalyzer() + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil && len(settings.Patterns) > 0 { - cfg = map[string]map[string]any{ - a.Name: { - reassign.FlagPattern: fmt.Sprintf("^(%s)$", strings.Join(settings.Patterns, "|")), - }, + cfg = map[string]any{ + reassign.FlagPattern: fmt.Sprintf("^(%s)$", strings.Join(settings.Patterns, "|")), } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(reassign.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/recvcheck/recvcheck.go b/pkg/golinters/recvcheck/recvcheck.go index ed1eb0b78765..76db48f93979 100644 --- a/pkg/golinters/recvcheck/recvcheck.go +++ b/pkg/golinters/recvcheck/recvcheck.go @@ -2,7 +2,6 @@ package recvcheck import ( "github.com/raeperd/recvcheck" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -16,12 +15,7 @@ func New(settings *config.RecvcheckSettings) *goanalysis.Linter { cfg.Exclusions = settings.Exclusions } - a := recvcheck.NewAnalyzer(cfg) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(recvcheck.NewAnalyzer(cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/revive/revive.go b/pkg/golinters/revive/revive.go index 544f398a06b1..3e13c516fa12 100644 --- a/pkg/golinters/revive/revive.go +++ b/pkg/golinters/revive/revive.go @@ -35,45 +35,44 @@ var ( func New(settings *config.ReviveSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, + Name: linterName, + Doc: "Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.", Run: goanalysis.DummyRun, } - return goanalysis.NewLinter( - linterName, - "Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - w, err := newWrapper(settings) - if err != nil { - lintCtx.Log.Errorf("setup revive: %v", err) - return - } - - analyzer.Run = func(pass *analysis.Pass) (any, error) { - issues, err := w.run(pass) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + w, err := newWrapper(settings) if err != nil { - return nil, err + lintCtx.Log.Errorf("setup revive: %v", err) + return } - if len(issues) == 0 { - return nil, nil - } + analyzer.Run = func(pass *analysis.Pass) (any, error) { + issues, err := w.run(pass) + if err != nil { + return nil, err + } - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + if len(issues) == 0 { + return nil, nil + } - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } type wrapper struct { @@ -107,7 +106,7 @@ func newWrapper(settings *config.ReviveSettings) (*wrapper, error) { }, nil } -func (w *wrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { +func (w *wrapper) run(pass *analysis.Pass) ([]*goanalysis.Issue, error) { packages := [][]string{internal.GetGoFileNames(pass)} failures, err := w.revive.Lint(packages, w.lintingRules, *w.conf) @@ -115,7 +114,7 @@ func (w *wrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { return nil, err } - var issues []goanalysis.Issue + var issues []*goanalysis.Issue for failure := range failures { if failure.Confidence < w.conf.Confidence { continue @@ -127,7 +126,7 @@ func (w *wrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { return issues, nil } -func (w *wrapper) toIssue(pass *analysis.Pass, failure *lint.Failure) goanalysis.Issue { +func (w *wrapper) toIssue(pass *analysis.Pass, failure *lint.Failure) *goanalysis.Issue { lineRangeTo := failure.Position.End.Line if failure.RuleName == (&rule.ExportedRule{}).Name() { lineRangeTo = failure.Position.Start.Line @@ -153,7 +152,7 @@ func (w *wrapper) toIssue(pass *analysis.Pass, failure *lint.Failure) goanalysis f := pass.Fset.File(token.Pos(failure.Position.Start.Offset)) // Skip cgo files because the positions are wrong. - if failure.GetFilename() == f.Name() { + if failure.Filename() == f.Name() { issue.SuggestedFixes = []analysis.SuggestedFix{{ TextEdits: []analysis.TextEdit{{ Pos: f.LineStart(failure.Position.Start.Line), @@ -270,7 +269,7 @@ func safeTomlSlice(r []any) []any { } // This element is not exported by revive, so we need copy the code. -// Extracted from https://github.com/mgechev/revive/blob/v1.6.0/config/config.go#L16 +// Extracted from https://github.com/mgechev/revive/blob/v1.10.0/config/config.go#L16 var defaultRules = []lint.Rule{ &rule.VarDeclarationsRule{}, &rule.PackageCommentsRule{}, @@ -298,66 +297,70 @@ var defaultRules = []lint.Rule{ } var allRules = append([]lint.Rule{ + &rule.AddConstantRule{}, &rule.ArgumentsLimitRule{}, - &rule.CyclomaticRule{}, - &rule.FileHeaderRule{}, + &rule.AtomicRule{}, + &rule.BannedCharsRule{}, + &rule.BareReturnRule{}, + &rule.BoolLiteralRule{}, + &rule.CallToGCRule{}, + &rule.CognitiveComplexityRule{}, + &rule.CommentsDensityRule{}, + &rule.CommentSpacingsRule{}, &rule.ConfusingNamingRule{}, - &rule.GetReturnRule{}, - &rule.ModifiesParamRule{}, &rule.ConfusingResultsRule{}, - &rule.DeepExitRule{}, - &rule.AddConstantRule{}, - &rule.FlagParamRule{}, - &rule.UnnecessaryStmtRule{}, - &rule.StructTagRule{}, - &rule.ModifiesValRecRule{}, &rule.ConstantLogicalExprRule{}, - &rule.BoolLiteralRule{}, - &rule.ImportsBlocklistRule{}, - &rule.FunctionResultsLimitRule{}, - &rule.MaxPublicStructsRule{}, - &rule.RangeValInClosureRule{}, - &rule.RangeValAddress{}, - &rule.WaitGroupByValueRule{}, - &rule.AtomicRule{}, - &rule.EmptyLinesRule{}, - &rule.LineLengthLimitRule{}, - &rule.CallToGCRule{}, + &rule.CyclomaticRule{}, + &rule.DataRaceRule{}, + &rule.DeepExitRule{}, + &rule.DeferRule{}, &rule.DuplicatedImportsRule{}, - &rule.ImportShadowingRule{}, - &rule.BareReturnRule{}, - &rule.UnusedReceiverRule{}, - &rule.UnhandledErrorRule{}, - &rule.CognitiveComplexityRule{}, - &rule.StringOfIntRule{}, - &rule.StringFormatRule{}, &rule.EarlyReturnRule{}, - &rule.UnconditionalRecursionRule{}, - &rule.IdenticalBranchesRule{}, - &rule.DeferRule{}, - &rule.UnexportedNamingRule{}, - &rule.FunctionLength{}, - &rule.NestedStructs{}, - &rule.UselessBreak{}, - &rule.UncheckedTypeAssertionRule{}, - &rule.TimeEqualRule{}, - &rule.BannedCharsRule{}, - &rule.OptimizeOperandsOrderRule{}, - &rule.UseAnyRule{}, - &rule.DataRaceRule{}, - &rule.CommentSpacingsRule{}, - &rule.IfReturnRule{}, - &rule.RedundantImportAlias{}, - &rule.ImportAliasNamingRule{}, + &rule.EmptyLinesRule{}, &rule.EnforceMapStyleRule{}, &rule.EnforceRepeatedArgTypeStyleRule{}, &rule.EnforceSliceStyleRule{}, - &rule.MaxControlNestingRule{}, - &rule.CommentsDensityRule{}, + &rule.FileHeaderRule{}, &rule.FileLengthLimitRule{}, &rule.FilenameFormatRule{}, + &rule.FlagParamRule{}, + &rule.FunctionLength{}, + &rule.FunctionResultsLimitRule{}, + &rule.GetReturnRule{}, + &rule.IdenticalBranchesRule{}, + &rule.IfReturnRule{}, + &rule.ImportAliasNamingRule{}, + &rule.ImportsBlocklistRule{}, + &rule.ImportShadowingRule{}, + &rule.LineLengthLimitRule{}, + &rule.MaxControlNestingRule{}, + &rule.MaxPublicStructsRule{}, + &rule.ModifiesParamRule{}, + &rule.ModifiesValRecRule{}, + &rule.NestedStructs{}, + &rule.OptimizeOperandsOrderRule{}, + &rule.RangeValAddress{}, + &rule.RangeValInClosureRule{}, &rule.RedundantBuildTagRule{}, + &rule.RedundantImportAlias{}, + &rule.RedundantTestMainExitRule{}, + &rule.StringFormatRule{}, + &rule.StringOfIntRule{}, + &rule.StructTagRule{}, + &rule.TimeDateRule{}, + &rule.TimeEqualRule{}, + &rule.UncheckedTypeAssertionRule{}, + &rule.UnconditionalRecursionRule{}, + &rule.UnexportedNamingRule{}, + &rule.UnhandledErrorRule{}, + &rule.UnnecessaryFormatRule{}, + &rule.UnnecessaryStmtRule{}, + &rule.UnusedReceiverRule{}, + &rule.UseAnyRule{}, &rule.UseErrorsNewRule{}, + &rule.UseFmtPrintRule{}, + &rule.UselessBreak{}, + &rule.WaitGroupByValueRule{}, }, defaultRules...) const defaultConfidence = 0.8 @@ -433,7 +436,7 @@ func displayRules(conf *lint.Config) { slices.Sort(enabledRules) debugf("All available rules (%d): %s.", len(allRules), strings.Join(extractRulesName(allRules), ", ")) - debugf("Default rules (%d): %s.", len(allRules), strings.Join(extractRulesName(allRules), ", ")) + debugf("Default rules (%d): %s.", len(defaultRules), strings.Join(extractRulesName(defaultRules), ", ")) debugf("Enabled by config rules (%d): %s.", len(enabledRules), strings.Join(enabledRules, ", ")) debugf("revive configuration: %#v", conf) @@ -453,11 +456,11 @@ func extractRulesName(rules []lint.Rule) []string { // Extracted from https://github.com/mgechev/revive/blob/v1.7.0/formatter/severity.go // Modified to use pointers (related to hugeParam rule). -func severity(config *lint.Config, failure *lint.Failure) lint.Severity { - if cfg, ok := config.Rules[failure.RuleName]; ok && cfg.Severity == lint.SeverityError { +func severity(cfg *lint.Config, failure *lint.Failure) lint.Severity { + if cfg, ok := cfg.Rules[failure.RuleName]; ok && cfg.Severity == lint.SeverityError { return lint.SeverityError } - if cfg, ok := config.Directives[failure.RuleName]; ok && cfg.Severity == lint.SeverityError { + if cfg, ok := cfg.Directives[failure.RuleName]; ok && cfg.Severity == lint.SeverityError { return lint.SeverityError } return lint.SeverityWarning diff --git a/pkg/golinters/rowserrcheck/rowserrcheck.go b/pkg/golinters/rowserrcheck/rowserrcheck.go index 2bd975ddf28f..de0fe4da917e 100644 --- a/pkg/golinters/rowserrcheck/rowserrcheck.go +++ b/pkg/golinters/rowserrcheck/rowserrcheck.go @@ -2,7 +2,6 @@ package rowserrcheck import ( "github.com/jingyugao/rowserrcheck/passes/rowserr" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -10,16 +9,13 @@ import ( func New(settings *config.RowsErrCheckSettings) *goanalysis.Linter { var pkgs []string + if settings != nil { pkgs = settings.Packages } - a := rowserr.NewAnalyzer(pkgs...) - - return goanalysis.NewLinter( - a.Name, - "checks whether Rows.Err of rows is checked successfully", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(rowserr.NewAnalyzer(pkgs...)). + WithDesc("checks whether Rows.Err of rows is checked successfully"). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/sloglint/sloglint.go b/pkg/golinters/sloglint/sloglint.go index 01e75e44ab48..891f1fcfdbdf 100644 --- a/pkg/golinters/sloglint/sloglint.go +++ b/pkg/golinters/sloglint/sloglint.go @@ -2,7 +2,6 @@ package sloglint import ( "go-simpler.org/sloglint" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -10,6 +9,7 @@ import ( func New(settings *config.SlogLintSettings) *goanalysis.Linter { var opts *sloglint.Options + if settings != nil { opts = &sloglint.Options{ NoMixedArgs: settings.NoMixedArgs, @@ -18,6 +18,7 @@ func New(settings *config.SlogLintSettings) *goanalysis.Linter { NoGlobal: settings.NoGlobal, ContextOnly: settings.Context, StaticMsg: settings.StaticMsg, + MsgStyle: settings.MsgStyle, NoRawKeys: settings.NoRawKeys, KeyNamingCase: settings.KeyNamingCase, ForbiddenKeys: settings.ForbiddenKeys, @@ -25,9 +26,7 @@ func New(settings *config.SlogLintSettings) *goanalysis.Linter { } } - a := sloglint.New(opts) - return goanalysis. - NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). + NewLinterFromAnalyzer(sloglint.New(opts)). WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/spancheck/spancheck.go b/pkg/golinters/spancheck/spancheck.go index 264623058b1e..345c36277447 100644 --- a/pkg/golinters/spancheck/spancheck.go +++ b/pkg/golinters/spancheck/spancheck.go @@ -2,7 +2,6 @@ package spancheck import ( "github.com/jjti/go-spancheck" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -25,9 +24,7 @@ func New(settings *config.SpancheckSettings) *goanalysis.Linter { } } - a := spancheck.NewAnalyzerWithConfig(cfg) - return goanalysis. - NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). + NewLinterFromAnalyzer(spancheck.NewAnalyzerWithConfig(cfg)). WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/spancheck/testdata/go.mod b/pkg/golinters/spancheck/testdata/go.mod index 838836345136..256ae9e1b2a9 100644 --- a/pkg/golinters/spancheck/testdata/go.mod +++ b/pkg/golinters/spancheck/testdata/go.mod @@ -1,15 +1,15 @@ module spancheck -go 1.22.0 +go 1.23.0 require ( - go.opentelemetry.io/otel v1.35.0 - go.opentelemetry.io/otel/trace v1.35.0 + go.opentelemetry.io/otel v1.36.0 + go.opentelemetry.io/otel/trace v1.36.0 ) require ( - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.36.0 // indirect ) diff --git a/pkg/golinters/spancheck/testdata/go.sum b/pkg/golinters/spancheck/testdata/go.sum index 98e72be93493..da8e1100881e 100644 --- a/pkg/golinters/spancheck/testdata/go.sum +++ b/pkg/golinters/spancheck/testdata/go.sum @@ -1,8 +1,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -13,11 +13,11 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/golinters/sqlclosecheck/sqlclosecheck.go b/pkg/golinters/sqlclosecheck/sqlclosecheck.go index 7f7e70c71401..4c970cc5295d 100644 --- a/pkg/golinters/sqlclosecheck/sqlclosecheck.go +++ b/pkg/golinters/sqlclosecheck/sqlclosecheck.go @@ -2,18 +2,12 @@ package sqlclosecheck import ( "github.com/ryanrolds/sqlclosecheck/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := analyzer.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/staticcheck/staticcheck.go b/pkg/golinters/staticcheck/staticcheck.go index 1ec39244c100..7aae52870cbb 100644 --- a/pkg/golinters/staticcheck/staticcheck.go +++ b/pkg/golinters/staticcheck/staticcheck.go @@ -15,6 +15,12 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +var ( + debugf = logutils.Debug(logutils.DebugKeyStaticcheck) + isDebug = logutils.HaveDebugTag(logutils.DebugKeyStaticcheck) ) func New(settings *config.StaticCheckSettings) *goanalysis.Linter { @@ -29,6 +35,21 @@ func New(settings *config.StaticCheckSettings) *goanalysis.Linter { analyzers := setupAnalyzers(allAnalyzers, cfg.Checks) + if isDebug { + allAnalyzerNames := extractAnalyzerNames(allAnalyzers) + slices.Sort(allAnalyzerNames) + debugf("All available checks (%d): %s", len(allAnalyzers), strings.Join(allAnalyzerNames, ",")) + + var cfgAnalyzerNames []string + for _, a := range analyzers { + cfgAnalyzerNames = append(cfgAnalyzerNames, a.Name) + } + slices.Sort(cfgAnalyzerNames) + debugf("Enabled by config checks (%d): %s", len(analyzers), strings.Join(cfgAnalyzerNames, ",")) + + debugf("staticcheck configuration: %#v", cfg) + } + return goanalysis.NewLinter( "staticcheck", "It's the set of rules from staticcheck.", @@ -107,12 +128,7 @@ func normalizeList(list []string) []string { } func setupAnalyzers(src []*lint.Analyzer, checks []string) []*analysis.Analyzer { - var names []string - for _, a := range src { - names = append(names, a.Analyzer.Name) - } - - filter := filterAnalyzerNames(names, checks) + filter := filterAnalyzerNames(extractAnalyzerNames(src), checks) var ret []*analysis.Analyzer for _, a := range src { @@ -124,6 +140,14 @@ func setupAnalyzers(src []*lint.Analyzer, checks []string) []*analysis.Analyzer return ret } +func extractAnalyzerNames(analyzers []*lint.Analyzer) []string { + var names []string + for _, a := range analyzers { + names = append(names, a.Analyzer.Name) + } + return names +} + // https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/lintcmd/lint.go#L437-L477 // //nolint:gocritic // Keep the original source code. diff --git a/pkg/golinters/swaggo/swaggo.go b/pkg/golinters/swaggo/swaggo.go new file mode 100644 index 000000000000..98f7a6bef4dc --- /dev/null +++ b/pkg/golinters/swaggo/swaggo.go @@ -0,0 +1,20 @@ +package swaggo + +import ( + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(swaggo.Name), + "Check if swaggo comments are formatted", + swaggo.New(), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/golinters/swaggo/swaggo_integration_test.go b/pkg/golinters/swaggo/swaggo_integration_test.go new file mode 100644 index 000000000000..23fd3f1ff788 --- /dev/null +++ b/pkg/golinters/swaggo/swaggo_integration_test.go @@ -0,0 +1,19 @@ +package swaggo + +import ( + "testing" + + "github.com/golangci/golangci-lint/v2/test/testshared/integration" +) + +func TestFromTestdata(t *testing.T) { + integration.RunTestdata(t) +} + +func TestFix(t *testing.T) { + integration.RunFix(t) +} + +func TestFixPathPrefix(t *testing.T) { + integration.RunFixPathPrefix(t) +} diff --git a/pkg/golinters/swaggo/testdata/fix/in/swaggo.go b/pkg/golinters/swaggo/testdata/fix/in/swaggo.go new file mode 100644 index 000000000000..33c814b2805b --- /dev/null +++ b/pkg/golinters/swaggo/testdata/fix/in/swaggo.go @@ -0,0 +1,18 @@ +//golangcitest:config_path testdata/swaggo.yml +//golangcitest:expected_exitcode 0 +package api + +import "net/http" + +// @Summary Add a new pet to the store +// @Description get string by ID +// @ID get-string-by-int +// @Accept json +// @Produce json +// @Param some_id path int true "Some ID" Format(int64) +// @Param some_id body web.Pet true "Some ID" +// @Success 200 {string} string "ok" +// @Failure 400 {object} web.APIError "We need ID!!" +// @Failure 404 {object} web.APIError "Can not find ID" +// @Router /testapi/get-string-by-int/{some_id} [get] +func GetStringByInt(w http.ResponseWriter, r *http.Request) {} diff --git a/pkg/golinters/swaggo/testdata/fix/out/swaggo.go b/pkg/golinters/swaggo/testdata/fix/out/swaggo.go new file mode 100644 index 000000000000..8c4d2a2cdd40 --- /dev/null +++ b/pkg/golinters/swaggo/testdata/fix/out/swaggo.go @@ -0,0 +1,18 @@ +//golangcitest:config_path testdata/swaggo.yml +//golangcitest:expected_exitcode 0 +package api + +import "net/http" + +// @Summary Add a new pet to the store +// @Description get string by ID +// @ID get-string-by-int +// @Accept json +// @Produce json +// @Param some_id path int true "Some ID" Format(int64) +// @Param some_id body web.Pet true "Some ID" +// @Success 200 {string} string "ok" +// @Failure 400 {object} web.APIError "We need ID!!" +// @Failure 404 {object} web.APIError "Can not find ID" +// @Router /testapi/get-string-by-int/{some_id} [get] +func GetStringByInt(w http.ResponseWriter, r *http.Request) {} diff --git a/pkg/golinters/swaggo/testdata/swaggo.go b/pkg/golinters/swaggo/testdata/swaggo.go new file mode 100644 index 000000000000..db6b7da9dcfc --- /dev/null +++ b/pkg/golinters/swaggo/testdata/swaggo.go @@ -0,0 +1,18 @@ +//golangcitest:config_path testdata/swaggo.yml +package api + +import "net/http" + +// want +1 "File is not properly formatted" +// @Summary Add a new pet to the store +// @Description get string by ID +// @ID get-string-by-int +// @Accept json +// @Produce json +// @Param some_id path int true "Some ID" Format(int64) +// @Param some_id body web.Pet true "Some ID" +// @Success 200 {string} string "ok" +// @Failure 400 {object} web.APIError "We need ID!!" +// @Failure 404 {object} web.APIError "Can not find ID" +// @Router /testapi/get-string-by-int/{some_id} [get] +func GetStringByInt(w http.ResponseWriter, r *http.Request) {} diff --git a/pkg/golinters/swaggo/testdata/swaggo.yml b/pkg/golinters/swaggo/testdata/swaggo.yml new file mode 100644 index 000000000000..458e2fca7eeb --- /dev/null +++ b/pkg/golinters/swaggo/testdata/swaggo.yml @@ -0,0 +1,5 @@ +version: "2" + +formatters: + enable: + - swaggo diff --git a/pkg/golinters/tagalign/tagalign.go b/pkg/golinters/tagalign/tagalign.go index 412d69b937ef..eba51311c0cf 100644 --- a/pkg/golinters/tagalign/tagalign.go +++ b/pkg/golinters/tagalign/tagalign.go @@ -2,7 +2,6 @@ package tagalign import ( "github.com/4meepo/tagalign" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -24,12 +23,7 @@ func New(settings *config.TagAlignSettings) *goanalysis.Linter { } } - analyzer := tagalign.NewAnalyzer(options...) - - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(tagalign.NewAnalyzer(options...)). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/tagliatelle/tagliatelle.go b/pkg/golinters/tagliatelle/tagliatelle.go index f6357e0e3747..e12cc9e82062 100644 --- a/pkg/golinters/tagliatelle/tagliatelle.go +++ b/pkg/golinters/tagliatelle/tagliatelle.go @@ -1,8 +1,9 @@ package tagliatelle import ( + "maps" + "github.com/ldez/tagliatelle" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -20,9 +21,7 @@ func New(settings *config.TagliatelleSettings) *goanalysis.Linter { } if settings != nil { - for k, v := range settings.Case.Rules { - cfg.Rules[k] = v - } + maps.Copy(cfg.Rules, settings.Case.Rules) cfg.ExtendedRules = toExtendedRules(settings.Case.ExtendedRules) cfg.UseFieldName = settings.Case.UseFieldName @@ -42,14 +41,9 @@ func New(settings *config.TagliatelleSettings) *goanalysis.Linter { } } - a := tagliatelle.New(cfg) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(tagliatelle.New(cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) } func toExtendedRules(src map[string]config.TagliatelleExtendedRule) map[string]tagliatelle.ExtendedRule { diff --git a/pkg/golinters/testableexamples/testableexamples.go b/pkg/golinters/testableexamples/testableexamples.go index 38334a096237..45fdc900e2c3 100644 --- a/pkg/golinters/testableexamples/testableexamples.go +++ b/pkg/golinters/testableexamples/testableexamples.go @@ -2,18 +2,12 @@ package testableexamples import ( "github.com/maratori/testableexamples/pkg/testableexamples" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := testableexamples.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(testableexamples.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/testifylint/testifylint.go b/pkg/golinters/testifylint/testifylint.go index b19471c1ea05..bb5eac0e451e 100644 --- a/pkg/golinters/testifylint/testifylint.go +++ b/pkg/golinters/testifylint/testifylint.go @@ -2,18 +2,16 @@ package testifylint import ( "github.com/Antonboom/testifylint/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.TestifylintSettings) *goanalysis.Linter { - a := analyzer.New() + var cfg map[string]any - cfg := make(map[string]map[string]any) if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "enable-all": settings.EnableAll, "disable-all": settings.DisableAll, @@ -23,30 +21,28 @@ func New(settings *config.TestifylintSettings) *goanalysis.Linter { "go-require.ignore-http-handlers": settings.GoRequire.IgnoreHTTPHandlers, } if len(settings.EnabledCheckers) > 0 { - cfg[a.Name]["enable"] = settings.EnabledCheckers + cfg["enable"] = settings.EnabledCheckers } if len(settings.DisabledCheckers) > 0 { - cfg[a.Name]["disable"] = settings.DisabledCheckers + cfg["disable"] = settings.DisabledCheckers } if b := settings.Formatter.CheckFormatString; b != nil { - cfg[a.Name]["formatter.check-format-string"] = *b + cfg["formatter.check-format-string"] = *b } if p := settings.ExpectedActual.ExpVarPattern; p != "" { - cfg[a.Name]["expected-actual.pattern"] = p + cfg["expected-actual.pattern"] = p } if p := settings.RequireError.FnPattern; p != "" { - cfg[a.Name]["require-error.fn-pattern"] = p + cfg["require-error.fn-pattern"] = p } if m := settings.SuiteExtraAssertCall.Mode; m != "" { - cfg[a.Name]["suite-extra-assert-call.mode"] = m + cfg["suite-extra-assert-call.mode"] = m } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/testpackage/testpackage.go b/pkg/golinters/testpackage/testpackage.go index ddd5ce95cd15..39c333f1b56d 100644 --- a/pkg/golinters/testpackage/testpackage.go +++ b/pkg/golinters/testpackage/testpackage.go @@ -4,25 +4,23 @@ import ( "strings" "github.com/maratori/testpackage/pkg/testpackage" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.TestpackageSettings) *goanalysis.Linter { - a := testpackage.NewAnalyzer() + var cfg map[string]any - var cfg map[string]map[string]any if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - testpackage.SkipRegexpFlagName: settings.SkipRegexp, - testpackage.AllowPackagesFlagName: strings.Join(settings.AllowPackages, ","), - }, + cfg = map[string]any{ + testpackage.SkipRegexpFlagName: settings.SkipRegexp, + testpackage.AllowPackagesFlagName: strings.Join(settings.AllowPackages, ","), } } - return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, cfg). + return goanalysis. + NewLinterFromAnalyzer(testpackage.NewAnalyzer()). + WithConfig(cfg). WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/thelper/thelper.go b/pkg/golinters/thelper/thelper.go index d9058582d83c..77090c5f8b15 100644 --- a/pkg/golinters/thelper/thelper.go +++ b/pkg/golinters/thelper/thelper.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/kulti/thelper/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -14,8 +13,6 @@ import ( ) func New(settings *config.ThelperSettings) *goanalysis.Linter { - a := analyzer.NewAnalyzer() - opts := map[string]struct{}{ "t_name": {}, "t_begin": {}, @@ -47,18 +44,14 @@ func New(settings *config.ThelperSettings) *goanalysis.Linter { args := slices.Collect(maps.Keys(opts)) - cfg := map[string]map[string]any{ - a.Name: { - "checks": strings.Join(args, ","), - }, + cfg := map[string]any{ + "checks": strings.Join(args, ","), } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } func applyTHelperOptions(o config.ThelperOptions, prefix string, opts map[string]struct{}) { diff --git a/pkg/golinters/tparallel/tparallel.go b/pkg/golinters/tparallel/tparallel.go index f3ce2fcf7975..480ef3b1e92b 100644 --- a/pkg/golinters/tparallel/tparallel.go +++ b/pkg/golinters/tparallel/tparallel.go @@ -2,17 +2,12 @@ package tparallel import ( "github.com/moricho/tparallel" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := tparallel.Analyzer - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(tparallel.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/typecheck.go b/pkg/golinters/typecheck.go index ad51e8d00f90..db29f7c18394 100644 --- a/pkg/golinters/typecheck.go +++ b/pkg/golinters/typecheck.go @@ -7,18 +7,11 @@ import ( ) func NewTypecheck() *goanalysis.Linter { - const linterName = "typecheck" - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - linterName, - "Like the front-end of a Go compiler, parses and type-checks Go code", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeNone) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "typecheck", + Doc: "Like the front-end of a Go compiler, parses and type-checks Go code", + Run: goanalysis.DummyRun, + }). + WithLoadMode(goanalysis.LoadModeNone) } diff --git a/pkg/golinters/unconvert/unconvert.go b/pkg/golinters/unconvert/unconvert.go index 5ca8e09ad110..593dfbe96e63 100644 --- a/pkg/golinters/unconvert/unconvert.go +++ b/pkg/golinters/unconvert/unconvert.go @@ -16,40 +16,39 @@ const linterName = "unconvert" func New(settings *config.UnconvertSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runUnconvert(pass, settings) + unconvert.SetFastMath(settings.FastMath) + unconvert.SetSafe(settings.Safe) - if len(issues) == 0 { - return nil, nil - } + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Remove unnecessary type conversions", + Run: func(pass *analysis.Pass) (any, error) { + issues := runUnconvert(pass) - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + if len(issues) == 0 { + return nil, nil + } - return nil, nil - }, - } + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return goanalysis.NewLinter( - linterName, - "Remove unnecessary type conversions", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runUnconvert(pass *analysis.Pass, settings *config.UnconvertSettings) []goanalysis.Issue { - positions := unconvert.Run(pass, settings.FastMath, settings.Safe) +func runUnconvert(pass *analysis.Pass) []*goanalysis.Issue { + positions := unconvert.Run(pass) - var issues []goanalysis.Issue + var issues []*goanalysis.Issue for _, position := range positions { issues = append(issues, goanalysis.NewIssue(&result.Issue{ Pos: position, diff --git a/pkg/golinters/unparam/unparam.go b/pkg/golinters/unparam/unparam.go index 5a9bc8a5e473..b6cb2668b076 100644 --- a/pkg/golinters/unparam/unparam.go +++ b/pkg/golinters/unparam/unparam.go @@ -10,29 +10,22 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) -const linterName = "unparam" - func New(settings *config.UnparamSettings) *goanalysis.Linter { - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Requires: []*analysis.Analyzer{buildssa.Analyzer}, - Run: func(pass *analysis.Pass) (any, error) { - err := runUnparam(pass, settings) - if err != nil { - return nil, err - } - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Reports unused function parameters", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "unparam", + Doc: "Reports unused function parameters", + Requires: []*analysis.Analyzer{buildssa.Analyzer}, + Run: func(pass *analysis.Pass) (any, error) { + err := runUnparam(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } func runUnparam(pass *analysis.Pass, settings *config.UnparamSettings) error { diff --git a/pkg/golinters/unused/unused.go b/pkg/golinters/unused/unused.go index 375962259676..c0f4657dcc26 100644 --- a/pkg/golinters/unused/unused.go +++ b/pkg/golinters/unused/unused.go @@ -20,7 +20,7 @@ const linterName = "unused" func New(settings *config.UnusedSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue analyzer := &analysis.Analyzer{ Name: linterName, @@ -45,12 +45,12 @@ func New(settings *config.UnusedSettings) *goanalysis.Linter { "Checks Go code for unused constants, variables, functions and types", []*analysis.Analyzer{analyzer}, nil, - ).WithIssuesReporter(func(_ *linter.Context) []goanalysis.Issue { + ).WithIssuesReporter(func(_ *linter.Context) []*goanalysis.Issue { return resIssues }).WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []goanalysis.Issue { +func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []*goanalysis.Issue { res := getUnusedResults(pass, cfg) used := make(map[string]bool) @@ -58,7 +58,7 @@ func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []goanalysis.Iss used[fmt.Sprintf("%s %d %s", obj.Position.Filename, obj.Position.Line, obj.Name)] = true } - var issues []goanalysis.Issue + var issues []*goanalysis.Issue // Inspired by https://github.com/dominikh/go-tools/blob/d694aadcb1f50c2d8ac0a1dd06217ebb9f654764/lintcmd/lint.go#L177-L197 for _, object := range res.Unused { diff --git a/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.go b/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.go index 14f4a93a6b3c..9eee473f0d6d 100644 --- a/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.go +++ b/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.go @@ -2,7 +2,10 @@ //golangcitest:config_path testdata/usestdlibvars_non_default.yml package testdata -import "net/http" +import ( + "net/http" + "time" +) func _200() { _ = 200 @@ -52,3 +55,8 @@ const ( _ = "ECDSAWithP256AndSHA256" // want `"ECDSAWithP256AndSHA256" can be replaced by tls\.ECDSAWithP256AndSHA256\.String\(\)` _ = "ECDSAWithP384AndSHA384" // want `"ECDSAWithP384AndSHA384" can be replaced by tls\.ECDSAWithP384AndSHA384\.String\(\)` ) + +func _() { + var _ = time.Date(2023, 1, 2, 3, 4, 5, 0, time.UTC) // want `"1" can be replaced by time\.January` + var _ = time.Date(2023, 10, 2, 3, 4, 5, 0, time.UTC) // want `"10" can be replaced by time\.October` +} diff --git a/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.yml b/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.yml index 8100af59cdb1..d2942621daee 100644 --- a/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.yml +++ b/pkg/golinters/usestdlibvars/testdata/usestdlibvars_non_default.yml @@ -13,3 +13,4 @@ linters: sql-isolation-level: true tls-signature-scheme: true constant-kind: true + time-date-month: true diff --git a/pkg/golinters/usestdlibvars/usestdlibvars.go b/pkg/golinters/usestdlibvars/usestdlibvars.go index f0b5f5420d00..e4a900ff6465 100644 --- a/pkg/golinters/usestdlibvars/usestdlibvars.go +++ b/pkg/golinters/usestdlibvars/usestdlibvars.go @@ -2,18 +2,16 @@ package usestdlibvars import ( "github.com/sashamelentyev/usestdlibvars/pkg/analyzer" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.UseStdlibVarsSettings) *goanalysis.Linter { - a := analyzer.New() + var cfg map[string]any - cfg := make(map[string]map[string]any) if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ analyzer.ConstantKindFlag: settings.ConstantKind, analyzer.CryptoHashFlag: settings.CryptoHash, analyzer.HTTPMethodFlag: settings.HTTPMethod, @@ -26,13 +24,12 @@ func New(settings *config.UseStdlibVarsSettings) *goanalysis.Linter { analyzer.TimeMonthFlag: settings.TimeMonth, analyzer.TimeWeekdayFlag: settings.TimeWeekday, analyzer.TLSSignatureSchemeFlag: settings.TLSSignatureScheme, + analyzer.TimeDateMonthFlag: settings.TimeDateMonth, } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/usetesting/usetesting.go b/pkg/golinters/usetesting/usetesting.go index 5dfa9f11ad54..7371cc28eb01 100644 --- a/pkg/golinters/usetesting/usetesting.go +++ b/pkg/golinters/usetesting/usetesting.go @@ -2,18 +2,16 @@ package usetesting import ( "github.com/ldez/usetesting" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.UseTestingSettings) *goanalysis.Linter { - a := usetesting.NewAnalyzer() + var cfg map[string]any - cfg := make(map[string]map[string]any) if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "contextbackground": settings.ContextBackground, "contexttodo": settings.ContextTodo, "oschdir": settings.OSChdir, @@ -24,10 +22,8 @@ func New(settings *config.UseTestingSettings) *goanalysis.Linter { } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(usetesting.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/varnamelen/varnamelen.go b/pkg/golinters/varnamelen/varnamelen.go index dbd8005ee0d1..a19d7987ddcd 100644 --- a/pkg/golinters/varnamelen/varnamelen.go +++ b/pkg/golinters/varnamelen/varnamelen.go @@ -5,15 +5,13 @@ import ( "strings" "github.com/blizzy78/varnamelen" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.VarnamelenSettings) *goanalysis.Linter { - analyzer := varnamelen.NewAnalyzer() - cfg := map[string]map[string]any{} + var cfg map[string]any if settings != nil { vnlCfg := map[string]any{ @@ -30,17 +28,15 @@ func New(settings *config.VarnamelenSettings) *goanalysis.Linter { if settings.MaxDistance > 0 { vnlCfg["maxDistance"] = strconv.Itoa(settings.MaxDistance) } + if settings.MinNameLength > 0 { vnlCfg["minNameLength"] = strconv.Itoa(settings.MinNameLength) } - - cfg[analyzer.Name] = vnlCfg } - return goanalysis.NewLinter( - analyzer.Name, - "checks that the length of a variable's name matches its scope", - []*analysis.Analyzer{analyzer}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(varnamelen.NewAnalyzer()). + WithDesc("checks that the length of a variable's name matches its scope"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/wastedassign/wastedassign.go b/pkg/golinters/wastedassign/wastedassign.go index 6599f7d4dace..d103a8d5a55b 100644 --- a/pkg/golinters/wastedassign/wastedassign.go +++ b/pkg/golinters/wastedassign/wastedassign.go @@ -2,18 +2,13 @@ package wastedassign import ( "github.com/sanposhiho/wastedassign/v2" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := wastedassign.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Finds wasted assignment statements", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(wastedassign.Analyzer). + WithDesc("Finds wasted assignment statements"). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/whitespace/whitespace.go b/pkg/golinters/whitespace/whitespace.go index cd7fda1ce0d0..bf03e1d8088b 100644 --- a/pkg/golinters/whitespace/whitespace.go +++ b/pkg/golinters/whitespace/whitespace.go @@ -2,7 +2,6 @@ package whitespace import ( "github.com/ultraware/whitespace" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -17,12 +16,7 @@ func New(settings *config.WhitespaceSettings) *goanalysis.Linter { } } - a := whitespace.NewAnalyzer(&wsSettings) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(whitespace.NewAnalyzer(&wsSettings)). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/wrapcheck/wrapcheck.go b/pkg/golinters/wrapcheck/wrapcheck.go index 8918a82eaf1a..c29c509a80fd 100644 --- a/pkg/golinters/wrapcheck/wrapcheck.go +++ b/pkg/golinters/wrapcheck/wrapcheck.go @@ -2,7 +2,6 @@ package wrapcheck import ( "github.com/tomarrell/wrapcheck/v2/wrapcheck" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -10,8 +9,10 @@ import ( func New(settings *config.WrapcheckSettings) *goanalysis.Linter { cfg := wrapcheck.NewDefaultConfig() + if settings != nil { cfg.ExtraIgnoreSigs = settings.ExtraIgnoreSigs + cfg.ReportInternalErrors = settings.ReportInternalErrors if len(settings.IgnoreSigs) != 0 { cfg.IgnoreSigs = settings.IgnoreSigs @@ -27,12 +28,7 @@ func New(settings *config.WrapcheckSettings) *goanalysis.Linter { } } - a := wrapcheck.NewAnalyzer(cfg) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(wrapcheck.NewAnalyzer(cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/golinters/wsl/wsl.go b/pkg/golinters/wsl/wsl.go index 12148627eb5b..c71706f5c1d3 100644 --- a/pkg/golinters/wsl/wsl.go +++ b/pkg/golinters/wsl/wsl.go @@ -2,7 +2,6 @@ package wsl import ( "github.com/bombsimon/wsl/v4" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" @@ -10,6 +9,7 @@ import ( func New(settings *config.WSLSettings) *goanalysis.Linter { var conf *wsl.Configuration + if settings != nil { conf = &wsl.Configuration{ StrictAppend: settings.StrictAppend, @@ -30,12 +30,7 @@ func New(settings *config.WSLSettings) *goanalysis.Linter { } } - a := wsl.NewAnalyzer(conf) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(wsl.NewAnalyzer(conf)). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/pkg/golinters/zerologlint/testdata/go.mod b/pkg/golinters/zerologlint/testdata/go.mod index 5d75bdc3f5f4..6e255ef19b13 100644 --- a/pkg/golinters/zerologlint/testdata/go.mod +++ b/pkg/golinters/zerologlint/testdata/go.mod @@ -1,11 +1,11 @@ module zerologlint -go 1.19 +go 1.23.0 -require github.com/rs/zerolog v1.33.0 +require github.com/rs/zerolog v1.34.0 require ( - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - golang.org/x/sys v0.25.0 // indirect + golang.org/x/sys v0.33.0 // indirect ) diff --git a/pkg/golinters/zerologlint/testdata/go.sum b/pkg/golinters/zerologlint/testdata/go.sum index b52b48f18cd0..3b0d10eedda7 100644 --- a/pkg/golinters/zerologlint/testdata/go.sum +++ b/pkg/golinters/zerologlint/testdata/go.sum @@ -1,17 +1,18 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= diff --git a/pkg/golinters/zerologlint/zerologlint.go b/pkg/golinters/zerologlint/zerologlint.go index 0daf0d48a4d6..46832da96c8b 100644 --- a/pkg/golinters/zerologlint/zerologlint.go +++ b/pkg/golinters/zerologlint/zerologlint.go @@ -2,18 +2,12 @@ package zerologlint import ( "github.com/ykadowak/zerologlint" - "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New() *goanalysis.Linter { - a := zerologlint.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(zerologlint.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/pkg/lint/linter/linter.go b/pkg/lint/linter/linter.go index 7f68545cf159..e6b484efbb05 100644 --- a/pkg/lint/linter/linter.go +++ b/pkg/lint/linter/linter.go @@ -8,7 +8,7 @@ import ( ) type Linter interface { - Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) + Run(ctx context.Context, lintCtx *Context) ([]*result.Issue, error) Name() string Desc() string } @@ -43,7 +43,7 @@ func NewNoopDeprecated(name string, cfg *config.Config, level DeprecationLevel) return noop } -func (n Noop) Run(_ context.Context, lintCtx *Context) ([]result.Issue, error) { +func (n Noop) Run(_ context.Context, lintCtx *Context) ([]*result.Issue, error) { if n.reason == "" { return nil, nil } diff --git a/pkg/lint/lintersdb/builder_linter.go b/pkg/lint/lintersdb/builder_linter.go index 6c533d2e4878..734aab63cd1c 100644 --- a/pkg/lint/lintersdb/builder_linter.go +++ b/pkg/lint/lintersdb/builder_linter.go @@ -3,6 +3,7 @@ package lintersdb import ( "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/golinters" + "github.com/golangci/golangci-lint/v2/pkg/golinters/arangolint" "github.com/golangci/golangci-lint/v2/pkg/golinters/asasalint" "github.com/golangci/golangci-lint/v2/pkg/golinters/asciicheck" "github.com/golangci/golangci-lint/v2/pkg/golinters/bidichk" @@ -18,6 +19,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/dupl" "github.com/golangci/golangci-lint/v2/pkg/golinters/dupword" "github.com/golangci/golangci-lint/v2/pkg/golinters/durationcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/embeddedstructfieldcheck" "github.com/golangci/golangci-lint/v2/pkg/golinters/err113" "github.com/golangci/golangci-lint/v2/pkg/golinters/errcheck" "github.com/golangci/golangci-lint/v2/pkg/golinters/errchkjson" @@ -29,6 +31,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/fatcontext" "github.com/golangci/golangci-lint/v2/pkg/golinters/forbidigo" "github.com/golangci/golangci-lint/v2/pkg/golinters/forcetypeassert" + "github.com/golangci/golangci-lint/v2/pkg/golinters/funcorder" "github.com/golangci/golangci-lint/v2/pkg/golinters/funlen" "github.com/golangci/golangci-lint/v2/pkg/golinters/gci" "github.com/golangci/golangci-lint/v2/pkg/golinters/ginkgolinter" @@ -76,6 +79,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/nilnil" "github.com/golangci/golangci-lint/v2/pkg/golinters/nlreturn" "github.com/golangci/golangci-lint/v2/pkg/golinters/noctx" + "github.com/golangci/golangci-lint/v2/pkg/golinters/noinlineerr" "github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint" "github.com/golangci/golangci-lint/v2/pkg/golinters/nonamedreturns" "github.com/golangci/golangci-lint/v2/pkg/golinters/nosprintfhostport" @@ -93,6 +97,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/golinters/spancheck" "github.com/golangci/golangci-lint/v2/pkg/golinters/sqlclosecheck" "github.com/golangci/golangci-lint/v2/pkg/golinters/staticcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/swaggo" "github.com/golangci/golangci-lint/v2/pkg/golinters/tagalign" "github.com/golangci/golangci-lint/v2/pkg/golinters/tagliatelle" "github.com/golangci/golangci-lint/v2/pkg/golinters/testableexamples" @@ -129,9 +134,16 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { return nil, nil } + placeholderReplacer := config.NewPlaceholderReplacer(cfg) + // The linters are sorted in the alphabetical order (case-insensitive). // When a new linter is added the version in `WithSince(...)` must be the next minor version of golangci-lint. return []*linter.Config{ + linter.NewConfig(arangolint.New()). + WithSince("v2.2.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/Crocmagnon/arangolint"), + linter.NewConfig(asasalint.New(&cfg.Linters.Settings.Asasalint)). WithSince("v1.47.0"). WithLoadForGoAnalysis(). @@ -180,7 +192,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithSince("v1.44.0"). WithURL("https://gitlab.com/bosi/decorder"), - linter.NewConfig(depguard.New(&cfg.Linters.Settings.Depguard, cfg.GetBasePath())). + linter.NewConfig(depguard.New(&cfg.Linters.Settings.Depguard, placeholderReplacer)). WithSince("v1.4.0"). WithURL("https://github.com/OpenPeeDeeP/depguard"), @@ -202,6 +214,10 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithLoadForGoAnalysis(). WithURL("https://github.com/charithe/durationcheck"), + linter.NewConfig(embeddedstructfieldcheck.New(&cfg.Linters.Settings.EmbeddedStructFieldCheck)). + WithSince("v2.2.0"). + WithURL("https://github.com/manuelarte/embeddedstructfieldcheck"), + linter.NewConfig(errcheck.New(&cfg.Linters.Settings.Errcheck)). WithGroups(config.GroupStandard). WithSince("v1.0.0"). @@ -254,6 +270,10 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithLoadForGoAnalysis(). WithURL("https://github.com/gostaticanalysis/forcetypeassert"), + linter.NewConfig(funcorder.New(&cfg.Linters.Settings.FuncOrder)). + WithSince("v2.1.0"). + WithURL("https://github.com/manuelarte/funcorder"), + linter.NewConfig(fatcontext.New(&cfg.Linters.Settings.Fatcontext)). WithSince("v1.58.0"). WithLoadForGoAnalysis(). @@ -298,9 +318,10 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { linter.NewConfig(goconst.New(&cfg.Linters.Settings.Goconst)). WithSince("v1.0.0"). + WithLoadForGoAnalysis(). WithURL("https://github.com/jgautheron/goconst"), - linter.NewConfig(gocritic.New(&cfg.Linters.Settings.Gocritic)). + linter.NewConfig(gocritic.New(&cfg.Linters.Settings.Gocritic, placeholderReplacer)). WithSince("v1.12.0"). WithLoadForGoAnalysis(). WithAutoFix(). @@ -340,7 +361,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithAutoFix(). WithURL("https://github.com/segmentio/golines"), - linter.NewConfig(goheader.New(&cfg.Linters.Settings.Goheader, cfg.GetBasePath())). + linter.NewConfig(goheader.New(&cfg.Linters.Settings.Goheader, placeholderReplacer)). WithSince("v1.28.0"). WithAutoFix(). WithURL("https://github.com/denis-tingaikin/go-header"), @@ -450,7 +471,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { linter.NewConfig(misspell.New(&cfg.Linters.Settings.Misspell)). WithSince("v1.8.0"). WithAutoFix(). - WithURL("https://github.com/client9/misspell"), + WithURL("https://github.com/golangci/misspell"), linter.NewConfig(musttag.New(&cfg.Linters.Settings.MustTag)). WithSince("v1.51.0"). @@ -491,6 +512,11 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithLoadForGoAnalysis(). WithURL("https://github.com/sonatard/noctx"), + linter.NewConfig(noinlineerr.New()). + WithSince("v2.2.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/AlwxSin/noinlineerr"), + linter.NewConfig(nonamedreturns.New(&cfg.Linters.Settings.NoNamedReturns)). WithSince("v1.46.0"). WithLoadForGoAnalysis(). @@ -553,6 +579,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { linter.NewConfig(sloglint.New(&cfg.Linters.Settings.SlogLint)). WithSince("v1.55.0"). WithLoadForGoAnalysis(). + WithAutoFix(). WithURL("https://github.com/go-simpler/sloglint"), linter.NewConfig(sqlclosecheck.New()). @@ -572,6 +599,11 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { WithAutoFix(). WithURL("https://staticcheck.dev/"), + linter.NewConfig(swaggo.New()). + WithSince("v2.2.0"). + WithAutoFix(). + WithURL("https://github.com/swaggo/swaggo"), + linter.NewConfig(tagalign.New(&cfg.Linters.Settings.TagAlign)). WithSince("v1.53.0"). WithAutoFix(). diff --git a/pkg/lint/package.go b/pkg/lint/package.go index f9bf2230d074..3127a24b8e56 100644 --- a/pkg/lint/package.go +++ b/pkg/lint/package.go @@ -39,13 +39,13 @@ type PackageLoader struct { } // NewPackageLoader creates a new PackageLoader. -func NewPackageLoader(log logutils.Log, cfg *config.Config, args []string, goenv *goutil.Env, loadGuard *load.Guard) *PackageLoader { +func NewPackageLoader(log logutils.Log, cfg *config.Config, args []string, env *goutil.Env, loadGuard *load.Guard) *PackageLoader { return &PackageLoader{ cfg: cfg, args: args, log: log, debugf: logutils.Debug(logutils.DebugKeyLoader), - goenv: goenv, + goenv: env, pkgTestIDRe: regexp.MustCompile(`^(.*) \[(.*)\.test\]`), loadGuard: loadGuard, } diff --git a/pkg/lint/runner.go b/pkg/lint/runner.go index ebb35a0d7460..ba7750f28577 100644 --- a/pkg/lint/runner.go +++ b/pkg/lint/runner.go @@ -110,7 +110,7 @@ func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env, processors.NewSourceCode(lineCache, log.Child(logutils.DebugKeySourceCode)), processors.NewPathShortener(), processors.NewSeverity(log.Child(logutils.DebugKeySeverityRules), lineCache, &cfg.Severity), - processors.NewPathPrettifier(log, cfg.Output.PathPrefix), + processors.NewPathPrettifier(log, &cfg.Output), processors.NewSortResults(&cfg.Output), }, lintCtx: lintCtx, @@ -118,17 +118,17 @@ func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env, }, nil } -func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]result.Issue, error) { +func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]*result.Issue, error) { sw := timeutils.NewStopwatch("linters", r.Log) defer sw.Print() var ( lintErrors error - issues []result.Issue + issues []*result.Issue ) for _, lc := range linters { - linterIssues, err := timeutils.TrackStage(sw, lc.Name(), func() ([]result.Issue, error) { + linterIssues, err := timeutils.TrackStage(sw, lc.Name(), func() ([]*result.Issue, error) { return r.runLinterSafe(ctx, r.lintCtx, lc) }) if err != nil { @@ -146,7 +146,7 @@ func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]result.Is func (r *Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context, lc *linter.Config, -) (ret []result.Issue, err error) { +) (ret []*result.Issue, err error) { defer func() { if panicData := recover(); panicData != nil { if pe, ok := panicData.(*errorutil.PanicError); ok { @@ -185,13 +185,13 @@ func (r *Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context, return issues, nil } -func (r *Runner) processLintResults(inIssues []result.Issue) []result.Issue { +func (r *Runner) processLintResults(inIssues []*result.Issue) []*result.Issue { sw := timeutils.NewStopwatch("processing", r.Log) var issuesBefore, issuesAfter int statPerProcessor := map[string]processorStat{} - var outIssues []result.Issue + var outIssues []*result.Issue if len(inIssues) != 0 { issuesBefore += len(inIssues) outIssues = r.processIssues(inIssues, sw, statPerProcessor) @@ -225,14 +225,14 @@ func (r *Runner) printPerProcessorStat(stat map[string]processorStat) { } } -func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, statPerProcessor map[string]processorStat) []result.Issue { +func (r *Runner) processIssues(issues []*result.Issue, sw *timeutils.Stopwatch, statPerProcessor map[string]processorStat) []*result.Issue { for _, p := range r.Processors { - newIssues, err := timeutils.TrackStage(sw, p.Name(), func() ([]result.Issue, error) { + newIssues, err := timeutils.TrackStage(sw, p.Name(), func() ([]*result.Issue, error) { return p.Process(issues) }) if err != nil { - r.Log.Warnf("Can't process result by %s processor: %s", p.Name(), err) + r.Log.Warnf("Can't process results by %s processor: %s", p.Name(), err) } else { stat := statPerProcessor[p.Name()] stat.inCount += len(issues) @@ -243,7 +243,7 @@ func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, s // This is required by JSON serialization if issues == nil { - issues = []result.Issue{} + issues = []*result.Issue{} } } diff --git a/pkg/logutils/logutils.go b/pkg/logutils/logutils.go index 2fbb4a7b2493..e417ac4b738d 100644 --- a/pkg/logutils/logutils.go +++ b/pkg/logutils/logutils.go @@ -17,6 +17,7 @@ const envDebug = "GL_DEBUG" const ( DebugKeyBinSalt = "bin_salt" + DebugKeyGoModSalt = "gomod_salt" DebugKeyConfigReader = "config_reader" DebugKeyEmpty = "" DebugKeyEnabledLinters = "enabled_linters" @@ -78,11 +79,12 @@ const ( // Linters. const ( - DebugKeyForbidigo = "forbidigo" // Debugs `forbidigo` linter. - DebugKeyGoCritic = "gocritic" // Debugs `gocritic` linter. - DebugKeyGovet = "govet" // Debugs `govet` linter. - DebugKeyLinter = "linter" - DebugKeyRevive = "revive" // Debugs `revive` linter. + DebugKeyForbidigo = "forbidigo" // Debugs `forbidigo` linter. + DebugKeyGoCritic = "gocritic" // Debugs `gocritic` linter. + DebugKeyGovet = "govet" // Debugs `govet` linter. + DebugKeyLinter = "linter" + DebugKeyRevive = "revive" // Debugs `revive` linter. + DebugKeyStaticcheck = "staticcheck" // Debugs `staticcheck` linter. ) func getEnabledDebugs() map[string]bool { diff --git a/pkg/logutils/stderr_log.go b/pkg/logutils/stderr_log.go index b47c65eace22..af4296429127 100644 --- a/pkg/logutils/stderr_log.go +++ b/pkg/logutils/stderr_log.go @@ -17,14 +17,14 @@ const ( envLogTimestamp = "LOG_TIMESTAMP" ) +var _ Log = NewStderrLog(DebugKeyEmpty) + type StderrLog struct { name string logger *logrus.Logger level LogLevel } -var _ Log = NewStderrLog(DebugKeyEmpty) - func NewStderrLog(name string) *StderrLog { sl := &StderrLog{ name: name, @@ -44,16 +44,7 @@ func NewStderrLog(name string) *StderrLog { } sl.logger.Out = StdErr - formatter := &logrus.TextFormatter{ - DisableTimestamp: true, // `INFO[0007] msg` -> `INFO msg` - EnvironmentOverrideColors: true, - } - if os.Getenv(envLogTimestamp) == "1" { - formatter.DisableTimestamp = false - formatter.FullTimestamp = true - formatter.TimestampFormat = time.StampMilli - } - sl.logger.Formatter = formatter + sl.logger.Formatter = logFormatter return sl } @@ -127,3 +118,24 @@ func (sl StderrLog) Child(name string) Log { func (sl *StderrLog) SetLevel(level LogLevel) { sl.level = level } + +var logFormatter = newLogFormatter() + +func DisableColors(disable bool) { + logFormatter.DisableColors = disable +} + +func newLogFormatter() *logrus.TextFormatter { + formatter := &logrus.TextFormatter{ + DisableTimestamp: true, // `INFO[0007] msg` -> `INFO msg` + EnvironmentOverrideColors: true, + } + + if os.Getenv(envLogTimestamp) == "1" { + formatter.DisableTimestamp = false + formatter.FullTimestamp = true + formatter.TimestampFormat = time.StampMilli + } + + return formatter +} diff --git a/pkg/printers/checkstyle.go b/pkg/printers/checkstyle.go index 5a60554bdb62..c3869bd39d9d 100644 --- a/pkg/printers/checkstyle.go +++ b/pkg/printers/checkstyle.go @@ -37,15 +37,14 @@ func NewCheckstyle(log logutils.Log, w io.Writer) *Checkstyle { } } -func (p *Checkstyle) Print(issues []result.Issue) error { +func (p *Checkstyle) Print(issues []*result.Issue) error { out := checkstyleOutput{ Version: "5.0", } files := map[string]*checkstyleFile{} - for i := range issues { - issue := &issues[i] + for _, issue := range issues { file, ok := files[issue.FilePath()] if !ok { file = &checkstyleFile{ diff --git a/pkg/printers/checkstyle_test.go b/pkg/printers/checkstyle_test.go index f087a79b83b0..5c8781e388fb 100644 --- a/pkg/printers/checkstyle_test.go +++ b/pkg/printers/checkstyle_test.go @@ -14,7 +14,7 @@ import ( ) func TestCheckstyle_Print(t *testing.T) { - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "warning", diff --git a/pkg/printers/codeclimate.go b/pkg/printers/codeclimate.go index 872d860d3ba4..e2eded608fb9 100644 --- a/pkg/printers/codeclimate.go +++ b/pkg/printers/codeclimate.go @@ -30,12 +30,10 @@ func NewCodeClimate(log logutils.Log, w io.Writer) *CodeClimate { } } -func (p *CodeClimate) Print(issues []result.Issue) error { +func (p *CodeClimate) Print(issues []*result.Issue) error { ccIssues := make([]codeClimateIssue, 0, len(issues)) - for i := range issues { - issue := issues[i] - + for _, issue := range issues { ccIssue := codeClimateIssue{ Description: issue.Description(), CheckName: issue.FromLinter, diff --git a/pkg/printers/codeclimate_test.go b/pkg/printers/codeclimate_test.go index 28fd281c4548..159dd86e37ae 100644 --- a/pkg/printers/codeclimate_test.go +++ b/pkg/printers/codeclimate_test.go @@ -13,7 +13,7 @@ import ( ) func TestCodeClimate_Print(t *testing.T) { - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "minor", diff --git a/pkg/printers/html.go b/pkg/printers/html.go index 0f99bb7ff8ce..1f6ed18344b0 100644 --- a/pkg/printers/html.go +++ b/pkg/printers/html.go @@ -132,20 +132,20 @@ func NewHTML(w io.Writer) *HTML { return &HTML{w: w} } -func (p HTML) Print(issues []result.Issue) error { +func (p HTML) Print(issues []*result.Issue) error { var htmlIssues []htmlIssue - for i := range issues { - pos := fmt.Sprintf("%s:%d", issues[i].FilePath(), issues[i].Line()) - if issues[i].Pos.Column != 0 { - pos += fmt.Sprintf(":%d", issues[i].Pos.Column) + for _, issue := range issues { + pos := fmt.Sprintf("%s:%d", issue.FilePath(), issue.Line()) + if issue.Pos.Column != 0 { + pos += fmt.Sprintf(":%d", issue.Pos.Column) } htmlIssues = append(htmlIssues, htmlIssue{ - Title: strings.TrimSpace(issues[i].Text), + Title: strings.TrimSpace(issue.Text), Pos: pos, - Linter: issues[i].FromLinter, - Code: strings.Join(issues[i].SourceLines, "\n"), + Linter: issue.FromLinter, + Code: strings.Join(issue.SourceLines, "\n"), }) } diff --git a/pkg/printers/html_test.go b/pkg/printers/html_test.go index 3964d81ddeaf..17db307509c2 100644 --- a/pkg/printers/html_test.go +++ b/pkg/printers/html_test.go @@ -118,7 +118,7 @@ const expectedHTML = ` ` func TestHTML_Print(t *testing.T) { - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "warning", diff --git a/pkg/printers/json.go b/pkg/printers/json.go index 64fd33c7bae5..97354081c903 100644 --- a/pkg/printers/json.go +++ b/pkg/printers/json.go @@ -22,17 +22,17 @@ func NewJSON(w io.Writer, rd *report.Data) *JSON { } type JSONResult struct { - Issues []result.Issue + Issues []*result.Issue Report *report.Data } -func (p JSON) Print(issues []result.Issue) error { +func (p JSON) Print(issues []*result.Issue) error { res := JSONResult{ Issues: issues, Report: p.rd, } if res.Issues == nil { - res.Issues = []result.Issue{} + res.Issues = []*result.Issue{} } return json.NewEncoder(p.w).Encode(res) diff --git a/pkg/printers/json_test.go b/pkg/printers/json_test.go index 001c283ee611..50c67f995fe1 100644 --- a/pkg/printers/json_test.go +++ b/pkg/printers/json_test.go @@ -12,7 +12,7 @@ import ( ) func TestJSON_Print(t *testing.T) { - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "warning", diff --git a/pkg/printers/junitxml.go b/pkg/printers/junitxml.go index 708f83e5a860..b040e746703c 100644 --- a/pkg/printers/junitxml.go +++ b/pkg/printers/junitxml.go @@ -27,31 +27,30 @@ func NewJUnitXML(w io.Writer, extended bool) *JUnitXML { } } -func (p JUnitXML) Print(issues []result.Issue) error { +func (p JUnitXML) Print(issues []*result.Issue) error { suites := make(map[string]testSuiteXML) // use a map to group by file - for ind := range issues { - i := &issues[ind] - suiteName := i.FilePath() + for _, issue := range issues { + suiteName := issue.FilePath() testSuite := suites[suiteName] - testSuite.Suite = i.FilePath() + testSuite.Suite = issue.FilePath() testSuite.Tests++ testSuite.Failures++ tc := testCaseXML{ - Name: i.FromLinter, - ClassName: i.Pos.String(), + Name: issue.FromLinter, + ClassName: issue.Pos.String(), Failure: failureXML{ - Type: i.Severity, - Message: i.Pos.String() + ": " + i.Text, + Type: issue.Severity, + Message: issue.Pos.String() + ": " + issue.Text, Content: fmt.Sprintf("%s: %s\nCategory: %s\nFile: %s\nLine: %d\nDetails: %s", - i.Severity, i.Text, i.FromLinter, i.Pos.Filename, i.Pos.Line, strings.Join(i.SourceLines, "\n")), + issue.Severity, issue.Text, issue.FromLinter, issue.Pos.Filename, issue.Pos.Line, strings.Join(issue.SourceLines, "\n")), }, } if p.extended { - tc.File = i.Pos.Filename - tc.Line = i.Pos.Line + tc.File = issue.Pos.Filename + tc.Line = issue.Pos.Line } testSuite.TestCases = append(testSuite.TestCases, tc) diff --git a/pkg/printers/junitxml_test.go b/pkg/printers/junitxml_test.go index 7a429e546f46..90a365e79870 100644 --- a/pkg/printers/junitxml_test.go +++ b/pkg/printers/junitxml_test.go @@ -12,7 +12,7 @@ import ( ) func TestJUnitXML_Print(t *testing.T) { - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "warning", diff --git a/pkg/printers/printer.go b/pkg/printers/printer.go index 575bba75f1d5..bb3eab6205e8 100644 --- a/pkg/printers/printer.go +++ b/pkg/printers/printer.go @@ -23,7 +23,7 @@ const ( const defaultFileMode = 0o644 type issuePrinter interface { - Print(issues []result.Issue) error + Print(issues []*result.Issue) error } // Printer prints issues. @@ -63,7 +63,7 @@ func NewPrinter(log logutils.Log, cfg *config.Formats, reportData *report.Data, // Print prints issues based on the formats defined. // //nolint:gocyclo,funlen // the complexity is related to the number of formats. -func (c *Printer) Print(issues []result.Issue) error { +func (c *Printer) Print(issues []*result.Issue) error { if c.cfg.IsEmpty() { c.cfg.Text.Path = outputStdOut } diff --git a/pkg/printers/printer_test.go b/pkg/printers/printer_test.go index 850ee94a097b..6b3737f16688 100644 --- a/pkg/printers/printer_test.go +++ b/pkg/printers/printer_test.go @@ -29,7 +29,7 @@ func unmarshalFile(t *testing.T, filename string, v any) { func TestPrinter_Print_stdout(t *testing.T) { logger := logutils.NewStderrLog("skip") - var issues []result.Issue + var issues []*result.Issue unmarshalFile(t, "in-issues.json", &issues) data := &report.Data{} @@ -86,7 +86,7 @@ func TestPrinter_Print_stdout(t *testing.T) { func TestPrinter_Print_stderr(t *testing.T) { logger := logutils.NewStderrLog("skip") - var issues []result.Issue + var issues []*result.Issue unmarshalFile(t, "in-issues.json", &issues) data := &report.Data{} @@ -122,7 +122,7 @@ func TestPrinter_Print_stderr(t *testing.T) { func TestPrinter_Print_file(t *testing.T) { logger := logutils.NewStderrLog("skip") - var issues []result.Issue + var issues []*result.Issue unmarshalFile(t, "in-issues.json", &issues) data := &report.Data{} @@ -165,7 +165,7 @@ func TestPrinter_Print_file(t *testing.T) { func TestPrinter_Print_multiple(t *testing.T) { logger := logutils.NewStderrLog("skip") - var issues []result.Issue + var issues []*result.Issue unmarshalFile(t, "in-issues.json", &issues) data := &report.Data{} diff --git a/pkg/printers/sarif.go b/pkg/printers/sarif.go index e8d8c64f7da3..e1caf179a821 100644 --- a/pkg/printers/sarif.go +++ b/pkg/printers/sarif.go @@ -36,14 +36,12 @@ func NewSarif(log logutils.Log, w io.Writer) *Sarif { } } -func (p *Sarif) Print(issues []result.Issue) error { +func (p *Sarif) Print(issues []*result.Issue) error { run := sarifRun{} run.Tool.Driver.Name = "golangci-lint" run.Results = make([]sarifResult, 0) - for i := range issues { - issue := issues[i] - + for _, issue := range issues { sr := sarifResult{ RuleID: issue.FromLinter, Level: p.sanitizer.Sanitize(issue.Severity), diff --git a/pkg/printers/sarif_test.go b/pkg/printers/sarif_test.go index f6ddf4d81f07..400bb25bed37 100644 --- a/pkg/printers/sarif_test.go +++ b/pkg/printers/sarif_test.go @@ -13,7 +13,7 @@ import ( ) func TestSarif_Print(t *testing.T) { - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "warning", diff --git a/pkg/printers/tab.go b/pkg/printers/tab.go index 0d14593e5950..8edbb05e11fe 100644 --- a/pkg/printers/tab.go +++ b/pkg/printers/tab.go @@ -40,11 +40,11 @@ func (p *Tab) SprintfColored(ca color.Attribute, format string, args ...any) str return c.Sprintf(format, args...) } -func (p *Tab) Print(issues []result.Issue) error { +func (p *Tab) Print(issues []*result.Issue) error { w := tabwriter.NewWriter(p.w, 0, 0, 2, ' ', 0) - for i := range issues { - p.printIssue(&issues[i], w) + for _, issue := range issues { + p.printIssue(issue, w) } if err := w.Flush(); err != nil { diff --git a/pkg/printers/tab_test.go b/pkg/printers/tab_test.go index f8e47f84b2b1..1920334753e8 100644 --- a/pkg/printers/tab_test.go +++ b/pkg/printers/tab_test.go @@ -22,7 +22,7 @@ func TestTab_Print(t *testing.T) { }) color.NoColor = false - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "warning", diff --git a/pkg/printers/teamcity.go b/pkg/printers/teamcity.go index a85307729d05..36114fedfc57 100644 --- a/pkg/printers/teamcity.go +++ b/pkg/printers/teamcity.go @@ -48,12 +48,10 @@ func NewTeamCity(log logutils.Log, w io.Writer) *TeamCity { } } -func (p *TeamCity) Print(issues []result.Issue) error { +func (p *TeamCity) Print(issues []*result.Issue) error { uniqLinters := map[string]struct{}{} - for i := range issues { - issue := issues[i] - + for _, issue := range issues { _, ok := uniqLinters[issue.FromLinter] if !ok { inspectionType := InspectionType{ diff --git a/pkg/printers/teamcity_test.go b/pkg/printers/teamcity_test.go index eda415670273..121a0519eb48 100644 --- a/pkg/printers/teamcity_test.go +++ b/pkg/printers/teamcity_test.go @@ -13,7 +13,7 @@ import ( ) func TestTeamCity_Print(t *testing.T) { - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "WARNING", diff --git a/pkg/printers/text.go b/pkg/printers/text.go index 545679fb7b45..eb9297615be2 100644 --- a/pkg/printers/text.go +++ b/pkg/printers/text.go @@ -42,16 +42,16 @@ func (p *Text) SprintfColored(ca color.Attribute, format string, args ...any) st return c.Sprintf(format, args...) } -func (p *Text) Print(issues []result.Issue) error { - for i := range issues { - p.printIssue(&issues[i]) +func (p *Text) Print(issues []*result.Issue) error { + for _, issue := range issues { + p.printIssue(issue) if !p.printIssuedLine { continue } - p.printSourceCode(&issues[i]) - p.printUnderLinePointer(&issues[i]) + p.printSourceCode(issue) + p.printUnderLinePointer(issue) } return nil diff --git a/pkg/printers/text_test.go b/pkg/printers/text_test.go index 4a1c39483526..4aa784ee4457 100644 --- a/pkg/printers/text_test.go +++ b/pkg/printers/text_test.go @@ -22,7 +22,7 @@ func TestText_Print(t *testing.T) { }) color.NoColor = false - issues := []result.Issue{ + issues := []*result.Issue{ { FromLinter: "linter-a", Severity: "warning", diff --git a/pkg/report/log.go b/pkg/report/log.go index ad096415123f..c964af559379 100644 --- a/pkg/report/log.go +++ b/pkg/report/log.go @@ -2,6 +2,7 @@ package report import ( "fmt" + "slices" "strings" "github.com/golangci/golangci-lint/v2/pkg/logutils" @@ -50,7 +51,7 @@ func (lw LogWrapper) Infof(format string, args ...any) { func (lw LogWrapper) Child(name string) logutils.Log { c := lw c.origLog = lw.origLog.Child(name) - c.tags = append([]string{}, lw.tags...) + c.tags = slices.Clone(lw.tags) c.tags = append(c.tags, name) return c } diff --git a/pkg/result/issue.go b/pkg/result/issue.go index 86a4ef3b7369..2587ffff2cc7 100644 --- a/pkg/result/issue.go +++ b/pkg/result/issue.go @@ -32,7 +32,7 @@ type Issue struct { // HunkPos is used only when golangci-lint is run over a diff HunkPos int `json:",omitempty"` - // If we know how to fix the issue we can provide replacement lines + // If we know how to fix the issue, we can provide replacement lines SuggestedFixes []analysis.SuggestedFix `json:",omitempty"` // If we are expecting a nolint (because this is from nolintlint), record the expected linter @@ -42,7 +42,7 @@ type Issue struct { // Only for Diff processor needs. WorkingDirectoryRelativePath string `json:"-"` - // Only for processor that need relative paths evaluation. + // Only for processors that need relative paths evaluation. RelativePath string `json:"-"` } diff --git a/pkg/result/processors/base_rule.go b/pkg/result/processors/base_rule.go index e544e373e27e..46886624848a 100644 --- a/pkg/result/processors/base_rule.go +++ b/pkg/result/processors/base_rule.go @@ -2,6 +2,7 @@ package processors import ( "regexp" + "slices" "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/fsutils" @@ -73,19 +74,13 @@ func (r *baseRule) match(issue *result.Issue, lines *fsutils.LineCache, log logu } func (r *baseRule) matchLinter(issue *result.Issue) bool { - for _, linter := range r.linters { - if linter == issue.FromLinter { - return true - } - } - - return false + return slices.Contains(r.linters, issue.FromLinter) } func (r *baseRule) matchSource(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { - sourceLine, errSourceLine := lineCache.GetLine(issue.RelativePath, issue.Line()) + sourceLine, errSourceLine := lineCache.GetLine(issue.FilePath(), issue.Line()) if errSourceLine != nil { - log.Warnf("Failed to get line %s:%d from line cache: %s", issue.RelativePath, issue.Line(), errSourceLine) + log.Warnf("Failed to get line %s:%d from line cache: %s", issue.FilePath(), issue.Line(), errSourceLine) return false // can't properly match } diff --git a/pkg/result/processors/cgo.go b/pkg/result/processors/cgo.go index dea3801e2c8a..4cc7b57dbf05 100644 --- a/pkg/result/processors/cgo.go +++ b/pkg/result/processors/cgo.go @@ -31,7 +31,7 @@ func (*Cgo) Name() string { return "cgo" } -func (p *Cgo) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *Cgo) Process(issues []*result.Issue) ([]*result.Issue, error) { return filterIssuesErr(issues, p.shouldPassIssue) } diff --git a/pkg/result/processors/diff.go b/pkg/result/processors/diff.go index a84caf7b686a..15574ff0d374 100644 --- a/pkg/result/processors/diff.go +++ b/pkg/result/processors/diff.go @@ -48,7 +48,7 @@ func (*Diff) Name() string { return "diff" } -func (p *Diff) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *Diff) Process(issues []*result.Issue) ([]*result.Issue, error) { if !p.onlyNew && p.fromRev == "" && p.fromMergeBase == "" && p.patchFilePath == "" && p.patch == "" { return issues, nil } diff --git a/pkg/result/processors/exclusion_generated_file_filter.go b/pkg/result/processors/exclusion_generated_file_filter.go index 6cbde3aedf58..d76ec3184f86 100644 --- a/pkg/result/processors/exclusion_generated_file_filter.go +++ b/pkg/result/processors/exclusion_generated_file_filter.go @@ -40,7 +40,7 @@ func (*GeneratedFileFilter) Name() string { return "generated_file_filter" } -func (p *GeneratedFileFilter) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *GeneratedFileFilter) Process(issues []*result.Issue) ([]*result.Issue, error) { if p.mode == config.GeneratedModeDisable { return issues, nil } diff --git a/pkg/result/processors/exclusion_paths.go b/pkg/result/processors/exclusion_paths.go index dafad44d1d3b..acf13edd0797 100644 --- a/pkg/result/processors/exclusion_paths.go +++ b/pkg/result/processors/exclusion_paths.go @@ -68,7 +68,7 @@ func (*ExclusionPaths) Name() string { return "exclusion_paths" } -func (p *ExclusionPaths) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *ExclusionPaths) Process(issues []*result.Issue) ([]*result.Issue, error) { if len(p.pathPatterns) == 0 && len(p.pathExceptPatterns) == 0 { return issues, nil } @@ -79,7 +79,7 @@ func (p *ExclusionPaths) Process(issues []result.Issue) ([]result.Issue, error) func (p *ExclusionPaths) Finish() { for pattern, count := range p.excludedPathCounter { if p.warnUnused && count == 0 { - p.log.Warnf("The pattern %q match %d issues", pattern, count) + p.log.Warnf("The pattern %q match no issues", pattern) } else { p.log.Infof("Skipped %d issues by pattern %q", count, pattern) } @@ -87,7 +87,7 @@ func (p *ExclusionPaths) Finish() { for pattern, count := range p.excludedPathExceptCounter { if p.warnUnused && count == 0 { - p.log.Warnf("The pattern %q match %d issues", pattern, count) + p.log.Warnf("The pattern %q match no issues", pattern) } } } @@ -114,5 +114,5 @@ func (p *ExclusionPaths) shouldPassIssue(issue *result.Issue) bool { matched = true } - return !matched + return matched } diff --git a/pkg/result/processors/exclusion_paths_test.go b/pkg/result/processors/exclusion_paths_test.go index 44e17d207d38..bfd19af13e65 100644 --- a/pkg/result/processors/exclusion_paths_test.go +++ b/pkg/result/processors/exclusion_paths_test.go @@ -19,22 +19,22 @@ func TestExclusionPaths_Process(t *testing.T) { testCases := []struct { desc string cfg *config.LinterExclusions - issues []result.Issue - expected []result.Issue + issues []*result.Issue + expected []*result.Issue }{ { desc: "paths: word", cfg: &config.LinterExclusions{ Paths: []string{"foo"}, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: "foo.go"}, {RelativePath: "foo/foo.go"}, {RelativePath: "foo/bar.go"}, {RelativePath: "bar/foo.go"}, {RelativePath: "bar/bar.go"}, }, - expected: []result.Issue{ + expected: []*result.Issue{ {RelativePath: "bar/bar.go"}, }, }, @@ -43,14 +43,14 @@ func TestExclusionPaths_Process(t *testing.T) { cfg: &config.LinterExclusions{ Paths: []string{"^foo"}, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("foo.go")}, {RelativePath: filepath.FromSlash("foo/foo.go")}, {RelativePath: filepath.FromSlash("foo/bar.go")}, {RelativePath: filepath.FromSlash("bar/foo.go")}, {RelativePath: filepath.FromSlash("bar/bar.go")}, }, - expected: []result.Issue{ + expected: []*result.Issue{ {RelativePath: filepath.FromSlash("bar/foo.go")}, {RelativePath: filepath.FromSlash("bar/bar.go")}, }, @@ -60,14 +60,14 @@ func TestExclusionPaths_Process(t *testing.T) { cfg: &config.LinterExclusions{ Paths: []string{"^foo/"}, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("foo.go")}, {RelativePath: filepath.FromSlash("foo/foo.go")}, {RelativePath: filepath.FromSlash("foo/bar.go")}, {RelativePath: filepath.FromSlash("bar/foo.go")}, {RelativePath: filepath.FromSlash("bar/bar.go")}, }, - expected: []result.Issue{ + expected: []*result.Issue{ {RelativePath: filepath.FromSlash("foo.go")}, {RelativePath: filepath.FromSlash("bar/foo.go")}, {RelativePath: filepath.FromSlash("bar/bar.go")}, @@ -78,22 +78,22 @@ func TestExclusionPaths_Process(t *testing.T) { cfg: &config.LinterExclusions{ Paths: []string{"c/d.go"}, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("a/b/c/d.go")}, {RelativePath: filepath.FromSlash("c/d.go")}, }, - expected: []result.Issue{}, + expected: []*result.Issue{}, }, { desc: "paths: same suffix with constrained expression", cfg: &config.LinterExclusions{ Paths: []string{"^c/d.go"}, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("a/b/c/d.go")}, {RelativePath: filepath.FromSlash("c/d.go")}, }, - expected: []result.Issue{ + expected: []*result.Issue{ {RelativePath: filepath.FromSlash("a/b/c/d.go")}, }, }, @@ -106,11 +106,11 @@ func TestExclusionPaths_Process(t *testing.T) { `^c/d.go`, }, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("a/b/c/d.go")}, {RelativePath: filepath.FromSlash("c/d.go")}, }, - expected: []result.Issue{ + expected: []*result.Issue{ {RelativePath: filepath.FromSlash("a/b/c/d.go")}, }, }, @@ -119,7 +119,7 @@ func TestExclusionPaths_Process(t *testing.T) { cfg: &config.LinterExclusions{ PathsExcept: []string{`^base/c/.*$`}, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("base/a/file.go")}, {RelativePath: filepath.FromSlash("base/b/file.go")}, {RelativePath: filepath.FromSlash("base/c/file.go")}, @@ -127,10 +127,10 @@ func TestExclusionPaths_Process(t *testing.T) { {RelativePath: filepath.FromSlash("base/c/b/file.go")}, {RelativePath: filepath.FromSlash("base/d/file.go")}, }, - expected: []result.Issue{ - {RelativePath: filepath.FromSlash("base/a/file.go")}, - {RelativePath: filepath.FromSlash("base/b/file.go")}, - {RelativePath: filepath.FromSlash("base/d/file.go")}, + expected: []*result.Issue{ + {RelativePath: filepath.FromSlash("base/c/file.go")}, + {RelativePath: filepath.FromSlash("base/c/a/file.go")}, + {RelativePath: filepath.FromSlash("base/c/b/file.go")}, }, }, { @@ -142,7 +142,7 @@ func TestExclusionPaths_Process(t *testing.T) { `^base/c/.*$`, }, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("base/a/file.go")}, {RelativePath: filepath.FromSlash("base/b/file.go")}, {RelativePath: filepath.FromSlash("base/c/file.go")}, @@ -150,10 +150,10 @@ func TestExclusionPaths_Process(t *testing.T) { {RelativePath: filepath.FromSlash("base/c/b/file.go")}, {RelativePath: filepath.FromSlash("base/d/file.go")}, }, - expected: []result.Issue{ - {RelativePath: filepath.FromSlash("base/a/file.go")}, - {RelativePath: filepath.FromSlash("base/b/file.go")}, - {RelativePath: filepath.FromSlash("base/d/file.go")}, + expected: []*result.Issue{ + {RelativePath: filepath.FromSlash("base/c/file.go")}, + {RelativePath: filepath.FromSlash("base/c/a/file.go")}, + {RelativePath: filepath.FromSlash("base/c/b/file.go")}, }, }, { @@ -164,7 +164,7 @@ func TestExclusionPaths_Process(t *testing.T) { `^base/c/.*$`, }, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("base/a/file.go")}, {RelativePath: filepath.FromSlash("base/b/file.go")}, {RelativePath: filepath.FromSlash("base/c/file.go")}, @@ -173,19 +173,20 @@ func TestExclusionPaths_Process(t *testing.T) { {RelativePath: filepath.FromSlash("base/d/file.go")}, {RelativePath: filepath.FromSlash("base/e/file.go")}, }, - expected: []result.Issue{ - {RelativePath: filepath.FromSlash("base/a/file.go")}, - {RelativePath: filepath.FromSlash("base/b/file.go")}, - {RelativePath: filepath.FromSlash("base/d/file.go")}, + expected: []*result.Issue{ + {RelativePath: filepath.FromSlash("base/c/file.go")}, + {RelativePath: filepath.FromSlash("base/c/a/file.go")}, + {RelativePath: filepath.FromSlash("base/c/b/file.go")}, + {RelativePath: filepath.FromSlash("base/e/file.go")}, }, }, { - desc: "pathsExcept and paths", + desc: "pathsExcept and paths (disjoint)", cfg: &config.LinterExclusions{ Paths: []string{"^base/b/"}, PathsExcept: []string{`^base/c/.*$`}, }, - issues: []result.Issue{ + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("base/a/file.go")}, {RelativePath: filepath.FromSlash("base/b/file.go")}, {RelativePath: filepath.FromSlash("base/c/file.go")}, @@ -193,10 +194,30 @@ func TestExclusionPaths_Process(t *testing.T) { {RelativePath: filepath.FromSlash("base/c/b/file.go")}, {RelativePath: filepath.FromSlash("base/d/file.go")}, }, - expected: []result.Issue{ + expected: []*result.Issue{ + {RelativePath: filepath.FromSlash("base/c/file.go")}, + {RelativePath: filepath.FromSlash("base/c/a/file.go")}, + {RelativePath: filepath.FromSlash("base/c/b/file.go")}, + }, + }, + { + desc: "pathsExcept and paths (intersection)", + cfg: &config.LinterExclusions{ + Paths: []string{"^base/c/a/"}, + PathsExcept: []string{`^base/c/.*$`}, + }, + issues: []*result.Issue{ {RelativePath: filepath.FromSlash("base/a/file.go")}, + {RelativePath: filepath.FromSlash("base/b/file.go")}, + {RelativePath: filepath.FromSlash("base/c/file.go")}, + {RelativePath: filepath.FromSlash("base/c/a/file.go")}, + {RelativePath: filepath.FromSlash("base/c/b/file.go")}, {RelativePath: filepath.FromSlash("base/d/file.go")}, }, + expected: []*result.Issue{ + {RelativePath: filepath.FromSlash("base/c/file.go")}, + {RelativePath: filepath.FromSlash("base/c/b/file.go")}, + }, }, } diff --git a/pkg/result/processors/exclusion_rules.go b/pkg/result/processors/exclusion_rules.go index 064921ae607a..2b5221a89085 100644 --- a/pkg/result/processors/exclusion_rules.go +++ b/pkg/result/processors/exclusion_rules.go @@ -49,7 +49,7 @@ func (*ExclusionRules) Name() string { return "exclusion_rules" } -func (p *ExclusionRules) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *ExclusionRules) Process(issues []*result.Issue) ([]*result.Issue, error) { if len(p.rules) == 0 { return issues, nil } diff --git a/pkg/result/processors/exclusion_rules_test.go b/pkg/result/processors/exclusion_rules_test.go index 5657f45ed7a3..6f78ee2d2b3e 100644 --- a/pkg/result/processors/exclusion_rules_test.go +++ b/pkg/result/processors/exclusion_rules_test.go @@ -63,7 +63,7 @@ func TestExclusionRules_Process_multiple(t *testing.T) { {Path: filepath.FromSlash("testdata/exclusion_rules/exclusion_rules.go"), Line: 3, Linter: "lll"}, } - var issues []result.Issue + var issues []*result.Issue for _, c := range cases { issues = append(issues, newIssueFromIssueTestCase(c)) } @@ -105,9 +105,9 @@ func TestExclusionRules_Process_text(t *testing.T) { p := NewExclusionRules(nil, lines, cfg) texts := []string{"exclude", "1", "", "exclud", "notexclude"} - var issues []result.Issue + var issues []*result.Issue for _, t := range texts { - issues = append(issues, result.Issue{ + issues = append(issues, &result.Issue{ Text: t, FromLinter: "linter", }) @@ -178,7 +178,7 @@ func TestExclusionRules_Process_caseSensitive_multiple(t *testing.T) { {Path: filepath.FromSlash("testdata/exclusion_rules/case_sensitive.go"), Line: 3, Linter: "lll"}, } - var issues []result.Issue + var issues []*result.Issue for _, c := range cases { issues = append(issues, newIssueFromIssueTestCase(c)) } @@ -225,9 +225,9 @@ func TestExclusionRules_Process_caseSensitive_text(t *testing.T) { texts := []string{"exclude", "excLude", "1", "", "exclud", "notexclude"} - var issues []result.Issue + var issues []*result.Issue for _, t := range texts { - issues = append(issues, result.Issue{ + issues = append(issues, &result.Issue{ Text: t, FromLinter: "linter", }) diff --git a/pkg/result/processors/filename_unadjuster.go b/pkg/result/processors/filename_unadjuster.go index a3cdd8e6ed7c..e39601d5a4a4 100644 --- a/pkg/result/processors/filename_unadjuster.go +++ b/pkg/result/processors/filename_unadjuster.go @@ -66,7 +66,7 @@ func (*FilenameUnadjuster) Name() string { return "filename_unadjuster" } -func (p *FilenameUnadjuster) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *FilenameUnadjuster) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, func(issue *result.Issue) *result.Issue { mapper := p.m[issue.FilePath()] if mapper == nil { diff --git a/pkg/result/processors/fixer.go b/pkg/result/processors/fixer.go index 14dd3454eab6..ce33b27fb276 100644 --- a/pkg/result/processors/fixer.go +++ b/pkg/result/processors/fixer.go @@ -22,6 +22,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt" "github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports" "github.com/golangci/golangci-lint/v2/pkg/goformatters/golines" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" "github.com/golangci/golangci-lint/v2/pkg/logutils" "github.com/golangci/golangci-lint/v2/pkg/result" "github.com/golangci/golangci-lint/v2/pkg/timeutils" @@ -55,14 +56,14 @@ func (Fixer) Name() string { return "fixer" } -func (p Fixer) Process(issues []result.Issue) ([]result.Issue, error) { +func (p Fixer) Process(issues []*result.Issue) ([]*result.Issue, error) { if !p.cfg.Issues.NeedFix { return issues, nil } p.log.Infof("Applying suggested fixes") - notFixableIssues, err := timeutils.TrackStage(p.sw, "all", func() ([]result.Issue, error) { + notFixableIssues, err := timeutils.TrackStage(p.sw, "all", func() ([]*result.Issue, error) { return p.process(issues) }) if err != nil { @@ -75,13 +76,13 @@ func (p Fixer) Process(issues []result.Issue) ([]result.Issue, error) { } //nolint:funlen,gocyclo // This function should not be split. -func (p Fixer) process(issues []result.Issue) ([]result.Issue, error) { +func (p Fixer) process(issues []*result.Issue) ([]*result.Issue, error) { // filenames / linters / edits editsByLinter := make(map[string]map[string][]diff.Edit) - formatters := []string{gofumpt.Name, goimports.Name, gofmt.Name, gci.Name, golines.Name} + formatters := []string{gofumpt.Name, goimports.Name, gofmt.Name, gci.Name, golines.Name, swaggo.Name} - var notFixableIssues []result.Issue + var notFixableIssues []*result.Issue toBeFormattedFiles := make(map[string]struct{}) @@ -93,7 +94,7 @@ func (p Fixer) process(issues []result.Issue) ([]result.Issue, error) { continue } - if issue.SuggestedFixes == nil || skipNoTextEdit(&issue) { + if issue.SuggestedFixes == nil || skipNoTextEdit(issue) { notFixableIssues = append(notFixableIssues, issue) continue } diff --git a/pkg/result/processors/invalid_issue.go b/pkg/result/processors/invalid_issue.go index a7f45d408333..fa1b19e82c17 100644 --- a/pkg/result/processors/invalid_issue.go +++ b/pkg/result/processors/invalid_issue.go @@ -24,7 +24,7 @@ func (InvalidIssue) Name() string { return "invalid_issue" } -func (p InvalidIssue) Process(issues []result.Issue) ([]result.Issue, error) { +func (p InvalidIssue) Process(issues []*result.Issue) ([]*result.Issue, error) { tcIssues := filterIssuesUnsafe(issues, func(issue *result.Issue) bool { return issue.FromLinter == typeCheckName }) diff --git a/pkg/result/processors/invalid_issue_test.go b/pkg/result/processors/invalid_issue_test.go index 32628c336d31..c685551a9673 100644 --- a/pkg/result/processors/invalid_issue_test.go +++ b/pkg/result/processors/invalid_issue_test.go @@ -19,21 +19,21 @@ func TestInvalidIssue_Process(t *testing.T) { testCases := []struct { desc string - issues []result.Issue - expected []result.Issue + issues []*result.Issue + expected []*result.Issue }{ { desc: "typecheck", - issues: []result.Issue{ + issues: []*result.Issue{ {FromLinter: "typecheck"}, }, - expected: []result.Issue{ + expected: []*result.Issue{ {FromLinter: "typecheck"}, }, }, { desc: "keep only typecheck issues if any exist", - issues: []result.Issue{ + issues: []*result.Issue{ {FromLinter: "typecheck"}, { FromLinter: "example", @@ -42,13 +42,13 @@ func TestInvalidIssue_Process(t *testing.T) { }, }, }, - expected: []result.Issue{ + expected: []*result.Issue{ {FromLinter: "typecheck"}, }, }, { desc: "Go file", - issues: []result.Issue{ + issues: []*result.Issue{ { FromLinter: "example", Pos: token.Position{ @@ -56,7 +56,7 @@ func TestInvalidIssue_Process(t *testing.T) { }, }, }, - expected: []result.Issue{ + expected: []*result.Issue{ { FromLinter: "example", Pos: token.Position{ @@ -67,7 +67,7 @@ func TestInvalidIssue_Process(t *testing.T) { }, { desc: "go.mod", - issues: []result.Issue{ + issues: []*result.Issue{ { FromLinter: "example", Pos: token.Position{ @@ -75,7 +75,7 @@ func TestInvalidIssue_Process(t *testing.T) { }, }, }, - expected: []result.Issue{ + expected: []*result.Issue{ { FromLinter: "example", Pos: token.Position{ @@ -86,7 +86,7 @@ func TestInvalidIssue_Process(t *testing.T) { }, { desc: "non Go file", - issues: []result.Issue{ + issues: []*result.Issue{ { FromLinter: "example", Pos: token.Position{ @@ -94,11 +94,11 @@ func TestInvalidIssue_Process(t *testing.T) { }, }, }, - expected: []result.Issue{}, + expected: []*result.Issue{}, }, { desc: "no filename", - issues: []result.Issue{ + issues: []*result.Issue{ { FromLinter: "example", Pos: token.Position{ @@ -106,7 +106,7 @@ func TestInvalidIssue_Process(t *testing.T) { }, }, }, - expected: []result.Issue{}, + expected: []*result.Issue{}, }, } diff --git a/pkg/result/processors/issues.go b/pkg/result/processors/issues.go index 1e76291c77a1..cc4deeb5267e 100644 --- a/pkg/result/processors/issues.go +++ b/pkg/result/processors/issues.go @@ -6,62 +6,62 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/result" ) -func filterIssues(issues []result.Issue, filter func(issue *result.Issue) bool) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - if issues[i].FromLinter == typeCheckName { +func filterIssues(issues []*result.Issue, filter func(issue *result.Issue) bool) []*result.Issue { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + if issue.FromLinter == typeCheckName { // don't hide typechecking errors in generated files: users expect to see why the project isn't compiling - retIssues = append(retIssues, issues[i]) + retIssues = append(retIssues, issue) continue } - if filter(&issues[i]) { - retIssues = append(retIssues, issues[i]) + if filter(issue) { + retIssues = append(retIssues, issue) } } return retIssues } -func filterIssuesUnsafe(issues []result.Issue, filter func(issue *result.Issue) bool) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - if filter(&issues[i]) { - retIssues = append(retIssues, issues[i]) +func filterIssuesUnsafe(issues []*result.Issue, filter func(issue *result.Issue) bool) []*result.Issue { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + if filter(issue) { + retIssues = append(retIssues, issue) } } return retIssues } -func filterIssuesErr(issues []result.Issue, filter func(issue *result.Issue) (bool, error)) ([]result.Issue, error) { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - if issues[i].FromLinter == typeCheckName { +func filterIssuesErr(issues []*result.Issue, filter func(issue *result.Issue) (bool, error)) ([]*result.Issue, error) { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + if issue.FromLinter == typeCheckName { // don't hide typechecking errors in generated files: users expect to see why the project isn't compiling - retIssues = append(retIssues, issues[i]) + retIssues = append(retIssues, issue) continue } - ok, err := filter(&issues[i]) + ok, err := filter(issue) if err != nil { - return nil, fmt.Errorf("can't filter issue %#v: %w", issues[i], err) + return nil, fmt.Errorf("can't filter issue %#v: %w", issue, err) } if ok { - retIssues = append(retIssues, issues[i]) + retIssues = append(retIssues, issue) } } return retIssues, nil } -func transformIssues(issues []result.Issue, transform func(issue *result.Issue) *result.Issue) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - newIssue := transform(&issues[i]) +func transformIssues(issues []*result.Issue, transform func(issue *result.Issue) *result.Issue) []*result.Issue { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + newIssue := transform(issue) if newIssue != nil { - retIssues = append(retIssues, *newIssue) + retIssues = append(retIssues, newIssue) } } diff --git a/pkg/result/processors/max_from_linter.go b/pkg/result/processors/max_from_linter.go index dec9f3e7f13a..bc7572f2ccaf 100644 --- a/pkg/result/processors/max_from_linter.go +++ b/pkg/result/processors/max_from_linter.go @@ -29,7 +29,7 @@ func (*MaxFromLinter) Name() string { return "max_from_linter" } -func (p *MaxFromLinter) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *MaxFromLinter) Process(issues []*result.Issue) ([]*result.Issue, error) { if p.limit <= 0 { // no limit return issues, nil } diff --git a/pkg/result/processors/max_per_file_from_linter.go b/pkg/result/processors/max_per_file_from_linter.go index fdb6bb0278da..b04b92ea7a7f 100644 --- a/pkg/result/processors/max_per_file_from_linter.go +++ b/pkg/result/processors/max_per_file_from_linter.go @@ -7,6 +7,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt" "github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports" "github.com/golangci/golangci-lint/v2/pkg/goformatters/golines" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" "github.com/golangci/golangci-lint/v2/pkg/result" ) @@ -24,7 +25,7 @@ func NewMaxPerFileFromLinter(cfg *config.Config) *MaxPerFileFromLinter { if !cfg.Issues.NeedFix { // if we don't fix we do this limiting to not annoy user; // otherwise we need to fix all issues in the file at once - for _, f := range []string{gofmt.Name, gofumpt.Name, goimports.Name, gci.Name, golines.Name} { + for _, f := range []string{gofmt.Name, gofumpt.Name, goimports.Name, gci.Name, golines.Name, swaggo.Name} { maxPerFileFromLinterConfig[f] = 1 } } @@ -39,7 +40,7 @@ func (*MaxPerFileFromLinter) Name() string { return "max_per_file_from_linter" } -func (p *MaxPerFileFromLinter) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *MaxPerFileFromLinter) Process(issues []*result.Issue) ([]*result.Issue, error) { return filterIssuesUnsafe(issues, func(issue *result.Issue) bool { limit := p.maxPerFileFromLinterConfig[issue.FromLinter] if limit == 0 { diff --git a/pkg/result/processors/max_per_file_from_linter_test.go b/pkg/result/processors/max_per_file_from_linter_test.go index c5bc7ebc1e8b..a886b47c75f0 100644 --- a/pkg/result/processors/max_per_file_from_linter_test.go +++ b/pkg/result/processors/max_per_file_from_linter_test.go @@ -7,8 +7,8 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/result" ) -func newFromLinterIssue(linterName string) result.Issue { - return result.Issue{ +func newFromLinterIssue(linterName string) *result.Issue { + return &result.Issue{ FromLinter: linterName, } } diff --git a/pkg/result/processors/max_same_issues.go b/pkg/result/processors/max_same_issues.go index 06e87586e171..ba22cf31fb62 100644 --- a/pkg/result/processors/max_same_issues.go +++ b/pkg/result/processors/max_same_issues.go @@ -31,7 +31,7 @@ func (*MaxSameIssues) Name() string { return "max_same_issues" } -func (p *MaxSameIssues) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *MaxSameIssues) Process(issues []*result.Issue) ([]*result.Issue, error) { if p.limit <= 0 { // no limit return issues, nil } diff --git a/pkg/result/processors/max_same_issues_test.go b/pkg/result/processors/max_same_issues_test.go index 574059ebbb41..8eb7de0e39a8 100644 --- a/pkg/result/processors/max_same_issues_test.go +++ b/pkg/result/processors/max_same_issues_test.go @@ -10,10 +10,10 @@ import ( func TestMaxSameIssues(t *testing.T) { p := NewMaxSameIssues(1, logutils.NewStderrLog(logutils.DebugKeyEmpty), &config.Config{}) - i1 := result.Issue{ + i1 := &result.Issue{ Text: "1", } - i2 := result.Issue{ + i2 := &result.Issue{ Text: "2", } diff --git a/pkg/result/processors/nolint_filter.go b/pkg/result/processors/nolint_filter.go index 96fd6403ec45..bd2a09abea43 100644 --- a/pkg/result/processors/nolint_filter.go +++ b/pkg/result/processors/nolint_filter.go @@ -91,7 +91,7 @@ func (*NolintFilter) Name() string { return "nolint_filter" } -func (p *NolintFilter) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *NolintFilter) Process(issues []*result.Issue) ([]*result.Issue, error) { // put nolintlint issues last because we process other issues first to determine which nolint directives are unused sort.Stable(sortWithNolintlintLast(issues)) return filterIssuesErr(issues, p.shouldPassIssue) @@ -185,8 +185,7 @@ func (p *NolintFilter) buildIgnoredRangesForFile(f *ast.File, fset *token.FileSe ast.Walk(&e, f) // TODO: merge all ranges: there are repeated ranges - allRanges := append([]ignoredRange{}, inlineRanges...) - allRanges = append(allRanges, e.expandedRanges...) + allRanges := slices.Concat(inlineRanges, e.expandedRanges) return allRanges } @@ -300,7 +299,7 @@ func (e *rangeExpander) Visit(node ast.Node) ast.Visitor { } // put nolintlint last -type sortWithNolintlintLast []result.Issue +type sortWithNolintlintLast []*result.Issue func (issues sortWithNolintlintLast) Len() int { return len(issues) diff --git a/pkg/result/processors/nolint_filter_test.go b/pkg/result/processors/nolint_filter_test.go index 852602a86ad2..c620875aba98 100644 --- a/pkg/result/processors/nolint_filter_test.go +++ b/pkg/result/processors/nolint_filter_test.go @@ -16,8 +16,8 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/result" ) -func newNolintFileIssue(line int, fromLinter string) result.Issue { - return result.Issue{ +func newNolintFileIssue(line int, fromLinter string) *result.Issue { + return &result.Issue{ Pos: token.Position{ Filename: filepath.FromSlash("testdata/nolint_filter/nolint.go"), Line: line, @@ -26,7 +26,7 @@ func newNolintFileIssue(line int, fromLinter string) result.Issue { } } -func newNolint2FileIssue(line int) result.Issue { +func newNolint2FileIssue(line int) *result.Issue { i := newNolintFileIssue(line, "errcheck") i.Pos.Filename = filepath.FromSlash("testdata/nolint_filter/nolint2.go") return i @@ -63,7 +63,7 @@ func TestTestNolintFilter_Process(t *testing.T) { processAssertEmpty(t, p, newNolintFileIssue(6, "any")) processAssertEmpty(t, p, newNolintFileIssue(7, "any")) - processAssertSame(t, p, newNolintFileIssue(1, "golint")) // no directive + processAssertSame(t, p, newNolintFileIssue(1, "wsl")) // no directive // test preceding comments processAssertEmpty(t, p, newNolintFileIssue(10, "any")) // preceding comment for var @@ -126,7 +126,7 @@ func TestTestNolintFilter_Process(t *testing.T) { func TestNolintFilter_Process_invalidLinterName(t *testing.T) { fileName := filepath.FromSlash("testdata/nolint_filter/bad_names.go") - issues := []result.Issue{ + issues := []*result.Issue{ { Pos: token.Position{ Filename: fileName, @@ -161,7 +161,7 @@ func TestNolintFilter_Process_invalidLinterName(t *testing.T) { func TestNolintFilter_Process_invalidLinterNameWithViolationOnTheSameLine(t *testing.T) { log := getMockLog() log.On("Warnf", "Found unknown linters in //nolint directives: %s", "foobar") - issues := []result.Issue{ + issues := []*result.Issue{ { Pos: token.Position{ Filename: filepath.FromSlash("testdata/nolint_filter/apply_to_unknown.go"), @@ -246,14 +246,14 @@ func TestNolintFilter_Process_wholeFile(t *testing.T) { p := newTestNolintFilter(getMockLog()) defer p.Finish() - processAssertEmpty(t, p, result.Issue{ + processAssertEmpty(t, p, &result.Issue{ Pos: token.Position{ Filename: fileName, Line: 9, }, FromLinter: "errcheck", }) - processAssertSame(t, p, result.Issue{ + processAssertSame(t, p, &result.Issue{ Pos: token.Position{ Filename: fileName, Line: 14, @@ -284,7 +284,7 @@ func TestNolintFilter_Process_unused(t *testing.T) { } // the issue below is the nolintlint issue that would be generated for the test file - nolintlintIssueMisspell := result.Issue{ + nolintlintIssueMisspell := &result.Issue{ Pos: token.Position{ Filename: fileName, Line: 3, @@ -295,7 +295,7 @@ func TestNolintFilter_Process_unused(t *testing.T) { } // the issue below is another nolintlint issue that would be generated for the test file - nolintlintIssueMisspellUnusedOK := result.Issue{ + nolintlintIssueMisspellUnusedOK := &result.Issue{ Pos: token.Position{ Filename: fileName, Line: 5, @@ -323,7 +323,7 @@ func TestNolintFilter_Process_unused(t *testing.T) { p := createProcessor(t, log, []string{"misspell", "nolintlint"}) defer p.Finish() - processAssertEmpty(t, p, []result.Issue{{ + processAssertEmpty(t, p, []*result.Issue{{ Pos: token.Position{ Filename: fileName, Line: 3, diff --git a/pkg/result/processors/path_absoluter.go b/pkg/result/processors/path_absoluter.go index 99f3de42a2cd..240cedf8eaf4 100644 --- a/pkg/result/processors/path_absoluter.go +++ b/pkg/result/processors/path_absoluter.go @@ -22,7 +22,7 @@ func (*PathAbsoluter) Name() string { return "path_absoluter" } -func (p *PathAbsoluter) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *PathAbsoluter) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, func(issue *result.Issue) *result.Issue { if filepath.IsAbs(issue.FilePath()) { return issue diff --git a/pkg/result/processors/path_prettifier.go b/pkg/result/processors/path_prettifier.go index 31270044f1fe..94dfbab370ab 100644 --- a/pkg/result/processors/path_prettifier.go +++ b/pkg/result/processors/path_prettifier.go @@ -3,6 +3,8 @@ package processors import ( "path/filepath" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" "github.com/golangci/golangci-lint/v2/pkg/logutils" "github.com/golangci/golangci-lint/v2/pkg/result" ) @@ -12,14 +14,15 @@ var _ Processor = (*PathPrettifier)(nil) // PathPrettifier modifies report file path to be relative to the base path. // Also handles the `output.path-prefix` option. type PathPrettifier struct { - prefix string - log logutils.Log + cfg *config.Output + + log logutils.Log } -func NewPathPrettifier(log logutils.Log, prefix string) *PathPrettifier { +func NewPathPrettifier(log logutils.Log, cfg *config.Output) *PathPrettifier { return &PathPrettifier{ - prefix: prefix, - log: log.Child(logutils.DebugKeyPathPrettifier), + cfg: cfg, + log: log.Child(logutils.DebugKeyPathPrettifier), } } @@ -27,14 +30,18 @@ func (*PathPrettifier) Name() string { return "path_prettifier" } -func (p *PathPrettifier) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *PathPrettifier) Process(issues []*result.Issue) ([]*result.Issue, error) { + if p.cfg.PathMode == fsutils.OutputPathModeAbsolute { + return issues, nil + } + return transformIssues(issues, func(issue *result.Issue) *result.Issue { newIssue := issue - if p.prefix == "" { + if p.cfg.PathPrefix == "" { newIssue.Pos.Filename = issue.RelativePath } else { - newIssue.Pos.Filename = filepath.Join(p.prefix, issue.RelativePath) + newIssue.Pos.Filename = filepath.Join(p.cfg.PathPrefix, issue.RelativePath) } return newIssue diff --git a/pkg/result/processors/path_prettifier_test.go b/pkg/result/processors/path_prettifier_test.go index ddd38e49759f..2f403d46a327 100644 --- a/pkg/result/processors/path_prettifier_test.go +++ b/pkg/result/processors/path_prettifier_test.go @@ -8,19 +8,20 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/golangci/golangci-lint/v2/pkg/config" "github.com/golangci/golangci-lint/v2/pkg/logutils" "github.com/golangci/golangci-lint/v2/pkg/result" ) -func newPPIssue(fn, rp string) result.Issue { - return result.Issue{ +func newPPIssue(fn, rp string) *result.Issue { + return &result.Issue{ Pos: token.Position{Filename: filepath.FromSlash(fn)}, RelativePath: filepath.FromSlash(rp), } } func TestPathPrettifier_Process(t *testing.T) { - paths := func(ps ...string) (issues []result.Issue) { + paths := func(ps ...string) (issues []*result.Issue) { for _, p := range ps { issues = append(issues, newPPIssue("test", p)) } @@ -29,12 +30,12 @@ func TestPathPrettifier_Process(t *testing.T) { for _, tt := range []struct { name, prefix string - issues, want []result.Issue + issues, want []*result.Issue }{ { name: "empty prefix", issues: paths("some/path", "cool"), - want: []result.Issue{ + want: []*result.Issue{ newPPIssue("some/path", "some/path"), newPPIssue("cool", "cool"), }, @@ -43,7 +44,7 @@ func TestPathPrettifier_Process(t *testing.T) { name: "prefix", prefix: "ok", issues: paths("some/path", "cool"), - want: []result.Issue{ + want: []*result.Issue{ newPPIssue("ok/some/path", "some/path"), newPPIssue("ok/cool", "cool"), }, @@ -52,14 +53,14 @@ func TestPathPrettifier_Process(t *testing.T) { name: "prefix slashed", prefix: "ok/", issues: paths("some/path", "cool"), - want: []result.Issue{ + want: []*result.Issue{ newPPIssue("ok/some/path", "some/path"), newPPIssue("ok/cool", "cool"), }, }, } { t.Run(tt.name, func(t *testing.T) { - p := NewPathPrettifier(logutils.NewStderrLog(logutils.DebugKeyEmpty), tt.prefix) + p := NewPathPrettifier(logutils.NewStderrLog(logutils.DebugKeyEmpty), &config.Output{PathPrefix: tt.prefix}) got, err := p.Process(tt.issues) require.NoError(t, err) diff --git a/pkg/result/processors/path_relativity.go b/pkg/result/processors/path_relativity.go index 8b2958a4a308..c68662c7bb1f 100644 --- a/pkg/result/processors/path_relativity.go +++ b/pkg/result/processors/path_relativity.go @@ -36,7 +36,7 @@ func (*PathRelativity) Name() string { return "path_relativity" } -func (p *PathRelativity) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *PathRelativity) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, func(issue *result.Issue) *result.Issue { newIssue := *issue diff --git a/pkg/result/processors/path_shortener.go b/pkg/result/processors/path_shortener.go index 7a14c39c972e..23df4f02cc20 100644 --- a/pkg/result/processors/path_shortener.go +++ b/pkg/result/processors/path_shortener.go @@ -29,7 +29,7 @@ func (PathShortener) Name() string { return "path_shortener" } -func (p PathShortener) Process(issues []result.Issue) ([]result.Issue, error) { +func (p PathShortener) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, func(issue *result.Issue) *result.Issue { newIssue := issue newIssue.Text = strings.ReplaceAll(newIssue.Text, p.wd+"/", "") diff --git a/pkg/result/processors/processor.go b/pkg/result/processors/processor.go index 1976d6e44ad9..f5603c94dc75 100644 --- a/pkg/result/processors/processor.go +++ b/pkg/result/processors/processor.go @@ -7,7 +7,7 @@ import ( const typeCheckName = "typecheck" type Processor interface { - Process(issues []result.Issue) ([]result.Issue, error) + Process(issues []*result.Issue) ([]*result.Issue, error) Name() string Finish() } diff --git a/pkg/result/processors/processor_test.go b/pkg/result/processors/processor_test.go index 41bb78a7b3ae..95fdb5f81445 100644 --- a/pkg/result/processors/processor_test.go +++ b/pkg/result/processors/processor_test.go @@ -18,8 +18,8 @@ type issueTestCase struct { Severity string } -func newIssueFromIssueTestCase(c issueTestCase) result.Issue { - return result.Issue{ +func newIssueFromIssueTestCase(c issueTestCase) *result.Issue { + return &result.Issue{ Text: c.Text, FromLinter: c.Linter, Severity: c.Severity, @@ -31,13 +31,13 @@ func newIssueFromIssueTestCase(c issueTestCase) result.Issue { } } -func newIssueFromTextTestCase(text string) result.Issue { - return result.Issue{ +func newIssueFromTextTestCase(text string) *result.Issue { + return &result.Issue{ Text: text, } } -func process(t *testing.T, p Processor, issues ...result.Issue) []result.Issue { +func process(t *testing.T, p Processor, issues ...*result.Issue) []*result.Issue { t.Helper() processedIssues, err := p.Process(issues) @@ -45,14 +45,14 @@ func process(t *testing.T, p Processor, issues ...result.Issue) []result.Issue { return processedIssues } -func processAssertSame(t *testing.T, p Processor, issues ...result.Issue) { +func processAssertSame(t *testing.T, p Processor, issues ...*result.Issue) { t.Helper() processedIssues := process(t, p, issues...) assert.Equal(t, issues, processedIssues) } -func processAssertEmpty(t *testing.T, p Processor, issues ...result.Issue) { +func processAssertEmpty(t *testing.T, p Processor, issues ...*result.Issue) { t.Helper() processedIssues := process(t, p, issues...) diff --git a/pkg/result/processors/severity.go b/pkg/result/processors/severity.go index 035ca80c4e1d..33c3997f8889 100644 --- a/pkg/result/processors/severity.go +++ b/pkg/result/processors/severity.go @@ -43,7 +43,7 @@ func NewSeverity(log logutils.Log, lines *fsutils.LineCache, cfg *config.Severit func (p *Severity) Name() string { return p.name } -func (p *Severity) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *Severity) Process(issues []*result.Issue) ([]*result.Issue, error) { if len(p.rules) == 0 && p.defaultSeverity == "" { return issues, nil } diff --git a/pkg/result/processors/severity_test.go b/pkg/result/processors/severity_test.go index 0774f0b1d517..a5c50d0011cc 100644 --- a/pkg/result/processors/severity_test.go +++ b/pkg/result/processors/severity_test.go @@ -92,7 +92,7 @@ func TestSeverity_multiple(t *testing.T) { {Path: "empty.go", Text: "empty", Linter: "empty"}, } - var issues []result.Issue + var issues []*result.Issue for _, c := range cases { issues = append(issues, newIssueFromIssueTestCase(c)) } @@ -141,9 +141,9 @@ func TestSeverity_text(t *testing.T) { p := NewSeverity(nil, nil, opts) texts := []string{"seveRity", "1", "", "serverit", "notseverity"} - var issues []result.Issue + var issues []*result.Issue for _, t := range texts { - issues = append(issues, result.Issue{ + issues = append(issues, &result.Issue{ Text: t, FromLinter: "linter", }) @@ -176,7 +176,7 @@ func TestSeverity_onlyDefault(t *testing.T) { {Path: "empty.go", Text: "empty", Linter: "empty"}, } - var issues []result.Issue + var issues []*result.Issue for _, c := range cases { issues = append(issues, newIssueFromIssueTestCase(c)) } @@ -230,7 +230,7 @@ func TestSeverity_caseSensitive(t *testing.T) { {Path: "e.go", Text: "ssL", Linter: "gosec"}, } - var issues []result.Issue + var issues []*result.Issue for _, c := range cases { issues = append(issues, newIssueFromIssueTestCase(c)) } diff --git a/pkg/result/processors/sort_results.go b/pkg/result/processors/sort_results.go index 033eca9a4374..8ba06bccfd10 100644 --- a/pkg/result/processors/sort_results.go +++ b/pkg/result/processors/sort_results.go @@ -54,7 +54,7 @@ func NewSortResults(cfg *config.Output) *SortResults { func (SortResults) Name() string { return "sort_results" } // Process is performing sorting of the result issues. -func (p SortResults) Process(issues []result.Issue) ([]result.Issue, error) { +func (p SortResults) Process(issues []*result.Issue) ([]*result.Issue, error) { if len(p.cfg.SortOrder) == 0 { p.cfg.SortOrder = []string{orderNameLinter, orderNameFile} } @@ -72,8 +72,8 @@ func (p SortResults) Process(issues []result.Issue) ([]result.Issue, error) { comp := mergeComparators(cmps...) - slices.SortFunc(issues, func(a, b result.Issue) int { - return comp(&a, &b) + slices.SortFunc(issues, func(a, b *result.Issue) int { + return comp(a, b) }) return issues, nil diff --git a/pkg/result/processors/sort_results_test.go b/pkg/result/processors/sort_results_test.go index fcfd824c8eb1..dc097cc967de 100644 --- a/pkg/result/processors/sort_results_test.go +++ b/pkg/result/processors/sort_results_test.go @@ -12,7 +12,7 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/result" ) -var issues = []result.Issue{ +var issues = []*result.Issue{ { FromLinter: "b", Severity: "medium", @@ -50,7 +50,7 @@ var issues = []result.Issue{ }, } -var extraSeverityIssues = []result.Issue{ +var extraSeverityIssues = []*result.Issue{ { FromLinter: "c", Severity: "error", @@ -72,16 +72,16 @@ var extraSeverityIssues = []result.Issue{ } type compareTestCase struct { - a, b result.Issue + a, b *result.Issue expected int } func testCompareValues(t *testing.T, cmp issueComparator, name string, tests []compareTestCase) { - for i, test := range tests { //nolint:gocritic // To ignore rangeValCopy rule + for i, test := range tests { t.Run(fmt.Sprintf("%s(%d)", name, i), func(t *testing.T) { t.Parallel() - res := cmp(&test.a, &test.b) + res := cmp(test.a, test.b) assert.Equal(t, compToString(test.expected), compToString(res)) }) @@ -210,7 +210,7 @@ func Test_numericCompare(t *testing.T) { } func TestSortResults_Process(t *testing.T) { - tests := make([]result.Issue, len(issues)) + tests := make([]*result.Issue, len(issues)) copy(tests, issues) cfg := &config.Output{} @@ -219,7 +219,7 @@ func TestSortResults_Process(t *testing.T) { results, err := sr.Process(tests) require.NoError(t, err) - assert.Equal(t, []result.Issue{issues[1], issues[0], issues[3], issues[2]}, results) + assert.Equal(t, []*result.Issue{issues[1], issues[0], issues[3], issues[2]}, results) } func compToString(c int) string { diff --git a/pkg/result/processors/source_code.go b/pkg/result/processors/source_code.go index 1096269c8176..d4e82643c0d9 100644 --- a/pkg/result/processors/source_code.go +++ b/pkg/result/processors/source_code.go @@ -31,7 +31,7 @@ func (SourceCode) Name() string { return "source_code" } -func (p SourceCode) Process(issues []result.Issue) ([]result.Issue, error) { +func (p SourceCode) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, p.transform), nil } diff --git a/pkg/result/processors/uniq_by_line.go b/pkg/result/processors/uniq_by_line.go index 113b5814ad16..953496355b09 100644 --- a/pkg/result/processors/uniq_by_line.go +++ b/pkg/result/processors/uniq_by_line.go @@ -25,7 +25,7 @@ func (*UniqByLine) Name() string { return "uniq_by_line" } -func (p *UniqByLine) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *UniqByLine) Process(issues []*result.Issue) ([]*result.Issue, error) { if !p.enabled { return issues, nil } diff --git a/pkg/result/processors/uniq_by_line_test.go b/pkg/result/processors/uniq_by_line_test.go index dadca6a9afa1..d623c2e62569 100644 --- a/pkg/result/processors/uniq_by_line_test.go +++ b/pkg/result/processors/uniq_by_line_test.go @@ -7,8 +7,8 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/result" ) -func newULIssue(file string, line int) result.Issue { - return result.Issue{ +func newULIssue(file string, line int) *result.Issue { + return &result.Issue{ Pos: token.Position{ Filename: file, Line: line, diff --git a/scripts/gen_github_action_config/go.mod b/scripts/gen_github_action_config/go.mod index d3da48a46556..32b5cca642a1 100644 --- a/scripts/gen_github_action_config/go.mod +++ b/scripts/gen_github_action_config/go.mod @@ -5,7 +5,7 @@ go 1.23.0 require ( github.com/shurcooL/githubv4 v0.0.0-20240429030203-be2daab69064 github.com/stretchr/testify v1.10.0 - golang.org/x/oauth2 v0.28.0 + golang.org/x/oauth2 v0.30.0 ) require ( diff --git a/scripts/gen_github_action_config/go.sum b/scripts/gen_github_action_config/go.sum index 1898ebd5e03c..16f1f14cd28c 100644 --- a/scripts/gen_github_action_config/go.sum +++ b/scripts/gen_github_action_config/go.sum @@ -1,7 +1,5 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shurcooL/githubv4 v0.0.0-20240429030203-be2daab69064 h1:RCQBSFx5JrsbHltqTtJ+kN3U0Y3a/N/GlVdmRSoxzyE= @@ -10,8 +8,8 @@ github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZV github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/scripts/website/expand_templates/exclusions.go b/scripts/website/expand_templates/exclusions.go index 99638b72d39a..b84cae8a1b03 100644 --- a/scripts/website/expand_templates/exclusions.go +++ b/scripts/website/expand_templates/exclusions.go @@ -10,22 +10,26 @@ import ( const exclusionTmpl = `{{- $tick := "` + "`" + `" -}} {{- range $name, $rules := . }} -### {{ $tick }}{{ $name }}{{ $tick }} -{{ range $rule := $rules }} -{{ $tick }}{{ range $linter := $rule.Linters }}{{ $linter }}{{ end }}{{ $tick }}: -{{ if $rule.Path -}} -- Path: {{ $tick }}{{ $rule.Path }}{{ $tick }} -{{ end -}} -{{ if $rule.PathExcept -}} -- Path Except: {{ $tick }}{{ $rule.PathExcept }}{{ $tick }} -{{ end -}} -{{ if $rule.Text -}} -- Text: {{ $tick }}{{ $rule.Text }}{{ $tick }} -{{ end -}} -{{ if $rule.Source -}} -- Source: {{ $tick }}{{ $rule.Source }}{{ $tick }} -{{ end -}} -{{ end }}{{ end }}` +### Preset {{ $tick }}{{ $name }}{{ $tick }} + + + + + + + + + +{{- range $rule := $rules }} + + + + +{{- end }} + +
LinterIssue Text
{{ range $linter := $rule.Linters }}{{ $linter }}{{ end }}{{ if $rule.Text }}{{ $rule.Text }}{{ end }}
+ +{{ end }}` func getExclusionPresets() (string, error) { linterExclusionPresets, err := readJSONFile[map[string][]types.ExcludeRule](filepath.Join("assets", "exclusion-presets.json")) diff --git a/scripts/website/expand_templates/linters.go b/scripts/website/expand_templates/linters.go index 4e4c28c0505b..0b6c88e5dfa2 100644 --- a/scripts/website/expand_templates/linters.go +++ b/scripts/website/expand_templates/linters.go @@ -206,8 +206,7 @@ type ExampleSnippetsExtractor struct { func NewExampleSnippetsExtractor() *ExampleSnippetsExtractor { return &ExampleSnippetsExtractor{ - // TODO(ldez) replace .golangci.next.reference.yml by .golangci.reference.yml - referencePath: ".golangci.next.reference.yml", + referencePath: ".golangci.reference.yml", assetsPath: "assets", } } @@ -254,7 +253,7 @@ func (e *ExampleSnippetsExtractor) extractExampleSnippets(example []byte) (*Sett for j, node := range root.Content { switch node.Value { - case "run", "output", keyLinters, keyFormatters, "issues", "severity": + case "run", "output", keyLinters, keyFormatters, "issues", "severity", "version": default: continue } @@ -280,7 +279,20 @@ func (e *ExampleSnippetsExtractor) extractExampleSnippets(example []byte) (*Sett }, } - globalNode.Content = append(globalNode.Content, node, newNode) + if node.Value == "version" { + n := &yaml.Node{ + HeadComment: fmt.Sprintf("See the dedicated %q documentation section.", node.Value), + Kind: node.Kind, + Style: node.Style, + Tag: node.Tag, + Value: node.Value, + Content: node.Content, + } + + globalNode.Content = append(globalNode.Content, n, nextNode) + } else { + globalNode.Content = append(globalNode.Content, node, newNode) + } if node.Value == keyLinters || node.Value == keyFormatters { for i := 0; i < len(nextNode.Content); i++ { @@ -367,18 +379,29 @@ func (e *ExampleSnippetsExtractor) getSettingSections(node, nextNode *yaml.Node) for i := 0; i < len(nextNode.Content); i += 2 { r := &yaml.Node{ - Kind: nextNode.Kind, - Style: nextNode.Style, + Kind: yaml.MappingNode, Tag: nextNode.Tag, Value: node.Value, Content: []*yaml.Node{ { - Kind: node.Kind, + Kind: yaml.ScalarNode, Value: node.Value, + Tag: node.Tag, }, { - Kind: nextNode.Kind, - Content: []*yaml.Node{nextNode.Content[i], nextNode.Content[i+1]}, + Kind: yaml.MappingNode, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "settings", + Tag: node.Tag, + }, + { + Kind: yaml.MappingNode, + Tag: nextNode.Tag, + Content: []*yaml.Node{nextNode.Content[i], nextNode.Content[i+1]}, + }, + }, }, }, } diff --git a/scripts/website/expand_templates/thanks.go b/scripts/website/expand_templates/thanks.go index c3b8c8daee72..a3a0035cf60c 100644 --- a/scripts/website/expand_templates/thanks.go +++ b/scripts/website/expand_templates/thanks.go @@ -3,6 +3,7 @@ package main import ( "fmt" "maps" + "regexp" "slices" "strings" @@ -11,6 +12,11 @@ import ( "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" ) +const ( + hostGitHub = "github" + hostGitLab = "gitlab" +) + type authorDetails struct { Linters []string Profile string @@ -35,29 +41,29 @@ func getThanksList() string { continue } - linterURL := extractLinterURL(lc) + info := extractInfo(lc) - if author := extractAuthor(linterURL, "https://github.com/"); author != "" && author != "golangci" { - if _, ok := addedAuthors[author]; ok { - addedAuthors[author].Linters = append(addedAuthors[author].Linters, lc.Name()) + switch { + case info.FromGitHub(): + if _, ok := addedAuthors[info.Author]; ok { + addedAuthors[info.Author].Linters = append(addedAuthors[info.Author].Linters, lc.Name()) } else { - addedAuthors[author] = &authorDetails{ + addedAuthors[info.Author] = &authorDetails{ Linters: []string{lc.Name()}, - Profile: fmt.Sprintf("[%[1]s](https://github.com/sponsors/%[1]s)", author), - Avatar: fmt.Sprintf(`%[1]s`, author), + Profile: fmt.Sprintf("[%[1]s](https://github.com/sponsors/%[1]s)", info.Author), + Avatar: fmt.Sprintf(`%[1]s`, info.Author), } } - } else if author := extractAuthor(linterURL, "https://gitlab.com/"); author != "" { - if _, ok := addedAuthors[author]; ok { - addedAuthors[author].Linters = append(addedAuthors[author].Linters, lc.Name()) + + case info.FromGitLab(): + if _, ok := addedAuthors[info.Author]; ok { + addedAuthors[info.Author].Linters = append(addedAuthors[info.Author].Linters, lc.Name()) } else { - addedAuthors[author] = &authorDetails{ + addedAuthors[info.Author] = &authorDetails{ Linters: []string{lc.Name()}, - Profile: fmt.Sprintf("[%[1]s](https://gitlab.com/%[1]s)", author), + Profile: fmt.Sprintf("[%[1]s](https://gitlab.com/%[1]s)", info.Author), } } - } else { - continue } } @@ -78,31 +84,68 @@ func getThanksList() string { return strings.Join(lines, "\n") } -func extractLinterURL(lc *linter.Config) string { +type authorInfo struct { + Author string + Host string +} + +func extractInfo(lc *linter.Config) authorInfo { + exp := regexp.MustCompile(`https://(github|gitlab)\.com/([^/]+)/.*`) + switch lc.Name() { case "staticcheck": - return "https://github.com/dominikh/go-tools" + return authorInfo{Author: "dominikh", Host: hostGitHub} + + case "misspell": + return authorInfo{Author: "client9", Host: hostGitHub} - case "depguard": - return "https://github.com/dixonwille/depguard" + case "fatcontext": + return authorInfo{Author: "Crocmagnon", Host: hostGitHub} default: - if strings.HasPrefix(lc.OriginalURL, "https://github.com/gostaticanalysis/") { - return "https://github.com/tenntenn/gostaticanalysis" + if strings.HasPrefix(lc.OriginalURL, "https://pkg.go.dev/") { + return authorInfo{Author: "golang", Host: hostGitHub} + } + + if !exp.MatchString(lc.OriginalURL) { + return authorInfo{} } - if strings.HasPrefix(lc.OriginalURL, "https://github.com/go-simpler/") { - return "https://github.com/tmzane/go-simpler" + submatch := exp.FindAllStringSubmatch(lc.OriginalURL, -1) + + info := authorInfo{ + Author: submatch[0][2], + Host: submatch[0][1], + } + + switch info.Author { + case "gostaticanalysis": + info.Author = "tenntenn" + + case "go-simpler": + info.Author = "tmzane" + + case "curioswitch": + info.Author = "chokoswitch" + + case "GaijinEntertainment": + info.Author = "xobotyi" + + case "OpenPeeDeeP": + info.Author = "dixonwille" + + case "golangci": + return authorInfo{} } - return lc.OriginalURL + return info } } -func extractAuthor(originalURL, prefix string) string { - if !strings.HasPrefix(originalURL, prefix) { - return "" - } +func (i authorInfo) FromGitHub() bool { + return i.Host == hostGitHub +} - return strings.SplitN(strings.TrimPrefix(originalURL, prefix), "/", 2)[0] +func (i authorInfo) FromGitLab() bool { + return i.Host == hostGitLab } diff --git a/scripts/website/expand_templates/thanks_test.go b/scripts/website/expand_templates/thanks_test.go new file mode 100644 index 000000000000..7caa7e28c49f --- /dev/null +++ b/scripts/website/expand_templates/thanks_test.go @@ -0,0 +1,142 @@ +package main + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +type FakeLinter struct { + name string +} + +func (*FakeLinter) Run(_ context.Context, _ *linter.Context) ([]*result.Issue, error) { + return nil, nil +} + +func (f *FakeLinter) Name() string { + return f.name +} + +func (*FakeLinter) Desc() string { + return "fake linter" +} + +func Test_extractInfo(t *testing.T) { + testCases := []struct { + desc string + lc *linter.Config + expected authorInfo + }{ + { + desc: "from GitHub", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://github.com/owner/linter", + }, + expected: authorInfo{Author: "owner", Host: "github"}, + }, + { + desc: "from GitLab", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://gitlab.com/owner/linter", + }, + expected: authorInfo{Author: "owner", Host: "gitlab"}, + }, + { + desc: "staticcheck", + lc: &linter.Config{ + Linter: &FakeLinter{name: "staticcheck"}, + OriginalURL: "https://github.com/owner/linter", + }, + expected: authorInfo{Author: "dominikh", Host: "github"}, + }, + { + desc: "gostaticanalysis", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://github.com/gostaticanalysis/linter", + }, + expected: authorInfo{Author: "tenntenn", Host: "github"}, + }, + { + desc: "go-simpler", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://github.com/go-simpler/linter", + }, + expected: authorInfo{Author: "tmzane", Host: "github"}, + }, + { + desc: "curioswitch", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://github.com/curioswitch/linter", + }, + expected: authorInfo{Author: "chokoswitch", Host: "github"}, + }, + { + desc: "GaijinEntertainment", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://github.com/GaijinEntertainment/linter", + }, + expected: authorInfo{Author: "xobotyi", Host: "github"}, + }, + { + desc: "OpenPeeDeeP", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://github.com/OpenPeeDeeP/linter", + }, + expected: authorInfo{Author: "dixonwille", Host: "github"}, + }, + { + desc: "misspell", + lc: &linter.Config{ + Linter: &FakeLinter{name: "misspell"}, + OriginalURL: "https://github.com/myorg/linter", + }, + expected: authorInfo{Author: "client9", Host: "github"}, + }, + { + desc: "pkg.go.dev", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://pkg.go.dev/linter", + }, + expected: authorInfo{Author: "golang", Host: "github"}, + }, + { + desc: "golangci", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://github.com/golangci/linter", + }, + expected: authorInfo{}, + }, + { + desc: "invalid", + lc: &linter.Config{ + Linter: &FakeLinter{name: "fake"}, + OriginalURL: "https://example.com/linter", + }, + expected: authorInfo{}, + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + info := extractInfo(test.lc) + + assert.Equal(t, test.expected, info) + }) + } +} diff --git a/test/testshared/integration/run.go b/test/testshared/integration/run.go index cd0b4ca97076..f1add865fb54 100644 --- a/test/testshared/integration/run.go +++ b/test/testshared/integration/run.go @@ -4,6 +4,7 @@ import ( "os" "os/exec" "path/filepath" + "slices" "strings" "testing" "time" @@ -70,7 +71,7 @@ func testOneSource(t *testing.T, log *logutils.StderrLog, binPath, sourcePath st } for _, addArg := range []string{"", "-Etypecheck"} { - caseArgs := append([]string{}, args...) + caseArgs := slices.Clone(args) if addArg != "" { caseArgs = append(caseArgs, addArg) diff --git a/test/testshared/runner.go b/test/testshared/runner.go index c516ad9a181a..69bb8bac80a7 100644 --- a/test/testshared/runner.go +++ b/test/testshared/runner.go @@ -4,6 +4,7 @@ import ( "os" "os/exec" "path/filepath" + "slices" "strings" "sync" "syscall" @@ -286,10 +287,8 @@ func (r *RunnerResult) ExpectNoIssues() { func (r *RunnerResult) ExpectExitCode(possibleCodes ...int) *RunnerResult { r.tb.Helper() - for _, pc := range possibleCodes { - if pc == r.exitCode { - return r - } + if slices.Contains(possibleCodes, r.exitCode) { + return r } assert.Fail(r.tb, "invalid exit code", "exit code (%d) must be one of %v: %s", r.exitCode, possibleCodes, r.output)