ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Flutter 构建基础设施实战指南:LUCI 持续集成、test.dart 分片测试与发布包打包回滚

Flutter 构建基础设施实战指南:LUCI 持续集成、test.dart 分片测试与发布包打包回滚 Flutter 构建基础设施实战指南LUCI 持续集成、test.dart 分片测试与发布包打包回滚【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter本文以 Flutter 仓库的dev/bots/README.md为主体完整解析 Flutter 官方构建基础设施build infrastructure的运作方式LUCILayered Universal Continuous Integration机器人如何对每个 PR 与合入提交执行 test.dart 分片测试、如何用prepare_package.dart构建并发布可下载 SDK 压缩包、如何用unpublish_package.dart回滚误发版本以及 Android SDK/NDK 云端缓存的更新流程。读完后你将掌握本地复现 CI 分片的运行方法、LUCI recipe 的编辑-测试-发布完整工作流以及发布事故下按 git revision 精确撤销压缩包的操作步骤。一、构建基础设施全貌dev/bots目录是 Flutter 构建基础设施的落脚地。按 dev/bots/README.md 的说明这套设施的整体分工如下构建结果看板所有构建结果汇总在官方 build dashboardflutter-dashboard.appspot.com上。该看板允许重新触发构建但需要特殊权限普通贡献者应提交一个team-infra标签的 issue 来申请权限或申请新增机器类型。LUCI 机器人基于 [LUCI](https://chromium.googlesource.com/infra/luci/luci-py//refs/heads/main/README.md 对应项目) 的机器人在 Windows、Linux、Mac 机器上运行对每个 PR 和每个合入的提交执行 test.dart 脚本覆盖三类工作工具tools测试框架framework测试仅对已合入的变更重建并更新 main 分支 API 文档的 staging 站点main-api.flutter.dev。tag 版本部署对打了 tag 的 dev 和 beta 构建还会构建 Flutter Gallery 应用并部署到应用商店。物理设备测试看板还包含提交后post-commit在真机上执行的测试详见 dev/devicelab/README.md。整套 CI 行为由两个.ci.yaml文件配置这是 LUCI 体系的“调度清单”配置对象文件框架framework.ci.yaml仓库根目录约 7800 行引擎engineengine/src/flutter/.ci.yaml约 626 行二、test.dartCI 的核心入口与分片模型test.dart 是 LUCI 每次构建真正执行的脚本同时也是本地开发者复现 CI 的入口。其文件头注释dev/bots/test.dart定义了它的运行契约默认输出被过滤只显示错误若某个测试超过 utils.dart 中_quietTimeout10 分钟仍无进展会开始逐字打印以防挂死被掩盖--verbose关闭输出过滤原样打印全部输出默认错误不致命所有测试都跑完最后汇总报错退出码在有错误时为 1--abort-on-error改为遇到错误立即退出--dry-run只列出“将要执行”的测试而不真正执行是查看分片划分的最快方式。2.1 用 SHARD / SUBSHARD 环境变量选择测试集本地复现某个分片只需要设置环境变量。脚本从 utils.dart 中读取SHARD与SUBSHARD两个键# 跑全部框架测试 SHARDframework_tests bin/cache/dart-sdk/bin/dart dev/bots/test.dart # 命名子分片如 framework_tests 的 widgets 子分片 SHARDframework_tests SUBSHARDwidgets bin/cache/dart-sdk/bin/dart dev/bots/test.dart # 数字子分片1_2 表示“两分片中的第一片” SHARDbuild_tests SUBSHARD1_2 bin/cache/dart-sdk/bin/dart dev/bots/test.dart # Web 测试的第 3 个子分片从 0 开始编号写 2 SHARDweb_tests SUBSHARD2 bin/cache/dart-sdk/bin/dart dev/bots/test.dart其中工具类测试的官方本地示例是test.dart 注释中给出SHARDtool_tests bin/cache/dart-sdk/bin/dart dev/bots/test.dart2.2 分片shard清单test.dart 的selectShard映射是当前仓库实际注册的全部分片可以逐一与看板上的 builder 对应分片名职责framework_testspackages/flutter的框架测试tool_tests/tool_tests_commands/web_tool_tests/tool_integration_testsflutter_tools 各测试目录general / commands / web / integration shardbuild_tests构建 examples 应用的 APK/IPA/桌面构建冒烟含带空格路径场景framework_coverage框架覆盖率web_canvaskit_tests/web_skwasm_tests/web_long_running_testsWeb 端 CanvasKit、SkwasmWASM单测与长时集成测试android_engine_vulkan_tests/android_engine_opengles_testsAndroid 引擎测试Impeller Vulkan / OpenGLES 后端android_hardware_smoke_*_tests含 instrumented 变体真机硬件冒烟测试add_to_app_life_cycle_tests混合 Add-to-App 生命周期测试android_preview_tool_integration_tests/android_java17_tool_integration_testsAndroid 预览通道、Java 17 集成工具测试flutter_plugins仓库内插件包测试analyze静态分析analyze.dartsnippets文档片段dev/snippets测试docsAPI 文档构建docs.shskp_generator引擎 goldenSKP生成测试customer_testing客户场景测试fuchsia_precacheFuchsia 预缓存verify_binaries_codesigned/verify_binaries_pre_codesigned预签名二进制校验test_harness_tests用于测试 test.dart 自身正确性的自测分片2.3 其他关键参数--local-enginetarget/--local-engine-hosttarget/--local-engine-src-pathpath用本地构建的引擎跑测试例如--local-enginehost_debug_unopt。这三个参数会被 test.dart 同时转写为FLUTTER_LOCAL_ENGINE*环境变量并透传给flutter test--test-randomize-ordering-seedn测试默认按随机顺序执行以暴露测试间依赖指定固定种子可复现乱序设置TEST_RANDOMIZATION_OFFtrue可关闭随机化见 utils.dart其余未识别参数一律透传给flutter test脚本通过LUCI_CI环境变量判断是否运行在 LUCI 上utils.dart在 LUCI 上会禁用彩色输出。三、LUCI 工作前置条件Prerequisites按 README维护这套基础设施需要depot_toolsChromium 系基础设施工具集Python 包安装器sudo apt-get install python-pip仅在运行training_simulation时需要 Python 覆盖率包sudo pip install coverage。机器数量与机型由 Google 内部托管需要新机型时同样通过提交team-infraissue 申请。3.1 本地运行 prepare_package.dart 的认证准备要在本地执行打包脚本 prepare_package.dartREADME 给出的认证流程是确保depot_tools在PATH中Windows 上还需额外设置名为DEPOT_TOOLS的环境变量值为depot_tools的路径运行gsutil.py configWindows 上为python3 %DEPOT_TOOLS%\gsutil.py config完成 Google Cloud 认证创建一个本地临时目录并cd进去执行打包命令--publish表示成功后发布到 GCSdart [你的 Flutter 仓库路径]/dev/bots/prepare_package.dart \ --temp_dir. \ --revision[要打包的 revision] \ --branch[要发布的分支] \ --publish若遇到gsutil权限问题需要找仓库中的Hixie确认是否具备正确的推送权限。四、编辑 LUCI recipe 的标准工作流Flutter 的每个测试类别对应一个 recipe它们通过recipe_modules共享公共动作具体测试用哪个 recipe 可以查 infra 仓库flutter.googlesource.com/infra中的 builder 配置。recipe 本质是“受导入限制的 Python”由 luci/recipes-py 项目定义。README 给出的完整编辑循环如下克隆 recipes 项目git clone https://flutter.googlesource.com/recipes做修改通常改//recipes/recipes下的文件更新测试运行recipes.py test train让既有期望输出匹配新行为对全新用例通过修改 recipe 的GenTests方法验证。recipe 要求 100% 测试覆盖率在 staging 环境试跑 builderled get-builder luci.flutter.staging:BUILDER_NAME \ | led edit -pa git_refrefs/pull/PR number/head \ | led edit -pa git_urlhttps://github.com/flutter/repo \ | led edit-recipe-bundle \ | led launch其中BUILDER_NAME是 builder 名如Linux Enginegit_ref/git_url指向要构建的变更。若led报错先确认depot_tools检出是否为最新 5. 提交 CL 前先在本地建分支git checkout -b [分支名] 6. 上传补丁git commit后git cl upload打开输出的 URL 进入 CL 7. 用 Find owners 找到 reviewer。五、Android 工具链的云端缓存与更新Chrome infra 机器人使用的 Android SDK 与 NDK 存放在 Google Cloud 上。构建时机器人执行download_android_tools.py脚本把所需版本的 Android SDK 下载到dev/bots/android_tools。要查看当前已安装组件可用同一脚本拉取云端 SDK 后执行dev/bots/android_tools/sdk/tools/bin/sdkmanager --list5.1 更新云端 Google Cloud Storage 上的 Android SDK运行 SDK Manager 更新包dev/bots/android_tools/sdk/tools/android update sdk # Windows 上改用 android.bat用 UI 勾选要安装/更新的包运行dev/bots/android_tools/sdk/tools/bin/sdkmanager --updateWindows 运行sdkmanager.bat。若因 Windows 文件锁其他进程占用时文件/目录变只读导致无法移动文件而失败复制一份dev/bots/android_tools/sdk/tools目录从副本运行sdkmanager.bat并用--sdk_root指向dev/bots/android_tools/sdk运行dev/bots/android_tools/sdk/tools/bin/sdkmanager --licenses接受新组件许可建议再跑一次确认打印 All SDK package licenses accepted上传回云端dev/bots/upload_android_tools.py -t sdk5.2 更新云端 Android NDK下载新的 NDK 二进制例如android-ndk-r10e-linux-x86_64.bin进入工具目录cd dev/bots/android_tools删除旧目录rm -rf ndk运行 NDK 二进制解压./android-ndk-r10e-linux-x86_64.bin重命名解压目录mv android-ndk-r10e ndk上传回云端cd ../.. dev/bots/upload_android_tools.py -t ndk六、Codelabs 构建冒烟测试Flutter 官方 codelabs 用 Shrine 演示应用讲解 Material 组件其代码与 Flutter Gallery 中的 Shrine 相似但不相同。codelabs_build_test.sh 保证 Material Components for Flutter Codelabs 的最终版本104-complete分支始终能构建通过。从脚本实现看它执行克隆 codelabs 仓库 → 检出104-complete→ 执行flutter build bundle结果写入build_log_for_104_complete.txt仅在“构建成功”或命中预期失败标记日志含is not configured for Running时以 0 退出。该测试是框架层面的冒烟测试原则上不应失败失败时应在自己的 PR 中修复后重跑若失败并非你的 PR 直接导致、且破坏该测试确有必要则需向 MDC-Flutter 团队提交紧急 issue 升级处理。七、发布包打包prepare_package.dartFlutter 的每个可下载 SDK 压缩包都由 CI 调用 prepare_package.dart 构建。脚本的作用是准备一个 Flutter git 仓库用于分发填充.pub-preload-cache预装 Dart 依赖以及bin/cache引擎依赖与快照。压缩包只包含其构建所在平台的可执行文件与定制内容。从 prepare_package.dart 的参数解析代码看完整参数如下参数说明--revision必填要打包的 git revision必须是完整 40 位哈希源码中显式校验revision.length ! 40即报错--branch必填构建的 Flutter 分支。取值来自 common.dart 的Branch枚举beta、stable、master、main--temp_dir临时目录位置会写入数 GiB 数据需预留足够空间不指定时自动创建并在结束后自动清理--output产物压缩包输出目录缺省写入当前目录目录不存在时会自动递归创建--publish创建成功后发布到 Google Cloud Storage 的$baseUrl$releaseFolder目录--target_arch目标架构取值来自 common.dart 的TargetArch枚举x64、arm64缺省为宿主机架构--force-f覆盖已上传的旧包--dry_run只打印gsutil命令而不执行--help打印帮助内部实现上脚本先构造ArchiveCreator负责初始化仓库、生成压缩包--publish且非 dry-run 时开启严格模式再根据--publish选择ArchivePublisher.publishArchive(force)真发布或generateLocalMetadata()只生成本地元数据finally块中统一清理自动创建的临时目录并按退出码输出错误。八、发布回滚unpublish_package.dart当某个不该发布的版本被意外发出时unpublish_package.dart 用于把该 revision 的压缩包从其发布过的所有渠道中移除。脚本头注释说明它会删除云存储上的归档以及网站用来判断可用版本的 JSON 元数据文件若删除的是该渠道当前指向的版本会自动用该渠道上次新的版本顶替。从源码常量可见其作用面unpublish_package.dartGCS 桶为gs://flutter_infra_release发布目录为/releases。可选渠道由Channel枚举限定为dev/beta/stable平台由PublishedPlatform枚举限定为linux/macos/windows--revision支持多次指定或逗号分隔列表且逐项校验必须是 40 位十六进制完整哈希。README 给出的标准操作流程以 git 哈希d444a455de87a2e40b7f576dc12ffd9ab82fd491为例——先干跑确认输出无误后再加--confirm真正执行# 第一步dry run只预览将执行的动作 dart ./unpublish_package.dart --temp_dir/tmp/foo --revision d444a455de87a2e40b7f576dc12ffd9ab82fd491 # 第二步确认无误后真正执行 dart ./unpublish_package.dart --confirm --temp_dir/tmp/foo --revision d444a455de87a2e40b7f576dc12ffd9ab82fd491注意事项必须能访问云存储服务器且本地装有gsutil脚本只能在 Linux 或 macOS 上运行README 明确说明更多参数见dart ./unpublish_package.dart --help撤销后该版本将从网站消失且不会自动重建——尽管仓库中 tag 仍在——除非有人在该 revision 上强制重跑打包构建。九、小结dev/bots/README.md勾勒的是一条完整链路两个.ci.yaml定义调度 → LUCI 机器人调用test.dart按 SHARD/SUBSHARD 分片验证每次 PR 与合入 → 打 tag 的版本经prepare_package.dart打包发布到 GCS → 异常时用unpublish_package.dart精确回滚外围辅以 Android 工具链云端缓存维护、codelabs 冒烟测试与真机 devicelab 测试。对本地开发者最值得记住的三个复现入口是# 查看某次调用将执行哪些测试不实际运行 bin/cache/dart-sdk/bin/dart dev/bots/test.dart --dry-run # 复现某个分片 SHARDframework_tests bin/cache/dart-sdk/bin/dart dev/bots/test.dart # 预览打包/回滚行为 dart dev/bots/prepare_package.dart --dry_run --revision40位哈希 --branchmain相关入口文件可继续深入dev/bots/test.dart、dev/bots/utils.dart、dev/bots/suite_runners/各分片的具体 runner 实现、dev/bots/prepare_package/打包与发布的子模块以及 dev/devicelab/README.md真机提交后测试。【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表