持续集成 (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。有关晋升的更多信息,请参阅包晋升

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