68

我们使用 Nuget 进行内部开发,以允许我们跨团队共享代码。但是,当一个人正在处理将同时部署在多个 nuget 包中的代码时,我们会遇到问题。例如

A依赖B,B依赖C。

A、B 和 C 将他们的工件推送到 Nuget,这就是我们管理 A、B 和 C 之间依赖关系的方式。我们发现的问题是,如果开发人员想要在 C 中进行更改并快速看到这些更改反映在 A 中,他们必须经过以下过程。

  1. 在 C 中进行更改。
  2. 将更改推送到 git
  3. CI 获取对 C 的更改并构建和部署新的 nuget 包。
  4. 使用 nuget update package 命令进入 B 并更新对 C 的引用。
  5. 将对 packages.config 文件的更改推送到 git
  6. CI 获取对 B 的更改并为 B 构建和部署新的 nuget 包
  7. 现在打开 A 并更改对 B 和 nuget 更新包的引用
  8. 在 A 中进行更改以配合 B 中的更改(以及传递 C)

这似乎非常痛苦,并导致我们的一些开发人员质疑为我们内部开发的代码选择 Nuget。每个人仍然喜欢它来消费外部包。

在内部使用 Nuget 是否有更好的工作流程?

4

4 回答 4

42

在我们公司,我们通过以下设置解决了级联更新问题。首先,我们为 NuGet 存储库和构建服务器进行了以下设置。

  • 有一个内部 NuGet 存储库,其中包含公司所有已发布的包。该存储库只是我们其中一台服务器上的共享目录。
  • 每个开发人员都可以在他们自己的计算机上拥有(但不是必须拥有)一个或多个目录,用作本地 NuGet 包存储库。通过使用用户特定的 NuGet配置,开发人员可以控制 NuGet 在包存储库中搜索以查找包的顺序。

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <packageRestore>
        <add key="enabled" value="True" />
      </packageRestore>
      <packageSources>
        <add key="Dev" value="D:\dev\testpackages" />
        <add key="Company" value="<UNC_ADDRESS_COMPANY_REPOSITORY>" />
        <add key="NuGet official package source" value="https://nuget.org/api/v2/" />
      </packageSources>
      <disabledPackageSources />
      <activePackageSource>
        <add key="All" value="(Aggregate source)" />
      </activePackageSource>
    </configuration>
    
  • 所有解决方案都启用了自动包恢复功能,因此我们不必将包提交到我们的版本控制系统。

  • 开发人员只能控制 4 个版本号中的 3 个,例如,如果版本是,<MAJOR>.<MINOR>.<BUILD>.<REVISION>则开发人员只能更改主要、次要和内部版本号,修订号设置为 0,除非在构建服务器完成的构建中它是内部版本号的构建。这很重要,因为这意味着对于由主要、次要和内部版本号组成的给定版本,构建服务器将始终生成更高的版本号。这再次意味着 NuGet 将更喜欢使用来自公司包存储库的包版本(它只通过构建服务器获取包)。

为了对基础库之一进行更改,有两个可能的过程正在使用。第一个过程是:

  1. 对基础库 (A) 进行更改。如果需要,更新 (A) 的版本。
  2. 运行 MsBuild 脚本以构建二进制文件并创建 (A) 的 NuGet 包
  3. 将新的 NuGet 包复制到本地计算机上的包存储库
  4. 在依赖项目 (B) 中升级到 (A) 的新包,这些包刚刚放置在本地计算机包存储库中(其版本应高于公司范围存储库或 NuGet.org 中可用的版本)
  5. 对 (B) 进行更改。

如果 (A) 需要更多更改,则重复步骤 1,2 和 3,然后从 (B) 的工作目录中删除 (A) 的包。下次运行构建时,NuGet 将寻找 (A) 的特定版本,在本地计算机存储库中找到它并将其拉回。请注意,NuGet 缓存有时可能会阻止此过程,尽管它看起来像 NuGet可能不会缓存来自同一台机器的包(?)。

