CI 如何影响语义版本控制?

Posted

技术标签:

【中文标题】CI 如何影响语义版本控制?【英文标题】:How does CI affect semantic versioning? 【发布时间】:2020-04-22 14:48:46 【问题描述】:

在Countinous Delivery book 中,建议将所有内容(包括 CI 脚本)保留在版本控制中。实际上,像 gitlab CI 这样的当前 CI 系统已经遵循这个经验法则,并在同一代码库中搜索 CI 脚本。 另一方面,只要代码库发生变化,我们就会对其进行版本控制(它是构建的工件)。我们为此遵循语义版本控制;增加 patch 字段用于错误修复,minor 用于非破坏性功能,等等... 我们通过在 CI 中检查版本来确保版本在提交之间递增。 但是,有些提交只会更改 CI 脚本;即添加分析作业、优化另一个作业等。 在这个冗长无聊的序言之后,我的问题是,对 CI 的此类更改进行版本控制的最佳实践是什么?因为它可能会影响最终构建的工件(例如,更改 CI 作业中的构建标志以进行优化或...)。 在这种情况下可以增加版本吗?

【问题讨论】:

版本化 git repo 的内容是多余的。问问自己,您使用 SemVer 进行版本化的目的是什么?它是您产品的包输出还是只是 API?是否有从这个代码库生成的多个 API 包? 你是说每次提交到你的 git repo 都会改变你包的 semver 吗?我想确保我正确理解了您的前言和问题。 @g7p,不,我是说 git 已经为此目的提供了提交哈希。将 SemVer 标签应用于 git 哈希可以说是可以的,但是您使用该标签进行的版本控制到底是什么?存储库中的 git 哈希或其他一些随机内容?如果标签包含 SemVer 字符串,还包括对该字符串适用的 API 或包目标的引用,这很好。请记住,它是 repo 的一个版本(git hash),它为版本化产品的生产提供了机器和素材。将 git 哈希添加到输出端的构建元标记中,总是正确的。 【参考方案1】:

Git 是一个版本控制系统。每次您向 git repo 提交内容时,它都会使用表示该版本的 repo 的内容哈希值标记 repo 的内容。 git repo 内容的语义版本控制是多余且毫无意义的。 SemVer 的重点是为生产者提供一种向消费者传达风险的方法。换句话说,语义版本控制旨在用于构建产品标签,而不是用于生成构建的位。

如果您尝试将 SemVer 语义应用于存储库,则您标记的是产品输入,而不是产品本身。在执行所有单元/回归/验收测试之前,您不应应用 SemVer 字符串。您还能如何确定代码/构建脚本更改是否破坏了任何内容?


预构建标签不起作用。能够连续两次复制完全相同的输出的构建过程是极其罕见的,如果有的话。在世界上拥有多个 API/包并附加相同的 SemVer 字符串是违反最佳实践的。如果您标记 repo 内容,然后将该标签转发到构建输出,则每次运行构建时,都会生成具有不同内容的包。总会有一些风险,即不止一种产出会被释放到野外。许多有安全意识的消费者密切关注他们消费的包裹的内容哈希。检测到特定生产者已发布多个包哈希值而没有增加版本号,将引发危险信号并导致对该生产者内部流程的不信任。


这是一个非常深奥的话题,在这里无法完全涵盖。其他需要考虑的问题是操作系统/编译器/工具链更新。您还会将整个构建工具链提交到同一个仓库吗?这是一种站不住脚的方法,充满了我无法完全列举的危险,如果不花几个月的时间来记录它们。

最佳实践:

使用能够明确说明开发人员意图的语义提交消息。 在包装/贴标签之前验证构建输出。 对于非预发布出版物,始终让人类参与其中。

为了清楚起见,让我补充一点,在存储库中维护构建脚本和工具清单被认为是最佳实践。它将您的脚本和工具的版本与您正在构建的代码的版本联系起来。 Git 通过创建一个包含整个 repo 状态的提交哈希(如果我没记错的话,减去标签)确实很好地完成了这项工作。但最终会出现问题,旧版本的工具会从文件共享/提要中撤出,尤其是在发现它们会造成安全漏洞时。

有时会出现这样的情况,即您的产品的旧版本无法使用较早的构建过程进行复制。签入二进制文件通常被宣传为解决此问题,但我认为这是一种反模式。您将来可能永远不会想要或需要的二进制文件不应存储在您的存储库中。它只会堵塞一切。

考虑使用备用存档系统。维护旧工具的单独存档并不是一个坏主意,但您经常会发现,如果不对构建机器进行重大重新配置并重新引入众所周知的安全风险,您就无法在当前硬件和操作系统上运行它们.您应该经常根据最新的已知风险和权衡必须做一些额外工作的成本来修剪这样的存档,如果/当那一天到来时,您需要从一个非常旧的提交哈希构建。

最好维护一个最新的构建系统,它可以构建你所有的代码库,回到它历史上的某个合理点。这一点通常是您愿意通过错误修复积极支持的最古老的部分。

【讨论】:

我曾经和一个人一起工作,他指出我们应该首先构建我们的工具,然后使用它们来构建我们的产品依赖项和输出。他是对的,但这在经济上是不可行的。在他的世界里,你只需要一个整数来碰撞每个构建。 SemVer 旨在为一个我们不构建用于生产我们产品的所有东西的世界。 +1 表示“对于非预发行出版物,始终让人类参与其中。” - 又名。对于任何向消费者发出的东西,总是使用人工门。自动化可以而且应该用来帮助人类,但脚本不应该是唯一的仲裁者。 向消费者发布预发布版本是完全可以接受的。根据SemVer,对于任何预发布版本,所有关于版本三元组语义的赌注都已失败。【参考方案2】:

这些天我正在使用与 SemVer 兼容的 Headver; https://github.com/line/HeadVer 感觉很开心。

由于自动增量版本控制,它对 CI 非常友好,但仍然能够通过允许手动定义主要版本号来宣布何时发生重大更改。

【讨论】:

以上是关于CI 如何影响语义版本控制?的主要内容,如果未能解决你的问题,请参考以下文章

关于使用 CI / CD 管道的语义版本控制发布的一般问题

sh travis-ci或任何其他ci的自动语义版本控制

如何根据语义版本控制自动增加 Web 应用程序版本?

使用 TeamCity 合并语义版本控制的最佳实践是啥

如何从 TFS CI 任务的源代码中获取版本(major.minor.patch)号

从基于日期的版本控制切换到语义版本控制后,如何防止 NuGet 升级包?