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
更多关于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的平台上都能工作。