更改完成后,我们:

  1. 提交对 (A) 的更改。构建服务器将运行集成构建以验证一切正常。
  2. 告诉构建服务器运行发布构建,它会构建二进制文件并将 NuGet 包推送到公司范围的 NuGet 存储库。
  3. 在 (B) 中,升级到 (A) 的最新版本(其版本号应高于测试包,因为测试包的版本应为 abc0,而公司范围存储库中的新构建版本应为 abc where > 0
  4. 提交对 (B) 的更改。等待构建服务器完成集成测试
  5. 告诉构建服务器为 (B) 运行发布构建。

进行开发工作的另一种方法是采取以下步骤

  1. 对基础库 (A) 进行更改。如果需要,更新 (A) 的版本。
  2. 构建二进制文件
  3. 将二进制文件复制到 NuGet 为项目 (B) 解压缩 (A) 包的位置(例如c:\mysource\projectB\packages\ProjectA.1.2.3.4
  4. 对项目 (B) 进行必要的更改

提交过程还是一样,项目(A)需要先提交,项目(B)中对(A)的NuGet引用需要升级。

第一种方法稍微简洁一些,因为此过程还会警告 (A) 的 NuGet 包中是否存在错误(例如忘记添加新程序集),而在第二个过程中,开发人员直到 (A) 的包之后才会知道) 已发布。

于 2013-08-12T04:16:34.030 回答
7

您在这里有两个选择:

  1. 在组织内运行NuGet 库的实例。这是运行 nuget.org 的代码
  2. 获得Artifactory Pro的许可证,它具有内置的 Nuget 支持并充当 Nuget 存储库。

我都使用过,#1 是一个合理的选择,但 NuGet Galley 是为 nuget.org 优化和设计的,而不是内部部署/企业使用,所以像删除包这样的事情很痛苦(需要手动 SQL )。

我想说你应该为 Artifactory Pro 支付(低)许可费——它是一款出色的产品,JFrog 团队非常热衷并开启了这项工作。

您不应该将 nuget.org 用于内部/企业包;nuget.org 是为 3rd 方/开源库设计的,而不是内部构建依赖项。

编辑:就工作流程而言,为什么要将共享代码放入多个包中?如果代码需要共享,则需要放入自己单独的包中。

编辑 2:为了加快开发人员的代码更改工作流程,您可以使用nuget.exe(命令行客户端)并使用命令行可访问的构建,因此您可以针对“开发人员”构建运行。然后在您的“开发人员”构建(与 CI 构建相反)中nuget install B -Source C:\Code\B,当您想要将新更新B的内容作为依赖项拉取并针对它进行构建时,您将 -Source 指定为本地路径(例如);同样适用于C或其他本地新更新的软件包。然后,当ABC都构建良好时,您可以git push全部(以相反的依赖顺序),并让 CI 做它的事情。

但是,如果您必须经常进行这种构建“跳舞”,您还应该质疑您的包分离是否真的合适,因为这表明所有代码都应该放在一个包中,或者可能沿着不同的行拆分到单独的包中。定义良好的包的一个关键特性是它不应该其他包造成连锁反应,如果您有效地使用语义版本控制,当然不会。

编辑 3 marcelo-oliveira 要求的一些澄清:“命令行可访问的构建”是可以完全从命令行进行的构建,而不使用 Visual Studio,通常通过批处理文件。“开发人员构建”是开发人员从她的工作站运行的构建,而不是在 CI 服务器上运行的 CI 构建(两个构建应该基本相同)。

于 2013-08-11T13:09:33.737 回答
2

如果 A、B 和 C 在同一个解决方案下,您可以在单个构建中为它们创建 NuGet 包。

只需确保 using 包具有它所依赖的包的新版本号(假设您的构建不会随机更改它)。

如果 A、B 和 C 有意采用不同的解决方案,例如 A 采用基础架构解决方案,而 B 采用产品解决方案,那么我对您的唯一建议是定义您的 CI 构建在签入时运行,而不是定期运行。


编辑:

另一种选择是在本地构建期间创建推送预发布包(例如版本 1.0.0-alpha)到您的 NuGet 服务器,这样开发人员可以在创建发布版本之前对包进行试验。

于 2014-08-05T22:27:41.953 回答
0

Nuget 专为共享第三方库而设计。我们计划在内部对所有可以在项目之间共享的通用代码使用 Nuget。诸如通用数据层、字符串和其他正则表达式函数、电子邮件组件和其他类似工件之类的东西。

我认为 Nuget 有帮助的唯一方法是,您在团队/项目之间共享的组件、代码或工件是稳定的,并且有自己的发布周期,与您的项目的发布周期不同。对于您的需求,Nuget 是一种矫枉过正。在同一个解决方案中链接所有此类项目可能会有更高的生产力。您的解决方案结构应包括三个项目 A、B 和 C,作为在需要时在内部引用的依赖项目。

于 2015-01-29T06:55:24.490 回答