ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

dotnet/runtime 的 Azure DevOps CI 管道架构与 Helix 测试编排完全指南

dotnet/runtime 的 Azure DevOps CI 管道架构与 Helix 测试编排完全指南 dotnet/runtime 的 Azure DevOps CI 管道架构与 Helix 测试编排完全指南【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime导读dotnet/runtime 仓库同时承载 CoreCLR、Mono、NativeAOT 等运行时与数百个基础类库跨云、移动、桌面与 IoT 平台。为了在有限的硬件资源下平衡测试覆盖与开发者体验仓库构建了一套基于 Azure DevOps Pipelines Helix 的多级验证体系。本文将基于 docs/workflow/ci/pipelines-overview.md结合仓库内真实的管道定义文件eng/pipelines/*.yml与路径评估脚本逐层拆解 PR 触发流程、各条管道的职责分工、Evaluate Paths 按变更裁剪测试的原理以及 Legacy 与 SourceGen Orchestrated 两种 Helix 测试执行模式的内部机制。读完本文你将掌握在 dotnet/runtime 仓库中定位管道定义、理解测试如何在 Helix 上分发与回收结果以及用/azp命令与 CI 交互的完整方法。一、整体架构从 PR 到测试结果回传的完整链路dotnet/runtime 仓库拥有数量庞大的验证管道validation pipelines用于在不同场景下评估产品质量。其中一部分自动运行一部分按需运行以适配硬件可用性与资源约束但整体的编排方式大体一致。假设有一个从feature/utf8分支合并到main的 PR其执行链路可以概括为以下 git 与时间线关系Azure DevOps Pipeline插件会取出合并到main的合并提交merge commit并将所有默认管道以及任何被请求的管道排队到Azure DevOps。随后各条管道经历构建运行时与类库 → 构建测试 → 在 Helix 上运行测试 → 将结果回传给 Azure DevOps → 在已知问题基础设施中检索已知失败字符串的流水线关键点每条管道都会自己构建不同版本的运行时与测试产物并最终执行测试。测试本身通常运行在一个名为Helix的独立环境中——这是一个分布式测试执行系统用于把数量庞大的测试分发到仓库所支持的广泛平台矩阵上执行。每个 worker 机器处理完自己的结果后结果会被回传至Azure DevOps并在构建的Tests选项卡中呈现。二、管道体系总览为什么需要这么多条管道该仓库包含多个运行时和覆盖面极广的类库与平台这种复杂性使得在资源使用、测试覆盖与开发者生产力之间取得平衡变得非常困难。为了尽量让构建更可靠并用最少的时间测试 PR 变更真正需要覆盖的内容仓库设计了多种管道——有的是必选required管道有的是可选optional管道。在 PR 上添加/azp list注释可以列出当前可用的管道添加/azp help注释可以查看可用的命令使用/azp run 管道名可以显式请求运行某条非默认管道。大多数仓库管道都使用一种基于 PR 变更内容评估路径的自定义机制以在不牺牲质量的前提下尽量少构建、少测试。这是每条依赖该基础设施的管道的初始阶段称为Evaluate Paths。在该步骤中可以看到仓库每个子集subset的评估结果。各子集的路径规则定义在 eng/pipelines/common/evaluate-default-paths.yml底层实现是 eng/pipelines/evaluate-changed-paths.sh其用法注释见该脚本开头L3-L12。2.1 Evaluate Paths按变更裁剪构建与测试的机制路径评估的本质是用git diff对比HEAD与一个 diff 目标如HEAD^1、origin/main再按照include包含与exclude排除路径规则判断当前变更是否命中某个子集。子集命中后管道中对应的 job 才会被触发。evaluate-default-paths.yml中定义的子集包括节选关键项子集说明include 要点exclude 要点coreclrCoreCLR 相关变更src/libraries/System.Private.CoreLib/*、src/native/libs/Common/*、src/native/libs/System.Globalization.Native/*等docs/*、src/mono/*、src/libraries/*、src/native/libs/*等mono_excluding_wasmMono不含 wasm变更同 CoreCLR 的核心共享路径src/coreclr/*、src/libraries/*及全部 wasm 专属路径libraries类库变更无默认全包含src/coreclr/*、src/mono/*、src/tests/*、src/tools/*等runtimetests运行时测试变更combined: truesrc/tests/*wasm/perf 专属路径tools_illinkILLink 工具链变更src/tools/illink/*、src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/*、src/coreclr/tools/ILVerification/*、global.json—tools_cdaccdacData Contract工具变更src/native/managed/cdac/*、src/coreclr/debug/runtimeinfo/*—installer安装器变更无src/coreclr/*、src/mono/*、src/libraries/*等coreclr_AppleSiliconApple Silicon 高风险目录src/coreclr/dlls/*、src/coreclr/gc/*、src/coreclr/jit/*、src/coreclr/pal/*、src/coreclr/vm/*等—wasmbuildtestsWASM 构建测试combined: trueeng/testing/tests.browser.targets、src/mono/wasm/Wasm.Build.Tests/*、src/tasks/*等—wasm_mono_runtimetests/wasm_coreclr_runtimetestsWASM 上的 Mono / CoreCLR 运行时测试combined: truesrc/tests/* 对应src/mono/*或src/coreclr/*各自排除不相关子目录non_mono_and_wasm非 Mono 且非 wasm 的兜底子集—eng/pipelines/mono/*、src/mono/*及全部 wasm 专属路径文件中还预定义了若干常量路径组_const_paths例如_wasm_specific_only所有 wasm/wasi 专属路径eng/testing/tests.browser.targets、src/mono/browser/*、src/mono/wasm/*、src/tasks/WasmAppBuilder/*等_wasm_pipelineseng/pipelines/**/*wasm*_wasm_chromeeng/testing/bump-chrome-version.proj、eng/testing/BrowserVersions.props_perf_pipeline_specific_onlyeng/pipelines/performance/*、eng/testing/performance/*_always_exclude*.md、LICENSE.TXT、PATENTS.TXT、THIRD-PARTY-NOTICES.TXT等——纯文档与许可证变更永远不触发构建。这些常量以${{ parameters._const_paths.* }}的方式被注入到各子集的 include/exclude 列表中确保 wasm 专属目录不会误触发通用 job。底层脚本的三种匹配模式eng/pipelines/evaluate-changed-paths.sh 是路径评估的底层实现其核心逻辑probePaths函数支持三种场景只指定 exclude 路径包含除 exclude 列表外的所有路径变更只指定 include 路径仅包含列表内的路径变更同时指定 exclude include传入--combined时先用 include 路径集再在其上应用 exclude 排除若仍有变更则设置变量为true未传--combined默认时先评估除 exclude 列表外的一切变更若未找到适用变更再评估 include 路径两者任一命中即设置变量为true。脚本支持的参数包括--difftarget SHA或分支与 HEAD 做 diff 的目标例如HEAD^1、origin/main、具体 SHA--excludepaths path1path2以分隔的排除路径列表--includepaths path1path2以分隔的包含路径列表--combined同时使用 include 与 exclude 路径--subset name子集名称仅用于日志输出--azurevariable name命中时写入的 Azure DevOps 变量名。底层使用自定义的git diffcustomGitDiff带-M -C -b --ignore-cr-at-eol --ignore-space-at-eol参数执行命中判定依赖git diff --exit-code --quiet的退出码并通过Write-PipelineSetVariable设置变量。命中后会打印----- Matching files for subset -----及具体匹配文件列表并输出Setting pipeline variable vartrue未命中则输出No changed files for subset。在管道 YAML 中消费该变量的方式如下以 eng/pipelines/runtime.yml 为例condition: - or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs[SetPathVars_coreclr.containsChange], true), eq(variables[isRollingBuild], true))即只有EvaluatePaths阶段评估出coreclr子集有变更或当前是滚动构建rolling build对应 job 才会执行。三、核心管道逐个拆解3.1 Runtime pipeline主验证管道必选runtime是运行时产品的主管道定义于 eng/pipelines/runtime.yml。它承载最关键、且测试资源充足到可以在合理时间内出结果的平台与测试。该管道中执行的 runtime 与 libraries 测试被视为inner loop——即开发者本地运行测试时执行的同一批测试。在 runtime.yml 中可以看到其触发配置trigger启用batch: true分支只包含release/*.*路径层面排除**.md、docs/*、eng/Version.Details.xml等pr覆盖所有分支include: [*]schedules使用 cron0 8,20 * * *UTC 08:00 与 20:00仅在main分支上运行且always: false仅当自上次成功调度运行以来有变更才运行。构建阶段通过 eng/pipelines/common/platform-matrix.yml 模板展开为庞大的平台矩阵主要包括CoreCLR verticals在 linux_musl_arm/arm64、windows_arm64、linux_arm、linux_arm64、linux_musl_x64、osx_arm64、windows_x64/windows_x86 等平台执行-s clrlibshostpacks系列构建Libraries 测试在 linux_x64、linux_musl_x64、osx_arm64、windows_x64 上以testScope: innerloop提交到 eng/pipelines/libraries/helix.yml 定义的 Helix 队列NativeAOTDebug/Checked/Release 配置下的 NativeAOT 构建与冒烟测试clr.aot子集nativeaot tree测试R2RReadyToRun测试、crossgen构建、GCC 工具链构建、非便携式构建如 tizen_armel/p:PortableBuildfalse等构建步骤前常预置setup-sccache构建后执行sccache-stats以加速与统计缓存命中。针对移动平台与 wasm该管道只运行冒烟测试smoke tests。原文档明确说明这是出于硬件与时间限制的考虑——此前贡献者因不稳定性和 PR 验证等待时间过长而受到影响因此迁移到冒烟测试方案来保护这些平台的基本质量。3.2 Runtime-dev-innerloop pipeline开发者内循环必选该管道同样是必选管道目的是覆盖**开发者内循环inner loop**场景例如运行某个特定构建命令、在 Visual Studio 中运行测试等可能被任意变更影响的场景。仓库中对应定义位于 eng/pipelines/global-build.yml其头部注释点明了设计意图The purpose of this pipeline is to exercise various developer workflows in the repo. Primarily, it is meant to cover local (non-cross) build scenarios and source-build scenarios that commonly cause build breaks.该管道用于演练仓库中各种开发者工作流主要覆盖本地非交叉构建场景和常见的导致构建破坏的 source-build 场景。从 global-build.yml 可以看到它覆盖的具体场景使用MSBuild generator的 Release 配置构建-c Release -msbuild验证 CMake/MSBuild 生成路径仅指定RuntimeFlavor如/p:RuntimeFlavorMono的 Debug 构建——专门捕捉依赖 Configuration 也被指定之类的隐性错误通过linux_x64_dev_innerloop平台定义在dev_innerloop队列上执行。3.3 Dotnet-linker-tests裁剪安全性验证必选这也是一条必选管道定义于 eng/pipelines/runtime-linker-tests.yml。其目的是验证libraries 代码对 ILLink 友好即使用 ILLink 裁剪类库时不会出现裁剪 bug——例如某个特定场景必需的方法被意外剪掉。从管道定义可见其执行内容ILLink 测试在 windows_x64 与 linux_x64 上构建libs.sfx子集后运行tools.illinktests测试/p:ToolsConfigurationDebug并把artifacts/TestResults/Debug下的 xUnit XML 结果复制到$(_BuildConfig)目录以正确发布到 Tests 选项卡Runtime_Release 纵向构建clr.runtimeclr.nativeaotruntimeclr.corelibclr.toolsclr.nativecorelibclr.nativeaotlibslibstools.illinkhost.native子集然后通过 eng/pipelines/libraries/execute-trimming-tests-steps.yml 执行裁剪测试Browser-wasm 纵向-s monolibstools.illink加上-p:WasmBuildNativefalse在 wasm 上执行裁剪测试runAotTests: false。该管道调度为 cron0 7,19 * * *UTC 07:00 与 19:00并在 PR 上作为必选检查运行。其触发条件绑定SetPathVars_tools_illink.containsChange、SetPathVars_libraries.containsChange等评估结果。3.4 Runtime-extra-platforms补充平台覆盖非默认双日调度该管道默认不随 PR 运行不属于 PR 必选检查但每天运行两次并且可以在特定 PR 上通过注释/azp run runtime-extra-platforms触发。它的定位是在硬件容量不足以常驻主管道的平台移动端、浏览器上运行 inner loop 测试在基于主管道覆盖可以合理推断测试会自然通过的平台上运行测试。例如主管道在较新的 Ubuntu 版本上运行测试而仓库还支持某个 LTS 版本则在 extra-platforms 管道上运行该 LTS 版本的测试确保面向实际发布平台的测试健康在总体稳定但硬件不足以放入常规管道的平台上运行测试。原文档给出的实例windows arm64 的 libraries 测试放在此管道而 JIT 测试留在主管道——因为 JIT 是生成该平台原生代码最需要优先测试的部分。定义文件 eng/pipelines/runtime-extra-platforms.yml 揭示了其调度与组成schedules使用 cron0 3 * * *UTC 03:00 每日always: false通过模板展开的 job 包括eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml仅滚动构建时添加runtime-extra-platforms-ioslike.yml、runtime-extra-platforms-ioslikesimulator.ymlruntime-extra-platforms-android.yml、runtime-extra-platforms-androidemulator.ymlruntime-extra-platforms-maccatalyst.yml、runtime-extra-platforms-linuxbionic.yml以及非平台专属的runtime-extra-platforms-other.yml仅当isNotSpecificPlatformOnlyBuild为 true 时执行。各 job 通过isExtraPlatformsBuild、isWasmOnlyBuild、isAndroidOnlyBuild等开关控制是否在仅某平台构建模式下运行。3.5 Outer loop 管道长耗时与不稳定测试每日分析仓库中存在多名称含Outerloop的管道。这些管道不会在每次 PR 上默认运行可以通过/azp run注释触发并每天运行一次用于分析测试结果。它们承载的测试通常具备以下特征长时间运行long-running稳定性不佳例如某些网络测试会修改机器状态state-modifying。四、Helix 上的运行时级测试编排两种执行模式无论是主管道还是补充管道测试最终都要分发到 Helix 执行。Helix 的 workitem 有两种典型编排模式理解二者有助于判断测试失败时的行为差异。4.1 Legacy tests经典 xUnit 控制台模式进程隔离在较老的运行时测试中经典的 xUnit 控制台运行器console runner运行一组生成的 xUnit facts。每个 fact 会调用一个 shell/batch 脚本脚本设置环境启动构成运行时测试台的各个控制台应用包装器wrapper负责收集所有被启动进程的输出。主要优点每个测试都运行在进程隔离process isolation中使 xUnit 与其子进程拥有解耦的运行时从而让测试装置对原生崩溃native crashes更有韧性。主要代价每个测试都要付出启动成本与进程启动成本极其昂贵。该类型 Helix workitem 的典型流程流程要点Helix 入口点Entrypoint在 LKGLast Known Good运行时中启动 xUnit 测试包装器包装器以进程隔离方式逐个启动测试Test N每个测试以退出码 100 报告成功最终由 Helix Reporter 将测试结果回传给 Azure DevOps。4.2 SourceGen Orchestrated tests合并运行器模式成本高效合并后的运行时测试consolidated runtime tests会在构建期间生成一个入口点程序集entry point assembly。其机制是源生成source generation对将要运行的测试做 glob 收集生成一个Main方法每个测试在try/catch块中运行并捕获所有必要输出少数确实需要隔离的测试不会在进程内调用而是按需启动另一个进程执行。主要优点较少依赖进程隔离测试成本效率更高。主要代价第一个未处理的原生或托管异常unhandled exception会暂停所有测试——这与 libraries 测试的行为类似。为保证可靠性该模式还有两个配套组件Watchdog看门狗顺序调用测试的合并运行器merged runner托管在 watchdog 之下用于处理挂起hang场景Log Fixer日志修复器在崩溃发生后运行尝试修复损坏的日志使 Helix 能尽可能多地汇报 workitem 进度。其典型流程从源码结构看仓库中为不同平台准备了多种可复用的测试运行器实现例如 src/libraries/Common/tests/AndroidTestRunner/AndroidTestRunner.cs、src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs、src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs 与 src/libraries/Common/tests/SingleFileTestRunner/SingleFileTestRunner.cs这些 runner 与上文的 watchdog/log-fixer 机制共同构成移动端、WebAssembly 与单文件场景下的合并测试执行支撑。五、开发者实用速查如何与 CI 交互综合原文档与仓库管道定义将常用交互方式汇总如下目的操作查看可用管道在 PR 评论中添加/azp list查看可用命令在 PR 评论中添加/azp help运行非默认管道如 extra-platforms在 PR 评论中添加/azp run runtime-extra-platforms运行任意 Outerloop 管道在 PR 评论中添加/azp run Outerloop管道名查看路径评估结果打开构建的Evaluate Paths阶段查看各子集SetPathVars_subset.containsChange的命中情况查看测试结果构建的Tests选项卡Helix 回收后的结果需要注意的是本文所述 cron 调度、平台矩阵与子集定义均以当前仓库 eng/pipelines 目录下的实际文件为准不同版本分支的调度时间与平台组合可能不同读者在阅读其他版本时应以对应分支的 YAML 为准。六、结语多级管道 路径裁剪 Helix 分发三位一体dotnet/runtime 的 CI 架构可以概括为三个相互咬合的层次多级管道体系必选的runtime主验证、global-builddev innerloop、runtime-linker-tests裁剪安全管道保护每个 PR 的核心质量非必选的runtime-extra-platforms与各种Outerloop管道通过/azp run或定时调度补足平台与长耗时测试的覆盖Evaluate Paths 路径裁剪通过 evaluate-default-paths.yml 的子集定义与 evaluate-changed-paths.sh 的 git diff 探测让每个 PR 只构建与测试真正受影响的组件在资源消耗与质量保障之间取得平衡Helix 分布式执行Legacy 模式以进程隔离换取韧性但成本高昂SourceGen Orchestrated 模式以合并运行器 watchdog log fixer 的组合换取成本效率二者共同支撑起跨平台的海量测试执行与结果回收。理解这三层机制是在这个多运行时、多平台的大型仓库中高效贡献代码、快速定位 CI 失败的关键起点。若需进一步了解 PR 提交流程与失败分析可继续阅读同目录下的 pr-guide.md 与 failure-analysis.md。【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表