.NET的构建和发布方式,是否再次迎来革新?
摘要:原文 | Matt Mitchell 翻译 | 郑子铭 为什么这么难?让我们绕道进入 Source Build 的世界。 微软大约在 .NET 3.1 版本发布前后开始着手将 Source Build 打造成一个“真正”的机制。在此之前,S
原文 | Matt Mitchell
翻译 | 郑子铭
为什么这么难?让我们绕道进入 Source Build 的世界。
微软大约在 .NET 3.1 版本发布前后开始着手将 Source Build 打造成一个“真正”的机制。在此之前,Source Build 的发布更像是针对每个 .NET 主要版本进行的一次性工作。由于持续开发过于困难,团队从春季新产品成型之初就开始着手,使新版 .NET 符合 Linux 发行版维护者的要求。为了理解为什么将微软的 .NET 发行版融入统一构建 (Unified Build) 项目如此困难,让我们回顾一下 Source Build 项目最初为何难以步入正轨。
为了使我们的发行合作伙伴能够分发 .NET,我们需要构建一个基础架构系统,该系统能够在以下限制条件下生成 .NET SDK:
单一实现!——每个组件只能实现一次
单平台——仅针对一个平台构建(即发行商合作伙伴试图发布的平台)。
单机构建——只需在一台机器上构建。我们不能要求复杂的编排基础架构。
Linux 发行版构建要求
Linux 发行版在构建将发布到其软件包源中的软件时,通常有更严格的规则和更低的灵活性。构建通常在离线状态下完成(断开与互联网的连接)。它只能使用之前在该构建系统中创建的工件作为输入。不允许使用已提交的二进制文件(尽管可以在构建时将其移除)。仓库中的任何源代码都必须满足严格的许可要求。有关 .NET 许可的信息,请参阅许可批准;有关示例发行版要求,请参阅 Fedora 许可批准。从概念层面来说,Linux 发行版合作伙伴希望能够追踪他们发布的每个工件,并将它们追溯到一组他们可以合理编辑的源代码和流程。所有未来的软件都应该基于之前 Source Build 生成的工件进行构建。注意:正如您所料,可能需要一个引导过程。
单一构建——一个用于将整个技术栈连接起来的仓库和编排框架
正如您之前了解到的,.NET 构建(与许多产品一样)实际上是由各种组件的 Azure DevOps 构建版本组成,并通过依赖项更新将它们拼接在一起。这意味着构建产品所需的信息和机制分布在存储库(构建系统中的构建逻辑和相关脚本,以及 Azure DevOps 处理的 YAML 文件)和我们“Maestro”系统保存的依赖关系流信息(生产者-消费者信息)之间。这对于我们的 Linux 发行版合作伙伴来说是不可行的。他们需要在无法访问这些 Microsoft 资源的情况下构建产品,并且构建方式必须适合他们的环境。手动从构建图中拼接产品是不合理的。我们需要一个能够封装这些信息的协调器。
源构建布局和协调器
编排器将 Azure DevOps 和 Maestro 为 .NET 分布式构建执行的任务替换为可以从单一源布局运行的任务,而无需连接互联网。您可以在dotnet/dotnet上查看现代化的更新布局和编排器。
单源布局–包含构建产品所需所有组件副本的单源布局。如果存在子模块(通常用于外部开源组件),则会将其扁平化。源布局的内容由产品图中每个组件的带注释依赖项决定,该依赖项以dotnet/sdk为根。该带注释依赖项的 SHA 值决定了布局中将填充哪些内容。注意:编译器和操作系统库等依赖项由构建环境提供。
关于每个组件的构建方式及其依赖关系的信息——对于单源布局中的每个组件,都提供了一个基本项目,其中说明了组件的构建方式。此外,还指明了组件级别的依赖关系。例如,必须先构建 .NET 运行时,ASP.NET Core 才能启动。
<ItemGroup>
<RepositoryReference Include="arcade" />
<RepositoryReference Include="runtime" />
<RepositoryReference Include="xdt" />
</ItemGroup>
构建协调器逻辑——构建协调器逻辑负责在构建图中的每个构建准备就绪(所有依赖项均已成功构建)时启动构建,并负责每个组件的输入和输出。组件构建完成后,协调器负责识别输出并为下游组件构建准备输入。您可以将其视为本地的 Dependabot,它计算已声明的输入存储库与包级依赖项信息的交集(例如,请参阅aspnetcore 的相关文档)。有关 .NET 构建中依赖项跟踪工作原理的更多信息,请参阅我之前的博客文章。
合规性验证——由于我们的 Linux 发行版合作伙伴构建的环境相对严格,因此我们需要构建一些自动化流程来识别潜在问题。
