持续集成 (CI) 教程

注意

  • 这是一个高级主题,需要具备 Conan 的先验知识。请先阅读并练习用户教程

  • 本节适用于设计和实施涉及 Conan 包的 CI 管道的开发运维 (devops) 和构建工程师,如果情况并非如此,您可以跳过本节。

持续集成对于不同的用户和组织有不同的含义。在本教程中,我们将介绍用户更改其包的源代码,并希望自动为这些包构建新二进制文件,同时计算这些新包更改是否能干净地集成或破坏组织主要产品的情景。

在本教程中,我们将使用这个小型项目,它使用多个包(默认为静态库)来构建几个应用程序:一个视频游戏和一个地图查看器实用程序。gamemapviewer 是我们的最终“**产品**”,是我们分发给用户的。

digraph game { node [fillcolor="lightskyblue", style=filled, shape=box] rankdir="BT" "game/1.0" -> "engine/1.0" -> "ai/1.0" -> "mathlib/1.0"; "engine/1.0" -> "graphics/1.0" -> "mathlib/1.0"; "mapviewer/1.0" -> "graphics/1.0"; "game/1.0" [fillcolor="lightgreen"]; "mapviewer/1.0" [fillcolor="lightgreen"]; { rank = same; edge[ style=invis]; "game/1.0" -> "mapviewer/1.0" ; rankdir = LR; } }

依赖图中的所有包都使用版本范围来 requires 其直接依赖项,例如,game 包含一个 requires("engine/[>=1.0 <2]"),因此依赖项的新补丁版本和次要版本将自动被使用,无需修改配方。

注意

重要说明

  • 本节以实践教程的形式编写。旨在通过在您的机器上复制命令来重现。

  • 本教程介绍了 CI 问题的一些工具、良好实践和常见方法。但没有万能的解决方案。本教程并非唯一行事方式。不同的组织可能有不同的需求和优先事项,不同的构建服务能力和预算,不同的规模等。教程中介绍的原则和实践可能需要进行调整。

  • 如果您有任何问题或反馈,请在 https://github.com/conan-io/conan/issues 提交新问题。

  • 然而,一些原则和最佳实践适用于所有方法。例如,包的不可变性、在不同仓库之间使用提升以及不为此目的使用 channel 都是应该遵循的良好实践。

包和产品管道

当开发人员对包源代码进行更改时,我们将考虑整个系统 CI 的两个不同部分或管道:**包管道**和**产品管道**。

  • **包管道**负责在包代码更改时构建单个包。如有必要,它将为不同的配置构建该包。

  • **产品管道**负责构建组织的主要“产品”(实现最终应用程序或可交付成果的包),并确保依赖项中的更改和新版本正确集成,必要时重建图中的任何中间包。

设想是,如果某个开发人员对 ai 包进行了更改,产生了新的 ai/1.1.0 版本,包管道将首先构建这个新版本。但这个新版本可能会意外地破坏或需要重建一些消费者包。如果我们的组织主要**产品**是 game/1.0mapviewer/1.0,那么产品管道就可以被触发,在这种情况下,它会重建 engine/1.0game/1.0,因为它们受到了更改的影响。

仓库和提升

多个服务器端仓库的概念对 CI 非常重要。在本教程中,我们将使用 3 个仓库。

  • develop:这个仓库是开发人员在他们的机器上配置的主要仓库,以便能够 conan install 依赖项并进行工作。因此,它应该相当稳定,类似于 Git 中的共享“develop”分支,并且该仓库应该包含组织预定义平台的预编译二进制文件,这样开发人员和 CI 就无需重复执行 --build=missing 并从源代码反复构建。

  • packages:这个仓库将用于临时上传由“包管道”构建的包,避免直接上传到 develop 仓库,直到这些包完全验证后再避免中断。

  • products:这个仓库将用于临时上传由“产品管道”构建的包,同时构建和测试新的依赖项更改不会破坏主要的“产品”。

digraph repositories { node [fillcolor="lightskyblue", style=filled, shape=box] rankdir="LR"; subgraph cluster_0 { style=filled; color=lightgrey; rankdir="LR"; label = "Packages server"; "packages\n repository" -> "products\n repository" -> "develop\n repository" [ label="promotion" ]; } }

提升是将包从一个管道提供给另一个管道的机制。将上述包和产品管道与仓库连接起来,将有 2 种提升方式。

  • 当单个包的不同配置的所有二进制文件都已通过 packages pipeline 构建完成并上传到 packages 仓库后,该包的新版本和更改可以被视为“正确”并被提升(复制)到 products 仓库。

  • products pipeline 由于 products 仓库中的新包版本而从源代码构建了所有需要重建的必要包,并检查了组织“产品”(例如 game/1.0mapviewer/1.0)没有被破坏时,这些包就可以从 products 仓库提升(复制)到 develop 仓库,以便所有其他开发人员和 CI 可以使用它们。

注意

本教程仅模拟**开发**流程。在生产系统中,将有其他仓库和提升,例如用于 QA 团队的 testing 仓库,以及用于最终用户的最终 release 仓库,以便包在通过验证后可以从 develop 提升到 testing 再到 release。有关提升的更多信息,请参阅包提升

让我们开始本教程,转到下一节进行项目设置。