Go Wiki: Watchflakes
Watchflakes 是一个用于对 build.golang.org 仪表板上出现的测试闪烁进行分类的程序。
出现的测试闪烁是指一种失败,该失败
- 不在完全失败的构建器上。
- 不在 已排除的构建器 上。
- 运行的提交没有在 4 个或更多构建器上失败。
- 在其构建器上不是 4 个或更多失败提交的运行的一部分。
Watchflakes 将每一个出现的测试闪烁发布到一个 Test Flakes 项目 的 issue 中。
Test Flakes 项目中的每个 issue 描述都以与该 issue 相关的失败模式开头:例如,#55260 的描述的 markdown 以
```
#!watchflakes
post <- pkg == "cmd/go" && test == "" && `unexpected files left in tmpdir`
```
Watchflakes 将每一个出现的测试闪烁与 issue 中的模式进行匹配
- 如果闪烁匹配 issue 中的模式,则会发布到该 issue。
- 如果闪烁匹配多个 issue 中的模式,则会发布到编号最小的 issue。
- 如果闪烁不匹配任何 issue 中的模式,watchflakes 会创建一个新的 issue,其模式匹配失败的包和测试用例。
新创建的 issue 的模式通常过于宽泛,应进行编辑以使其更具体地反映实际的失败。将失败发送到编号最小的匹配 issue 可确保创建新的、宽泛的默认模式不会“窃取”早期 issue 中的失败,也不会用同一测试中已单独跟踪的不相关失败来填充新 issue。
Watchflakes 将新创建的 issue 放置在 Test Flakes 项目中,并添加 NeedsInvestigation 标签。这些 issue 最初没有状态(不是 Active,也不是 Done)。没有状态的 issue 需要由人工检查,通常应细化模式以捕获失败的关键信息。然后,经过检查的 issue 可以移至 Active。当 issue 关闭时,GitHub 会自动将其从 Active 移至 Done。
Watchflakes 在匹配新失败时会考虑任何状态的 issue。如果它发现已关闭 issue 的新失败,它将发布该失败并重新打开该 issue。因此,当修复程序着陆时关闭 issue 是可以的,而不必等待几周来查看失败是否真的消失了:如果出现新失败,issue 将自动重新打开。
Watchflakes 本身不维护任何状态:所有状态都在 GitHub issue 中。每次运行时,它都会考虑过去 60 天的构建仪表板失败,并确保 Test Flakes 项目中记录了每一次明显的闪烁。如果匹配 issue 的失败已经发布到该 issue,watchflakes 当然不会再次发布。而且,如果 issue 被编辑以更新其模式以排除某些失败,watchflakes 不会删除其旧的帖子,但它会为这些失败寻找不同的匹配 issue,包括可能创建一个新的 issue。
语法
每个 issue 中的 watchflakes 节必须出现在 issue 描述的顶部。它必须是一个代码块(使用 ```
围起来或缩进),并且第一行必须是 #!watchflakes
,以防止 watchflakes 误解不相关的代码块。
块的其余部分是一个小的 watchflakes 脚本。行尾的注释以 #
开头。脚本是一系列规则,每条规则的形式为 action <- pattern
(将模式的匹配项发送到 action)。
Actions
Actions 是
post
将失败发布到脚本所在的 issue。skip
忽略失败,将其丢弃。此操作应仅在很少使用(例如,用于设置策略,如 #55166)。default
是 post 的低优先级版本。如果 issue 有匹配失败的post
或skip
,watchflakes 将执行该操作。但如果没有其他匹配项,watchflakes 会考虑default
模式匹配。(然后,如果没有default
匹配项,watchflakes 将创建一个新的 issue。)
Records
模式的输入是一个具有命名字段的记录,每个字段都有一个字符串值
-
pkg
是失败的构建或失败的测试的包的完整导入路径。 -
test
是包中失败的测试函数的名称。 -
mode
是build
或test
,取决于这是构建失败还是测试失败。 -
output
是失败的测试的输出。此输出在测试二进制文件退出时打印的最终FAIL
行之前停止。它不包括同一运行中其他失败的测试用例的输出,也不包括 all.bash 或 buildlet 在测试开始前打印的任何上下文。 -
log
是整个失败的构建日志。 -
snippet
是将发布到 issue 本身的output
的缩短形式。匹配项几乎总是应该使用output
而不是它。 -
builder
是运行测试的构建器的名称(例如dragonfly-amd64-622
)。 -
repo
是正在测试的仓库的名称(go
,net
,tools
, ...)。 -
goos
是 GOOS 值(linux
,windows
, ...)。 -
goarch
是 GOARCH 值(amd64
,mips64le
, ...)。 -
date
是正在测试的提交的日期,格式为2006-01-02T15:04:05
。没有日期比较逻辑;请使用字符串比较。日期比较应很少使用。 -
section
是发生失败的构建日志的节。在 all.bash 输出中,节由#####
引入,并且引导过程中的每一行Building
都被视为自己的节。在子仓库中,:: Running
行各自引入一个以运行的 go 命令命名的节(例如go test golang.org/x/tools/...
)。大多数模式不需要使用
section
。它对于主仓库中在备用执行环境中重新运行测试的测试最有帮助。
Patterns
模式是一个 Go 风格的语法中的布尔表达式,允许使用 ||、&&、!、( 和 ) 构建复杂表达式;使用 ==、!=、<、<=、> 和 >= 将字段与字符串字面量进行比较;以及使用 ~ 和 !~ 与正则表达式进行匹配。
所有字符串比较都必须在左侧有一个字段名,在右侧有一个双引号括起来的字符串字面量,例如 builder == "linux-amd64-alpine"
或 `goos == "
所有正则表达式匹配都必须在左侧有一个字段名,在右侧有一个反引号括起来的字符串字面量,例如 builder ~ `corellium`
。
单独的反引号字符串字面量被视为与 output
字段的比较,这适用于绝大多数模式中的正则表达式。
示例
将所有这些放在一起,这里有一些示例脚本。
#!watchflakes
post <- pkg == "net/http" && test == "TestHandlerAbortRacesBodyRead"
此脚本在 #55277 中是 watchflakes 响应 http.TestHandlerAbortRacesBodyRead 中的构建运行失败而自动创建的。促使 issue 创建的具体失败是超时。如果在该测试中发现了更多具有不同根本原因的失败,则可能适当地添加 && `panic: test timed out`
或以其他方式细化模式。
#!watchflakes
post <- goos == "openbsd" && `unlinkat .*: operation not permitted`
此脚本在 #49751 中收集了由于 os.Remove 调用 unlinkat 产生的意外 EPERM 错误在 openbsd 上引起的失败。这些失败会导致各种测试出现问题,因此对 pkg
或 test
没有条件限制。
#!watchflakes
post <- pkg ~ `^cmd/go` && `appspot.com.*: 503`
此脚本在 #54608 中跟踪了 cmd/go/... 包层次结构中任何测试的 appspot.com 产生的 503 响应的网络问题,而不仅仅是 cmd/go 本身。
#!watchflakes
post <- goos == "windows" &&
(`dnsquery: DNS server failure` || `getaddrinfow: This is usually a temporary error`)
此脚本在 #55165 中匹配在运行 Windows 的构建器上发生的特定 DNS 故障。
#!watchflakes
post <- builder == "darwin-arm64-12" && pkg == "" && test == ""
此脚本在 #55312 中是 watchflakes 自动创建的,用于跟踪 darwin-arm64-12 构建器上在该特定包测试运行之前发生的故障。
#!watchflakes
# note: sometimes the URL is printed with one /
default <- `(Get|read) "https://?(goproxy.io|proxy.golang.com.cn|goproxy.cn)`
此脚本在 #55163 中匹配使用某些非标准 Go 代理的错误。它使用 default
来允许其他 issue 承担这些代理引起的更具体失败的所有权。未匹配其他 issue 的失败将转到 #55163,而不是创建新的 issue。
#!watchflakes
default <- `: internal compiler error:`
此脚本在 #55257 中匹配任何构建中的编译器故障,无论正在测试什么包或仓库。它出于与上一个示例相同的原因使用 default
:因此,匹配特定编译器错误的 issue 仍然可以归档,但未匹配其他 issue 的失败将被分组到 #55257 中,而不是创建分配给触发问题的特定测试的新 issue。
此内容是 Go Wiki 的一部分。