使用 GitVersion 进行多个相关的 NuGet 库版本控制。 MonoRepo 还是 MultiRepo?

Posted

技术标签:

【中文标题】使用 GitVersion 进行多个相关的 NuGet 库版本控制。 MonoRepo 还是 MultiRepo?【英文标题】:Multiple related NuGet libraries versioning with GitVersion. MonoRepo or MultiRepo? 【发布时间】:2018-08-23 08:58:30 【问题描述】:

需要以下建议:

在我的公司中,我正在开发供外部利益相关者使用的 .NET 类库,并在利益相关者可以访问的私有 NuGet 源上共享它们。

这些库依赖于一个核心库,如下所示。目前,我在一个 VS 解决方案中维护这些库,显然是在一个 Git 存储库中。我正在关注 SemVer 对它们进行版本控制。

CoreLibrary
CoreLibrary.Extension1 (references CoreLibrary as project reference)
CoreLibrary.Extension2 (references CoreLibrary as project reference)
...
There might be more of these extension libraries in the near future

到目前为止,我一直在 Visual Studio 中手动对它们进行版本控制(每当我需要升级版本时,在 AssemblyInfo.cs 中手动设置正确的值),并在每个项目中使用批处理文件来打包并将特定库推送到NuGet。

但现在我最近开始研究 VSTS,我的下一个任务是尽可能地自动化构建和发布,包括自动版本控制。我偶然发现了 GitVersion,我认为它对最后一部分有很大帮助。

但是,这里是但是。如果我理解正确,GitVersion 在存储库级别运行,因此由 GitVersion 计算的给定 semver 版本适用于存储库中的所有程序集/库,对吗?

那么您对这些库的发布和版本控制策略有何建议?

1) 像现在一样将所有内容保存在一个解决方案和存储库中,每当需要发布的一个包(例如 CoreLibrary.Extension1)发生更改时,这也会为所有其他库生成一个 NuGet 包。因此,如果所有包都在 1.0.0 上,并且其中一个有一点小变化,它们都会被撞到 v1.1.0 并且都被打包和推送?

2) 为每个项目创建一个 git repo,并让 GitVersion 分别在每个 repo 上发挥它的魔力。在 Extension 库中通过 NuGet 引用 CoreLibrary。

选项 2 是我认为最简洁的选项,并且具有每个项目处理版本控制和打包的优势,但在维护它们方面可能会大大增加工作量,尤其是考虑到我是这些的唯一开发人员这一事实图书馆。

你有什么想法?在给定上下文的情况下,您会选择哪个选项?我是否错过了其他可能值得考虑的选项?

设置我在自动化构建和发布方面的第一步,因此任何建议都非常受欢迎。

谢谢

【问题讨论】:

我想你很理解这个问题。您应该根据对您来说更重要的内容来选择解决方案。如果这不是矫枉过正,我会选择2)。但是看到你的描述,我认为应该是这样我会选择1)(即使所有程序集都在同一个nuget包中) 我暂时选择了选项1,如果有需要我会重新考虑选项2。感谢您的建议。 【参考方案1】:

我强烈建议不要在这里使用任何 nuget 包。 Nuget 旨在作为一种管理软件项目的第三方依赖项的方式,而不是作为一种管理您定期构建的互连代码的方式。为此,您最好拥有一个存储库、一个 Visual Studio 解决方案和一个您从中构建/部署的构建堆栈。

如果您必须使用 Nuget,只需制作具有单个版本的单个包。

【讨论】:

我根本无法表达我对这种说法有多么不同意。 OP 正在生成供人们使用的库,这些人可能会发现 Nuget 包是使用它们的有用方式。这里唯一的问题是是将它们全部放在一个中还是将它们分开? 确实我需要与其他 .NET 开发人员共享库,所以我不明白为什么我不应该使用 Nuget... @jwdonahue 我是根据在企业级应用程序上“艰难地学习”的经验说的。应用程序开发团队做出了使用 nuget 的错误决定,因为它“有意义”。我们遇到的最大问题是分支/合并。 Nuget 的版本控制(1.1、1.2 等)是严格串行的,但 git 分支是分层的。我们需要做的是剪切一个分支并为我们的主线和发布分支管理单独的 nuget 包。这需要大量的构建脚本来保持这些 nuget 版本同步。公平警告... 如果所有软件都是在一个庞大的、无分支的 repo 中开发的,并且依赖项永远不会通过包工具来调节,那真的会更容易吗?我说不,我拥有世界上最大的源代码集合之一以及将其分解为可管理部分的努力的经验。 Nuget 绝对不是我最喜欢的打包工具,但它是集成到 VS 中的主要打包工具。您的团队将其工作流程弄得一团糟这一事实并不意味着 Nuget 无法胜任这项任务。【参考方案2】:

