持续集成 (CI) 教程

注意

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

  • 本节面向设计和实现涉及 Conan 包的 CI 流水线的 Devops 和构建工程师,如果您不属于此情况,可以跳过本节。

持续集成对不同的用户和组织有不同的含义。在本教程中,我们将涵盖用户对其包的源代码进行更改并希望自动构建这些包的新二进制文件,同时计算这些新的包更改是否能 cleanly 集成或破坏组织的最终产品的情况。

在本教程中,我们将使用这个小型项目,该项目使用几个包(默认为静态库)来构建两个应用程序:一个视频游戏和一个地图查看器工具。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]"),因此新依赖项的补丁和次要版本将自动被使用,无需修改 recipe。

注意

重要说明

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

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

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

  • 然而,一些原则和最佳实践对所有方法都通用。例如,包的不可变性,使用仓库之间的晋升而不是使用 channel 来达到此目的,这些都是应该遵循的良好实践。

包和产品流水线

当开发人员对其包的源代码进行更改时,我们将考虑整个 CI 系统中的 2 个不同的部分或流水线:包流水线产品流水线

  • 包流水线负责在包代码更改时构建单个包。如有必要,它将为不同的配置进行构建。

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

其思想是,如果某个开发人员对 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" ]; } }

晋升(Promotions)是用于使包从一个流水线对另一个流水线可用的机制。将上述包流水线和产品流水线与仓库连接起来,将有 2 次晋升。

  • 当包流水线为单个包的不同配置构建了所有不同的二进制文件,并上传到 packages 仓库后,新版本和对包的更改可以被认为是“正确的”,并晋升(复制)到 products 仓库。

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

注意

本教程仅模拟开发流程。在生产系统中,还会有其他仓库和晋升,例如用于 QA 团队的 testing 仓库,以及供最终用户使用的最终 release 仓库,这样包就可以随着通过验证从 develop 晋升到 testing 再到 release。阅读更多关于晋升的内容,请参见包晋升

让我们开始教程吧,进入下一节进行项目设置。