Подтвердить что ты не робот

Как обеспечить такую ​​же версию пакета nuget для нескольких проектов С#?

У меня есть куча небольших проектов на С#, которые используют пару пакетов NuGet. Я хотел бы иметь возможность обновлять версию данного пакета автоматически. Более того: я хотел бы быть предупрежден, если проект использует другую версию из других.

Как я могу применить такую ​​же зависимость версии для нескольких проектов С#?

4b9b3361

Ответ 1

Я считаю, что нашел установку, которая решает эту (и многие другие) проблему (и).

Я только что понял, что можно использовать папку в качестве источника nuget. Вот что я сделал:

root
  + localnuget
      + Newtonsoft.Json.6.0.1.nupkg
  + nuget.config
  + packages
      + Newtonsoft.Json.6.0.1
  + src
      + project1

nuget.config выглядит так:

<configuration>
  <config>
    <add key="repositoryPath" value="packages" />
  </config>
  <packageSources>
    <add key="local source" value="localnuget">
  </packageSources>
</configuration>

Вы можете добавить сервер Nuget в nuget.config, чтобы получить доступ к обновлениям или новым зависимостям во время разработки:

<add key="nuget.org" value="https://www.nuget.org/api/v2/" /> 

Как только вы закончите, вы можете скопировать .nupkg из кэша в папку localnuget чтобы проверить это.

Есть 3 вещи, которые я люблю в этой настройке:

  1. Теперь я могу использовать функции Nuget, такие как добавление реквизита и целей. Если у вас есть генератор кода (например, protobuf или Thrift), это становится бесценным.

  2. Это (частично) решает проблему того, что Visual Studio не копирует все библиотеки DLL, потому что вам нужно указать зависимости в файле .nuspec а .nuspec автоматически загружает косвенные зависимости.

  3. Раньше у меня был один файл решения для всех проектов, поэтому обновление пакетов nuget было проще. Я еще не пробовал, но думаю, что решил эту проблему тоже. У меня могут быть пакеты nuget для проекта, который я хочу экспортировать из данного решения.

Ответ 2

Спасибо, что спросили об этом, поэтому я не одинок. Я потратил немало времени на то, чтобы все проекты в моем решении использовали одну и ту же версию пакета. Пользовательский интерфейс NuGet (а также интерфейс командной строки) также способствует созданию разных версий среди проектов в рамках решения. В частности, когда к проекту добавляется новый проект, а в новый проект добавляется пакет X, NuGet слишком жадный, чтобы загрузить последнюю версию с nuget.org, вместо того, чтобы сначала использовать локальную версию, что было бы лучше по умолчанию.

Я полностью согласен с вами, что NuGet должен предупредить, если в решении используются разные версии пакета. И это должно помочь избежать этого и исправить такой лабиринт версии.

Лучшее, что я нашел сейчас, это перечислить все файлы packages.config в папке решения (ваши проекты-root), которые выглядят как

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net451" />
  ...
</packages>

затем сортировка xml-узлов по id и анализ номеров версий.

Если какой-либо пакет происходит с разными номерами версий, делая их одинаковыми, а затем запускает команду NuGet

Update-Package -ProjectName 'acme.lab.project' -Reinstall

должен исправить неправильные версии пакетов.

(Так как NuGet является открытым исходным кодом, конечно, было бы здорово заполучить наши руки и реализовать недостающую утилиту предотвращения конфликта версий.)

Ответ 3

Поскольку я не нашел другого способа обеспечить это, я написал модульное тестирование, которое не будет выполнено, если будут найдены разные версии пакетов в любом файле package.config в любой подпапке. Поскольку это может быть полезно для других, вы найдете код ниже. Вам нужно будет адаптировать разрешение корневой папки, сделанное в GetBackendDirectoryPath().

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;

using NUnit.Framework;

namespace Base.Test.Unit
{
    [TestFixture]
    public class NugetTest
    {
        private const string PACKAGES_CONFIG_FILE_NAME = "packages.config";
        private const string BACKEND_DIRECTORY_NAME = "DeviceCloud/";

        private const string PACKAGES_NODE_NAME = "packages";
        private const string PACKAGE_ID_ATTRIBUTE_NAME = "id";
        private const string PACKAGE_VERSION_ATTRIBUTE_NAME = "version";

