TeamCI的核心针对代码运行多个静态分析工具,并向GitHub Checks API报告。 团队使用多种语言,这意味着工具以不同的语言编写并以不同的方式发布。 TeamCI的支票生成器必须考虑多样性,同时要足够灵活以采用新的工具和语言。 我还希望授权用户改进他们的工具。 这就是支票生成器是开源的原因。 任何人都可以在GitHub上发布代码并将其标记为开源,但这还不足以使人们开始黑客入侵。 这篇文章通过示例介绍了代码。 除此之外,这只是一个有趣的例子,说明您可以使用肘部润滑脂和Bash飞溅(国王万岁)完成任务。
高级设计
我在上一篇文章中写过关于构建TeamCI的文章。 如果您不熟悉TeamCI的工作方式,那么这是一个很好的起点。
这篇文章涵盖了TeamCI实际工作原理的技术细节。
每个检查( rubocop , shellcheck , eslint等)都是Docker映像。 使用Docker可以轻松支持任何语言或运行时。 Docker Compose管理配置。 Docker容器运行时将测试代码安装在/code并将共享配置安装在/config 。 /code也是工作目录。 基于高山的图像是首选。

TeamCI使用TAP输出来分析结果并创建Github检查注释 。 没有工具输出符合TeamCI要求的TAP。 幸运的是,它们都输出JSON,因此每个Docker映像都包含一个将JSON输出转换为TeamCI的TAP的程序。
每个Docker映像都包含一个包装器脚本。 包装脚本处理设置CLI选项,将JSON解析为TAP并确定退出代码。 示例职责是检查/config文件,并添加适当的--config FILE和--output选项。 包装脚本以-tap后缀命名。 因此, shellcheck的包装器变为shellcheck-tap 。 包装脚本不仅可以设置选项,还可以指定要测试的文件。 它们也是Dockerfile的CMD 。 简而言之,他们负责正确调用基础工具,输出TAP并确定退出代码。
TeamCI使用三个退出代码:
-
0代表成功 -
1代表任何形式的失败 -
7表示跳过(例如运行Ruby linter,但没有Ruby文件)
仅当工具通过退出代码或输出传达结果时,才能确定跳过结果。 并非每个工具都这样做,因此在这种情况下使用退出代码0 。 不幸的是,在Github PR UI中这是“通过”而不是“中立”的。

