Golang中Vet工具应跳过vendor目录的探讨

Golang中Vet工具应跳过vendor目录的探讨 当我使用常见的 Go 代码检查工具(如 shadow)对代码进行静态分析时,我希望 vendor/ 目录中的第三方代码不会被扫描。因为这些代码不受我的控制。

$ go vet -vettool="$(which shadow)" ./...
# gitlab.com/gomidi/midi/v2/drivers/rtmididrv/imported/rtmidi
In file included from rtmidi_stub.cpp:4:
./cpp/RtMidi.cpp:1555:15: warning: variable length arrays in C++ are a Clang extension [-Wvla-cxx-extension]
./cpp/RtMidi.cpp:1555:15: note: read of non-const variable 'bufsize' is not allowed in a constant expression
./cpp/RtMidi.cpp:1554:13: note: declared here

使用 Go 1.24 和 go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest 安装。

Stack Overflow 上提出了许多变通方案,但它们依赖于 GNU/BSD 对 findutils 的扩展。这破坏了许多 Windows 环境、许多 *nix 环境以及其他操作系统。还有一些解决方案依赖于 gometalinter(臃肿软件)。所有这些方案都涉及将输出传递给子进程,并随之带来所有复杂性(祝你在当前系统上可移植地实现 set -o pipefail 好运)。

寻求一个纯 Go 的解决方案,理想情况下 go vet 默认就能做到这一点。

坦率地说,shadow 和其他 x/tools 工具应该天生就知道如何正确地递归遍历大型 Go 项目目录,并自动忽略任何 vendor 目录。在没有像 mage-extras 这样的工具的情况下,以便携的方式连接 which 部分是一件痛苦的事情。我个人使用 mage[-extras],但许多开发者希望使用 make 或其他构建工具。

更新:即使是未使用 shadow 的标准 vet 工具,也会遇到同样的问题,即为 vendor 目录中的原生 C/C++ 代码生成警告。


更多关于Golang中Vet工具应跳过vendor目录的探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中Vet工具应跳过vendor目录的探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go 1.24中,go vet确实会扫描vendor/目录,这可能导致对第三方代码产生不必要的警告。以下是几种解决方案:

1. 使用go vet-mod=readonly标志(推荐)

go vet -mod=readonly ./...

这个标志会告诉go vet不要修改go.mod文件,同时通常会跳过vendor目录的检查。

2. 使用go list过滤vendor目录

go vet $(go list ./... | grep -v /vendor/)

或者更精确的版本:

go vet $(go list ./... | grep -v '/vendor/\|/testdata/')

3. 在Go代码中实现自定义vet工具

创建自定义vet工具来排除vendor目录:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
)

func main() {
    // 获取当前目录下的所有Go包,排除vendor
    cmd := exec.Command("go", "list", "./...")
    output, err := cmd.Output()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error listing packages: %v\n", err)
        os.Exit(1)
    }

    packages := strings.Split(strings.TrimSpace(string(output)), "\n")
    var filtered []string
    
    for _, pkg := range packages {
        if !strings.Contains(pkg, "/vendor/") {
            filtered = append(filtered, pkg)
        }
    }

    if len(filtered) == 0 {
        return
    }

    // 执行go vet
    args := append([]string{"vet"}, filtered...)
    vetCmd := exec.Command("go", args...)
    vetCmd.Stdout = os.Stdout
    vetCmd.Stderr = os.Stderr
    
    if err := vetCmd.Run(); err != nil {
        os.Exit(1)
    }
}

4. 使用shadow工具时排除vendor

对于shadow工具,可以这样使用:

# 先获取排除vendor的包列表
packages=$(go list ./... | grep -v /vendor/)
go vet -vettool=$(which shadow) $packages

5. 使用go vet的配置文件

创建.govet.yaml配置文件:

checks: all
exclude:
  - "vendor/**"
  - "**/vendor/**"

然后使用支持配置文件的vet工具。

6. 在Makefile中实现

VET_PACKAGES = $(shell go list ./... | grep -v /vendor/)

vet:
    go vet $(VET_PACKAGES)

vet-shadow:
    go vet -vettool=$$(which shadow) $(VET_PACKAGES)

7. 使用go vet的-buildtag标志

如果vendor目录有特定的构建标签:

go vet -tags="!vendor" ./...

但需要vendor目录中的文件有相应的构建标签注释。

目前Go工具链还没有内置的-exclude-vendor标志,但社区已经在讨论这个功能。最稳定和跨平台的解决方案是使用go list过滤配合grep -v /vendor/,这在所有支持Go的平台上都能工作。

回到顶部