Гарантия той же версии пакетов Nuget
У нас есть фреймворк, который разделен на множество отдельных проектов в одном решении. Теперь я хочу создать пакеты NuGet для каждого отдельного проекта, но гарантирую, что в одном решении может использоваться только одна версия инфраструктуры (возможно, для нескольких проектов).
Например, скажем, фреймворк состоит из двух проектов:
Framework
Framework_1
Framework_2
Теперь при использовании этой структуры один проект может ссылаться Framework_1
, а другой проект ссылается Framework_2
, Я хочу убедиться, что оба пакета имеют одинаковую версию (бонусные баллы, если есть простой одношаговый процесс обновления до более новой версии)
Я думал, что просто определю один пакет Framework уровня решения, от которого строго зависят все остальные пакеты. Проблема в том, что у NuGet нет проблем с простой установкой нескольких версий пакета уровня решения.
В основном я попробовал следующее:
Файл nuspec уровня решения:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>My.Framework</id>
<version>1.0.0</version>
<title>My.Framework</title>
<authors>voo</authors>
<owners>voo</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Some Framework Solution Package</description>
<copyright>Copyright © 2015</copyright>
</metadata>
</package>
И один пакет nuspec для одной части:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>My.Framework.BL</id>
<version>1.0.0</version>
<title>My.Framework.BL</title>
<authors>voo</authors>
<owners>voo</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Business Layer</description>
<copyright>Copyright © 2015</copyright>
<dependencies>
<dependency id="My.Framework" version="[1.0.0]"/>
</dependencies>
</metadata>
</package>
Проблема сейчас в том, если я попытался установить, скажем, другой My.Framework.EF
пакет с версией 1.0.1
и явная зависимость от My.Framework
1.0.1 Visual Studio
просто установить My.Framework
дважды - один раз с версией 1.0.0 и один раз с 1.0.1.
4 ответа
Оказывается, вы можете позвонить Install-Package $package.Id -version <someVersion>
внутри Install.ps1, что приведет к удалению первоначально установленной версии и установке указанной версии.
Несколько упрощенная версия выглядит следующим образом:
param($installPath, $toolsPath, $package, $project)
function GetInstallingVersion() {
$package.Version
}
# Gets the current version of the used framework.
# If no framework is yet installed, we set the framework version
# to the one that's being installed right now.
function GetCurrentFrameworkVersion() {
$solutionPath = Split-Path $dte.Solution.FileName
$fwkVersionFile = "${solutionPath}\framework_version.txt"
if (Test-Path $fwkVersionFile) {
return Get-Content $fwkVersionFile
}
else {
$installingVersion = GetInstallingVersion
$installingVersion > $fwkVersionFile
return $installingVersion
}
}
$currentFwkVersion = GetCurrentFrameworkVersion
$installingVersion = GetInstallingVersion
if ($currentFwkVersion -ne $installingVersion) {
Install-Package $package.Id -version $currentFwkVersion
}
Вы можете ограничить версию вашего пакета, используя следующий синтаксис в вашем packages.config, например:
<package id="jQuery" version="1.9.1" allowedVersions="[1.9.1]" />
Также из оригинальной документации nuget: при создании пакета NuGet вы можете указать зависимости для пакета в файле.nuspec.
<dependency id="ExamplePackage" version="[1,3)" />
В этом примере приемлемы версия 1 и версия 2.9, но не 0.9 или 3.0.
Я полагаю, что вы можете ограничить это одним или несколькими версиями. Здесь вы можете прочитать больше об этом.
Вы можете создать простой модульный тест внутри вашего решения, чтобы предупредить вас, когда у вас возникнут проблемы. Код ниже.
Вам нужно будет install-package NuGet.Core
в вашем модульном тестовом проекте для работы приведенного ниже кода.
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NuGet;
[TestClass]
public class NugetPackagesTest
{
/// <summary>
/// This test method makes sure that we do not install different versions of the same nuget package
/// across the solution. For example this test will fail if one project references EntityFramework
/// version 6.1.3 and another project references version 6.2.0. Having different versions of the same
/// package installed often results in unexpected and hard-to-understand errors.
/// </summary>
[TestMethod]
public void PackagesAccrossProjectsAreOfSameVersion()
{
var dir = GetSolutionRoot();
Debug.Assert(dir != null, nameof(dir) + " != null");
var filePaths = Directory.GetFiles(dir.FullName, "*packages.config", SearchOption.AllDirectories);
var installedPackages = filePaths
.Select(t => new PackageReferenceFile(t))
.SelectMany(t => t.GetPackageReferences().Select(x => new { File = t, Package = x }))
.GroupBy(t => t.Package.Id)
.ToList();
foreach (var package in installedPackages)
{
var versions = package
.Select(t => t.Package.Version.ToNormalizedString())
.Distinct()
.ToList();
var report = package
.Select(t => $"{t.Package.Version} @ {t.File.FullPath}")
.OrderBy(t => t);
Assert.IsTrue(
versions.Count == 1,
$"Multiple versions of package {package.Key} are installed: {string.Join(", ", versions)}.\n" +
$"{string.Join("\n", report)}");
}
}
private static DirectoryInfo GetSolutionRoot()
{
var current = AppDomain.CurrentDomain.BaseDirectory;
var dir = Directory.GetParent(current);
while (dir != null)
{
// TODO: replace with name your solution's folder.
if (dir.Name == "MySolution")
{
dir = dir.Parent;
break;
}
dir = dir.Parent;
}
return dir;
}
}
Я бы вырвал "Пакет NuGet уровня решения", разделил бы ваш фреймворк на компоненты и создал пакет NuGet для каждого компонента. Никто не собирается иметь один единственный проект, который ссылается на ваш пакет NuGet "Framework Wrapper", и код для бизнес-логики, доступа к данным и WCF внутри этого единого проекта.
Тогда вам нужно выяснить, какова на самом деле ваша логика зависимостей, и каковы причины для строгого соблюдения политики той же версии.
Например, скажем, My.Framework.BL зависит от My.Framework.DAL. Таким образом, на данный момент у вас есть только 2 файла Nuspec и 2 пакета NuGet, при этом.nuspec вашего My.Framework.BL выглядит следующим образом:
<dependencies>
<dependency id="My.Framework.DAL" version="1.0.0" />
</dependencies>
И с вашим My.Framework.DAL, не содержащим конкретных зависимостей My.Framework.
Это хорошо, и ваше решение хотеть тесно связать число, связанное с версией, проблематично по нескольким причинам. Первое и самое важное - это то, что если вы обновите My.Framework.DAL, когда в нем будет 0 изменений, это может сбить с толку ваших пользователей, но вам пришлось обновить его, потому что вы изменили My.Framework.BL.
Вы могли бы потратить месяц или даже больше, и вам не пришлось бы обновлять зависимость My.Framework, в зависимости от уровня абстракции вашей платформы и от того, насколько низкоуровневое программирование вы делаете. По моему мнению, необходимость обновлять версии DLL Core Framework, когда фактически нет новых изменений, является НАМНОГО большей проблемой, чем одинаковые номера версий всех библиотек My.Framework. Приветствия.:)
Вот ссылки на документы nuspec.