TeamCI通过Buildkite执行检查。 使用Buildkite无需管理基础架构。 TeamCI使用Buildkite Elastic堆栈 ,该堆栈提供可伸缩的基础结构和正常运行的Docker堆栈。 GitHub Check Runs触发Buildkite构建。 每个检查都作为构建步骤运行。 TeamCI在每个完成的步骤上都会收到一个Webhook,并将结果传达回GitHub。
每个检查构建步骤都会克隆测试代码和关联的ORG/teamci配置存储库,并导出环境变量。 由于它在所有构建步骤之间共享,因此预命令挂钩可以执行所有这些操作。 这样就产生了苗条的构建脚本。 构建脚本通过docker-compose run和在/code和/config挂载的卷来运行相关检查。
验收测试涵盖所有检查。 接受测试用蝙蝠写。 测试涵盖0, , 1 ,和7退出案例以及自定义配置案例(例如/config存在一个配置文件)。 测试通过BuildKite 仿真包装器运行,该包装器导出相关的Buildkite环境变量并执行挂钩。 命令是在测试通过的可执行存根test/stubs/bin和附加test/stubs/bin至$PATH ,从而优先于真正的可执行文件。 测试套件将git命令存根以使用固定装置代码而不是实际的git存储库。 没有它,测试套件将无法工作。
检查代码演练
让我们通过一个具体的检查,看看它在实践中如何工作。 stylelint PR是一个很好的介绍。 让我们从测试开始:
@test "stylelint: invalid repo fails" {
buildkite-agent meta-data set 'teamci.repo.slug' 'stylelint/code'
buildkite-agent meta-data set 'teamci.head_branch' 'fail'
run test/emulate-buildkite script/stylelint
[ $status -eq 1 ]
[ -n "${output}" ]
[ "$(echo "${output}" | grep -cF -- '--- TAP')" -eq 2 ]
# Test for annotation keys
echo "${output}" | grep -qF 'filename:'
echo "${output}" | grep -qF 'blob_href:'
echo "${output}" | grep -qF 'start_line:'
echo "${output}" | grep -qF 'end_line:'
echo "${output}" | grep -qF 'warning_level:'
echo "${output}" | grep -qF 'message:'
echo "${output}" | grep -qF 'title:'
[ -n "$(buildkite-agent meta-data get 'teamci.stylelint.title')" ]
} 前两行是设置方法。 TeamCI通过构建元数据传递git repo,分支和提交,以便检查代码知道要克隆的代码。 这两行设置映射到git夹具的值。 灯具位于test/fixtures/$REPO/$BRANCH 。 git 存根以实现该模式。
下一行通过buildkite仿真包装器执行检查,然后对退出代码和输出进行断言。 此测试使用正确形状的注释声明TAP输出。
该测试涵盖了其余的成功案例和配置文件案例。 这是针对用户提供的配置文件的测试:
@test "stylelint: config file exists" {
buildkite-agent meta-data set 'teamci.repo.slug' 'stylelint/code'
buildkite-agent meta-data set 'teamci.head_branch' 'config_file'
buildkite-agent meta-data set 'teamci.config.repo' 'stylelint/config'
buildkite-agent meta-data set 'teamci.config.branch' 'config_file'
run test/emulate-buildkite script/stylelint
# The configured options should make the failing fixture pass
[ $status -eq 0 ]
[ -n "${output}" ]
[ -n "$(buildkite-agent meta-data get 'teamci.stylelint.title')" ]
} 除了提供的配置库夹具外,其结构相同。 这些测试使用的夹具使用默认配置失败,但通过自定义配置通过。 因此,预期结果为0 。
PR包含预期的代码更改:
- 从
/stylelint构建的stylelintDocker映像 -
/stylelintstylelint-tap包装器 - 甲
tapify.rb用于JSON转换为tap中/stylelint。 - 对
docker-compose.yml -
Makefile - 使用相应的夹具进行
test/acceptance。
“有效回购通过测试”可能还会在灯具中散布无关的代码文件。 Stylelint测试样式表(例如**/*.css 。css),因此代码目录中的杂散Ruby文件不应导致失败。 测试此内容取决于工具。 Stylelint需要一个明确的文件列表,因此使用了glob。 但是,对于诸如PHP CodeSniffer之类的东西而言却并非如此,它可以检测php文件本身。
包起来
一旦了解了结构,就可以直接添加新的支票。 我从最新的支票开始复制和粘贴,因为它们都足够相似。 然后,我调整测试, -tap包装程序和tapify.rb 。 我首先测试退出代码1。这使我可以测试工具是否按预期工作并检查JSON输出。 之后很容易调整tapify.rb 。 然后,它开始进行繁琐的工作来创建传递的固定装置,配置文件用例和Docker映像。
在以下情况下,添加新工具是最简单的:
- 该工具自动检测可测试的文件
- 可以提供一个明确的配置文件
- 该工具将JSON打印为标准输出
- 错误和无关信息会打印为标准错误
- 该工具发出信号(通过退出代码或输出),表明未找到可测试的文件
- 有一些排除文件的方法
我很高兴编写了构建器。 这是一项直接的任务,加上验收测试套件使我充满了信心。 经验还使我在这些工具中更喜欢使用语义。
所以你怎么看? 是否要添加自己的支票? 随时发送PR,使TeamCI对您更有用。 如果没有,那么至少您了解到使用Bash(国王万岁)进行TDD是可能的,而且很有趣。 在测试版中免费测试TeamCI 。
From: https://hackernoon.com/inside-teamcis-check-code-b12770de57a5