        /// <summary>
        /// Tests that all referenced nuget packages have the same version by doing:
        /// - Get all packages.config files contained in the backend
        /// - Retrieve the id and version of all packages
        /// - Fail this test if any referenced package has referenced to more than one version accross projects
        /// - Output a message mentioning the different versions for each package 
        /// </summary>
        [Test]
        public void EnforceCoherentReferences()
        {
            // Act
            IDictionary<string, ICollection<PackageVersionItem>> packageVersionsById = new Dictionary<string, ICollection<PackageVersionItem>>();
            foreach (string packagesConfigFilePath in GetAllPackagesConfigFilePaths())
            {
                var doc = new XmlDocument();
                doc.Load(packagesConfigFilePath);

                XmlNode packagesNode = doc.SelectSingleNode(PACKAGES_NODE_NAME);
                if (packagesNode != null && packagesNode.HasChildNodes)
                {
                    foreach (var packageNode in packagesNode.ChildNodes.Cast<XmlNode>())
                    {
                        if (packageNode.Attributes == null)
                        {
                            continue;
                        }

                        string packageId = packageNode.Attributes[PACKAGE_ID_ATTRIBUTE_NAME].Value;
                        string packageVersion = packageNode.Attributes[PACKAGE_VERSION_ATTRIBUTE_NAME].Value;

                        if (!packageVersionsById.TryGetValue(packageId, out ICollection<PackageVersionItem> packageVersions))
                        {
                            packageVersions = new List<PackageVersionItem>();
                            packageVersionsById.Add(packageId, packageVersions);
                        }

                        //if (!packageVersions.Contains(packageVersion))
                        if(!packageVersions.Any(o=>o.Version.Equals(packageVersion)))
                        {
                            packageVersions.Add(new PackageVersionItem()
                            {
                                SourceFile = packagesConfigFilePath,
                                Version = packageVersion
                            });
                        }

                        if (packageVersions.Count > 1)
                        {
                            //breakpoint to examine package source
                        }
                    }
                }
            }

            List<KeyValuePair<string, ICollection<PackageVersionItem>>> packagesWithIncoherentVersions = packageVersionsById.Where(kv => kv.Value.Count > 1).ToList();

            // Assert
            string errorMessage = string.Empty;
            if (packagesWithIncoherentVersions.Any())
            {
                errorMessage = $"Some referenced packages have incoherent versions. Please fix them by adapting the nuget reference:{Environment.NewLine}";
                foreach (var packagesWithIncoherentVersion in packagesWithIncoherentVersions)
                {
                    string packageName = packagesWithIncoherentVersion.Key;
                    string packageVersions = string.Join("\n  ", packagesWithIncoherentVersion.Value);
                    errorMessage += $"{packageName}:\n  {packageVersions}\n\n";
                }
            }

            Assert.IsTrue(packagesWithIncoherentVersions.Count == 0,errorMessage);
            //Assert.IsEmpty(packagesWithIncoherentVersions, errorMessage);
        }

        private static IEnumerable<string> GetAllPackagesConfigFilePaths()
        {
            return Directory.GetFiles(GetBackendDirectoryPath(), PACKAGES_CONFIG_FILE_NAME, SearchOption.AllDirectories)
                .Where(o=>!o.Contains(".nuget"));
        }

        private static string GetBackendDirectoryPath()
        {
            string codeBase = Assembly.GetExecutingAssembly().CodeBase;
            var uri = new UriBuilder(codeBase);
            string path = Uri.UnescapeDataString(uri.Path);
            return Path.GetDirectoryName(path.Substring(0, path.IndexOf(BACKEND_DIRECTORY_NAME, StringComparison.Ordinal) + BACKEND_DIRECTORY_NAME.Length));
        }

    }

    public class PackageVersionItem
    {
        public string SourceFile { get; set; }
        public string Version { get; set; }

        public override string ToString()
        {
            return $"{Version} in {SourceFile}";
        }
    }
}

Ответ 4

Я не знаю, как это сделать, но я нашел вкладку "Консолидация", чтобы помочь. На этой вкладке отображается пакет, который отличается от версии. Оттуда вы можете выбрать проекты и использовать кнопку установки, чтобы установить для них ту же версию пакета.

введите описание изображения здесь