您必须至少考虑以下两个因素:

    需要努力维护多个存储库/分支和发布流。 当您对一个或一小部分库进行小幅或大幅更改时,您的客户需要付出的潜在努力。

当一个项目很小并且只有一个开发人员在处理它时,完全在一个存储库中工作并为所有版本剪切一个包通常会更容易。然而,即使对于单个开发人员,这也不会随着库的数量而很好地扩展。一方面,VS 并不是特别擅长处理大型项目,尽管随着时间的推移,它确实在这方面不断改进。即便如此,还是有一个实际限制,但单个开发人员不太可能在不到几年的时间内达到足够的生产力。

最终,即使是单个开发人员,通常也希望获得足够的成功,从而满足规模化需求,无论是在开发方面,还是在支持客户方面。考虑当重要客户发现扩展程序 1 中的错误时,对扩展程序 2 的一些主要工作进行到一半的影响。现在您需要签出较早的提交,生成快速修复,剪切新包,测试,冲洗/重复,发布,返回到您的存储库的头部,挑选错误修复,然后继续。如果您一直在不同的 repo 中工作,甚至在同一个 repo 中的分支中工作,那么这项任务会更容易组织并在第一次尝试时就做好。

现在,对于您假设每个 Nuget 包需要单独的存储库,或者 GitVersion“在存储库级别运行”,我有一个要点可以选择。通常,您会找到的大多数文档和几乎所有示例都绝对适合单一产品/包/repo 格式,在大多数情况下我可能会建议这样做,但实际上这并不是硬性要求。 GitVersion 在分支级别起作用,您绝对应该为不同分支中的不同库进行开发,如果不是不同的 repo 的话。拥有一个 master 分支来合并所有内容可能也是一个好主意,但 Git 或 GitVersion 甚至不需要 master。您可以在单个 git 存储库中拥有多个 VS 解决方案和项目,并且可以从中生成多个 nuget 包。我并不是说你应该这样做,我是说这并不少见,至少对于不平凡的产品线而言。

在客户方面,这在很大程度上取决于您产品的性质。所有的扩展都是必要的,甚至对每个客户都有用吗?您会为早期采用者制作 alpha/beta 版本吗?您的代码是否在服务器上使用?是否在移动设备上使用?通常,您不希望服务器上运行的任何代码的升级时间过长,因此您应该认真考虑将您的产品线分解为多个独立版本的软件包。客户端过去在这个领域并不那么重要,但在移动设备上,下载时间成为一个主要因素。并非每个人都可以使用无限的免费下载带宽,因此成本可能是一个主要因素。

如果您要制作大量预发布版本,您可能希望将产品线分成单独的包。您仍然可以生成一个包,但最终您需要选择在模块级别发送更新。

一旦您完成了一个 repo/project/package/release-stream 路径,您将快速开发所需的自动化来帮助维护它。这就像干净的编码实践,刚开始时会有些痛苦,但最终会成为第二天性,并且最终的回报可能是巨大的。请记住,没有任何理由不能让多个 repo 拥有自己的解决方案和项目,并且在父目录上也有一个 VS 解决方案,从而为您提供完全集成的构建。只需将其视为构建系统的层次结构。你只需要学习如何使用.gitignore 文件或 git 子模块(我更喜欢前者,因为后者的工具很弱)。

【讨论】:

感谢您提供非常全面的见解。更详细地说:这些库只是“DTO”库和 API 客户端库,以允许需要与我们的 REST API 交互的外部 .NET 开发人员在开发中抢占先机。 API 的每个子模块都有一个通用 DTO 库和专门的扩展库。除了包含一些逻辑的客户端库外,DTO 库仅包含 POCO 对象,并没有太多的业务逻辑。我会看看你的 .gitignore 建议。再次感谢。

以上是关于使用 GitVersion 进行多个相关的 NuGet 库版本控制。 MonoRepo 还是 MultiRepo?的主要内容,如果未能解决你的问题,请参考以下文章

GitVersion 使用描述符和自动递增版本号进行基于主干的开发

如何在旧代码库上使用 gitversion

如何在ClickOnce 应用中使用 GitVersion

GitVersion:如何通过提交消息回滚 SemVer 编号更改?

GitVersion 配置不递增

GitVersion.yml 文件理解