语义版本控制和依赖更改

Posted

技术标签:

【中文标题】语义版本控制和依赖更改【英文标题】:Semantic Versioning and Dependency Changes 【发布时间】:2019-04-29 13:33:49 【问题描述】:

一些背景:我正在一个团队工作,该团队生产 6 个不同的 NuGet 包,它们直接、有时间接地相互依赖。简单地说,我们可能遇到像p0 < p1 < p2 这样的情况,其中包p0 依赖于p1,而p1 又依赖于p2。我们正在尝试关注Semantic Versioning 来获取这些软件包,但不太确定当p1p2 发生变化时如何处理p0 的版本。

下面是一些具体的例子:

p1 进行了重大更改(例如 0.0.01.0.0)。我们想要发布一个依赖于1.0.0p0 版本。这应该是p0 的主要版本还是次要版本? p1 做了一个小改动 (0.0.00.1.0)。这是否应该为p0 带来次要版本/补丁版本?

更重要的是,

对于依赖版本更改应如何影响包版本更改是否有任何标准/共识?

【问题讨论】:

如果所有的包都相互依赖,为什么不把它们都放到一个包中呢?将它们全部作为单独的库进行维护是什么情况? 将逻辑解耦到单独的库中有很多原因:1)您可以独立使用它们(例如,如果有些是 .NET Standard 1.3,有些是 .NET Standard 2.0,这很有用),2)底层逻辑清晰分离。 【参考方案1】:

绝不暗示@BradleyDotNET 的出色答案是不够的。我只是想补充一下我对此的看法。

p1 进行了重大更改(例如 0.0.0 → 1.0.0)。我们想发布一个依赖于 1.0.0 的 p0 版本。这应该是 p0 的主要版本还是次要版本?

是的,您正在向 p0 的用户引入一项重大更改。

p1 做了一个小的改动(0.0.0 → 0.1.0)。这是否应该为 p0 带来次要/补丁版本的提升?

如果 p1 的附加接口暴露在 p0 接口中,则为次要。如果依赖关系在实现层,则打补丁。这里真正的问题是你为什么要改变这种依赖关系?如果是给 p0 公共表面添加一个接口,那么它是 p0 的一个小凹凸,否则它是一个补丁级别的凹凸。

这里要考虑的另一件事是您将应用版本号的确切内容。包、库和接口都是不同的东西,它们都可以是独立的版本。正如 BradleyDotNET 指出的那样,一些包包含独立版本化工件的集合。尽管经常重新打包,您可能需要考虑修改您的策略,以便您的接口可以有稳定的版本。

【讨论】:

【参考方案2】:

语义版本控制是关于更改对库的用户意味着什么。因此,如果p1 中的更改不会导致p0 中的重大更改,那么我不明白为什么它需要p0 中的主要版本更新。

基本上,使用任何版本的依赖库(请记住,您的用户也可以根据您的依赖规则使用不同的版本覆盖它们!),您的版本控制应该只反映会影响您的用户的内容。

前面的警告、基于意见的内容

在我看来,如果您直接使用传递依赖项(即,使用p1,但仅将p0 作为依赖项列出)作为库的客户端,则存在相当多的“警告购买者”。当你有很多很多层的依赖项(就像在大多数 NPM 包中一样)时,这会增加一倍。我不希望这些库的作者跟踪所有传递依赖项的所有版本更改,所以我知道要检查。

【讨论】:

如果用户同时使用p0p1,但只将p0 列为依赖项怎么办?他们期望升级到p0 的新次要版本不会破坏他们,但它确实会带来p1 的破坏性变化,这确实会影响他们。答案是不是每个人都应该只编写使用他们在项目中列为依赖项的包的代码,而不是直接在自己的代码中使用传递依赖项?这对我来说听起来是个好主意,但我从未见过静态代码分析器会在这种情况发生时发出警告,这让我觉得这并不常见。 @Ziv 直接使用传递依赖是一件非常冒险的事情(尽管我们当然会这样做,尤其是使用框架代码时)。 NPM 甚至会警告你这样的事情(通过“对等依赖”的概念)。我只是认为,对别人代码的重大更改并不意味着对您的代码进行重大更改。 原则上我同意,我希望 .NET 生态系统有一个 FXCop 规则(也许有但我不知道)。但是,实际上它在 .NET 中不起作用(原始问题标记为 C# 和 NuGet)。如果我有一个关于 xunit 的参考,它会带来几个包,一个有断言方法,另一个有属性,我不记得输出助手是在哪里定义的。另一个例子是 Microsoft.AspNetCore.App。 Web 应用程序将使用依赖注入、设置/选项、kestrel、MVC 和其他包中的类型,而不直接引用这些包。 顺便说一句,我希望我的信息不会因为争论而出现。我认为这是一个非常有趣的话题,值得讨论。我对原始问题的解释包括我的第一条评论中的场景,所以我认为通过解决它会改进你的答案。 公平地说,Microsoft.AspNetCore.App 是一个“元包”,它被明确设计为“所有这些其他包,作为一个参考”。我没有意识到您认为我应该在答案中对此进行说明,所以我会添加它,而且我不认为您在争论:) @Ziv

以上是关于语义版本控制和依赖更改的主要内容,如果未能解决你的问题,请参考以下文章

语义版本控制对参数名称更改意味着啥?

在 Gradle 中对依赖项使用语义版本控制

npm学习之如何使用语义化版本

数据库模式更改是不是应该增加语义版本控制中的主要版本?

语义版本控制和持续部署

如何下载非依赖工件作为语义版本控制的 buildScript 块的一部分