本文档介绍了 Protocol Buffers 项目用于确保跨多种编程语言、操作系统和构建配置的代码质量的持续集成 (CI) 系统。
Protocol Buffers CI 系统会自动测试代码更改,以检测回归并确保项目各种语言实现之间的兼容性。该系统基于 GitHub Actions 构建,并采用全面的测试矩阵,涵盖各种平台、编译器和配置选项。
来源:.github/workflows/test_cpp.yml .github/workflows/test_java.yml .github/workflows/test_python.yml .github/workflows/test_ruby.yml .github/workflows/test_php.yml .github/workflows/test_csharp.yml .github/workflows/test_objectivec.yml .github/workflows/test_rust.yml .github/workflows/test_upb.yml .github/workflows/test_bazel.yml
CI 系统支持两种工作流
这些工作流在合并前针对拉取请求运行,侧重于关键测试,以便为开发人员提供快速反馈。目标是在不产生过多等待时间的情况下捕获明显问题。
这些工作流在更改合并到主分支后运行。它们包括所有预提交测试,以及其他耗时更长的测试,这些测试对于每个拉取请求来说都太慢了。
区别由工作流输入控制
在工作流文件中,测试可以标记为 continuous-only: true,以指示它们应仅在持续测试期间运行。
来源:.github/workflows/test_cpp.yml3-19 .github/workflows/test_cpp.yml32-37
CI 系统在全面的配置矩阵中测试 Protocol Buffers
每种支持的语言都有专用的工作流和特定的测试配置
| 语言 | 工作流文件 | 关键测试组件 |
|---|---|---|
| C++ | test_cpp.yml | 核心库、优化/调试构建、 sanitizers、多个编译器 |
| μpb | test_upb.yml | 小型 C 实现、wheel 生成 |
| Java | test_java.yml | JDK 版本 (8/11/17)、兼容性测试、Maven BOM |
| Python | test_python.yml | 多个 Python 版本、纯 Python 和 C++ 实现 |
| Ruby | test_ruby.yml | 多个 Ruby 版本、原生和 FFI 实现 |
| PHP | test_php.yml | PHP 版本、内存泄漏测试、扩展编译 |
| C# | test_csharp.yml | .NET 构建、一致性测试 |
| Objective-C | test_objectivec.yml | Xcode、CocoaPods、Apple Silicon 测试 |
| Rust | test_rust.yml | Bazel、Cargo、多种配置 |
来源:.github/workflows/test_cpp.yml26-40 .github/workflows/test_java.yml26-60 .github/workflows/test_python.yml26-56 .github/workflows/test_ruby.yml26-42 .github/workflows/test_php.yml26-55
每个工作流都遵循类似的结构
例如,在 C++ 工作流 (test_cpp.yml) 中,有以下作业组:
来源:.github/workflows/test_cpp.yml22-590 .github/workflows/test_java.yml26-60 .github/workflows/test_python.yml26-56 .github/workflows/test_ruby.yml26-42 .github/workflows/test_php.yml26-55
大多数基于 Linux 的测试在 Docker 容器中运行,以确保环境的一致性。这些容器托管在 Google Artifact Registry (us-docker.pkg.dev/protobuf-build/containers/)
不同的容器用于特定目的
java:8.0.1-11-b77fdae6d4771789dfc66a56bf8d806354e8011a)sanitize:8.0.1-b77fdae6d4771789dfc66a56bf8d806354e8011a)emulation:7.1.2-aarch64-2920199ab0090ed427413a8e422e62695c8392a8)来源:.github/workflows/test_cpp.yml72-79 .github/workflows/test_upb.yml48-57 .github/workflows/test_php.yml70-86
Bazel 是用于测试的主要构建系统。它提供了封闭式构建,并跨语言和平台实现了一致的依赖管理。
关键的 Bazel 配置定义在 .bazelrc 和 ci/common.bazelrc 中
# Build modes
build:dbg --compilation_mode=dbg
build:opt --compilation_mode=opt
# Sanitizer common settings
build:san-common --config=dbg --strip=never --copt=-O0 --copt=-fno-omit-frame-pointer
# Specific sanitizer configurations
build:asan --config=san-common --copt=-fsanitize=address --linkopt=-fsanitize=address
build:tsan --config=san-common --copt=-fsanitize=thread --linkopt=-fsanitize=thread
build:msan --config=san-common --copt=-fsanitize=memory --linkopt=-fsanitize=memory
build:ubsan --config=san-common --copt=-fsanitize=undefined --linkopt=-fsanitize=undefined
来源:.bazelrc1-37 ci/common.bazelrc1-84
CI 系统使用 protocolbuffers/protobuf-ci 仓库中的多个自定义 GitHub Actions
| 操作 | 目的 |
|---|---|
checkout | 安全地检出特定提交的代码 |
bazel | 运行 Bazel 命令 |
bazel-docker | 在 Docker 容器中运行 Bazel |
docker | 在 Docker 容器中运行命令 |
sccache/ccache | 提供编译器缓存以加快构建速度 |
cross-compile-protoc | 交叉编译 protoc 编译器 |
composer-setup | 设置 PHP Composer |
来源: .github/workflows/test_cpp.yml66-79 .github/workflows/test_php.yml64-86 .github/workflows/test_ruby.yml45-57
CI 系统使用多个 Sanitizer 来检测细微的错误
这些 Sanitizer 在 C++ 测试中进行了配置
来源: .bazelrc8-32 ci/common.bazelrc4-35 .github/workflows/test_cpp.yml30-36
CI 系统跨多个平台和架构测试 Protocol Buffers
交叉编译示例
来源: .github/workflows/test_cpp.yml120-126 .github/workflows/test_php.yml119-126 .github/workflows/test_ruby.yml76-83
仓库的 examples/ 目录包含演示 Protocol Buffers 使用不同构建系统的示例项目。这些示例也在 CI 中进行测试,以确保它们保持可用
来源: .github/workflows/test_bazel.yml25-75 examples/BUILD.bazel1-209 examples/WORKSPACE1-85 examples/MODULE.bazel1-31
开发者可以使用 Bazel 在本地运行相同的测试
当 Sanitizer 检测到问题时
当测试在特定平台上失败时
当测试在本地通过但在 CI 中失败时
Protocol Buffers CI 系统在多种语言、平台和配置下提供全面的测试。通过了解其工作原理,开发者可以更有效地为项目做出贡献,并在出现测试失败时进行故障排除。