产品流水线

产品流水线 回应了一个更具挑战性的问题:我的“产品”能否使用新版本的包正确构建?以及这些包及其依赖项?这才是真正的“持续集成”部分,其中不同包中的更改会针对组织的重要产品进行实际测试,以检查集成是否干净或是否中断。

让我们继续上面的例子,如果现在我们有一个新的 ai/1.1.0 包,它会破坏现有的 game/1.0 和/或 mapviewer/1.0 应用程序吗?是否有必要从源代码重新构建一些直接或间接依赖于 ai 包的现有包?在本教程中,我们使用 game/1.0mapviewer/1.0 作为我们的“产品”,但这个概念稍后会进一步解释,特别是为什么从“产品”的角度思考很重要,而不是试图在 CI 中自上而下地明确建模依赖关系。

这个例子中,产品流水线 的本质在于,上传到 products 仓库的新版本 ai/1.1.0 会自动落入有效的版本范围,并且我们的版本控制方法意味着这样的次要版本升级需要从源代码构建其消费者,在本例中是 engine/1.0game/1.0,并且按照特定的顺序进行,而所有其他包将保持不变。知道哪些包需要从源代码构建以及按照什么顺序,并执行该构建以检查组织的主要产品是否在新依赖版本下仍能正常工作,这是产品流水线的职责。

什么是产品

产品 是组织(公司、团队、项目)作为最终结果交付的主要软件构件,并为这些构件的用户提供价值。在此示例中,我们将 game/1.0mapviewer/1.0 视为“产品”。请注意,可以将同一包的不同版本定义为产品,例如,如果我们需要为不同客户维护不同版本的 game,我们可以将 game/1.0game/2.3 以及不同版本的 mapviewer 作为产品。

“产品”方法除了关注业务价值的优点外,还有一个非常重要的优点:它避免了在 CI 层建模依赖图。一种常见的尝试是建模反向依赖模型,即在 CI 级别表示给定包的依赖项或消费者。在我们的示例中,如果我们为构建 ai 包配置了一个作业,那么我们可以在 ai 作业触发后,为 engine 包配置另一个作业,以某种方式在 CI 系统中配置这种拓扑结构。

但这种方法完全无法扩展,并且有非常重要的局限性

  • 上面的例子相对简单,但在实践中,依赖图可能包含更多包,甚至数百个,这使得在 CI 中定义包之间的所有依赖关系非常繁琐且容易出错

  • 依赖关系随时间演变,会使用新版本,一些依赖被移除,并添加新的依赖。在 CI 级别建模的简单的仓库关系可能会导致非常低效、缓慢且耗时的 CI,甚至是一个脆弱的、因某些依赖项更改而持续中断的 CI。

  • 依赖图下游发生的组合性质,其中一个相对稳定的顶层依赖项,例如 mathlib/1.0 可能会被多个消费者使用,例如 ai/1.0ai/1.1ai/1.2,而这些消费者又可能被多个不同版本的 engine 等等使用。在许多情况下,只构建消费者最新版本是不够的,而构建所有版本将是极其昂贵的。

  • “反向”依赖模型,即询问给定包的“依赖者”是谁,在实践中极具挑战性,尤其是在像 Conan 这样的去中心化方法中,包可以存储在不同的仓库中,包括不同的服务器,并且没有一个包含所有包及其关系的中央数据库。此外,“反向”依赖模型与直接依赖模型类似,是条件性的。由于依赖项可以基于任何配置(settings、options)进行条件判断,反向关系也受相同逻辑的制约,并且这种逻辑也随着每个新修订和版本的发布而演变和变化。

在 C 和 C++ 项目中,“产品”流水线比其他语言中更必要和关键,因为其编译模型中头文件的文本包含会成为消费者的二进制构件的一部分,并且由于原生的构件链接模型。

构建中间包的新二进制文件

一个常见的问题是,当消费者包针对新的依赖版本进行构建时,它的版本应该是什么。明确地说,在我们的示例中,我们已经定义了需要重新构建 engine/1.0 包,因为它现在依赖于新的 ai/1.1.0 版本

  • 我们应该创建一个新的 engine/1.1 版本来针对新的 ai/1.1.0 进行构建吗?

  • 还是应该保持 engine/1.0 版本?

答案在于二进制模型以及依赖项如何影响 package_id。Conan 有一个二进制模型,它考虑了依赖项的版本、修订和 package_id,以及不同的包类型(package_type 属性)。

建议保持包版本与源代码对齐。如果 engine/1.0 是从其源代码仓库的特定提交/标签构建的,并且该仓库的源代码根本没有改变,那么拥有一个偏离源代码版本的、不断变化的包版本会非常令人困惑。使用 Conan 二进制模型,我们将得到 engine/1.0 的 2 个不同的二进制文件,具有 2 个不同的 package_id。一个二进制文件将针对 ai/1.0 版本构建,另一个二进制文件将针对 ai/1.1.0 构建,类似于

$ conan list engine:* -r=develop
engine/1.0
    revisions
      fba6659c9dd04a4bbdc7a375f22143cb (2024-08-22 09:46:24 UTC)
        packages
          2c5842e5aa3ed21b74ed7d8a0a637eb89068916e
            info
              settings
                ...
              requires
                ai/1.0.Z
                graphics/1.0.Z
                mathlib/1.0.Z
          de738ff5d09f0359b81da17c58256c619814a765
            info
              settings
                ...
              requires
                ai/1.1.Z
                graphics/1.0.Z
                mathlib/1.0.Z

让我们看看产品流水线如何使用新的依赖版本构建 engine/1.0game/1.0 的新二进制文件。在接下来的章节中,我们将以增量方式介绍产品流水线,就像包流水线一样。