Невозможно автоматически обновить пакет NuGet до последней версии во время сборки
У нас есть два отдельных .NET-решения:
- Запуск сборки для первого решения дает наш конечный продукт: куча DLL. Эти DLL файлы предоставляются нашим клиентам через NuGet-пакет.
- Второе решение служит решением для тестирования продукта: для него установлен пакет NuGet, он встроен и выполнен - таким образом, он использует наш продукт точно так же, как и наши клиенты.
Задача здесь состоит в том, что должен быть способ, которым наш последний пакет NuGet автоматически устанавливается в решение для тестирования продукта, желательно во время сборки этого тестового решения для продуктов.
На основе идей из аналогичного вопроса я догадался, что настроил решение для тестирования продукта:
- Сначала я включил восстановление пакета NuGet. Это позволяет полностью избавиться от каталога "packages" от VCS, так как пакет с версией, определенной в файле packages.config, будет автоматически загружен NuGet перед сборкой.
- Затем я добавил следующее событие для сборки в Visual Studio:
$(SolutionDir).nuget\nuget update -prerelease $(ProjectDir)packages.config
. Это позволяет мне использовать последнюю версию нашего пакета NuGet во время сборки.
В настоящее время я использую описанный выше сценарий для запуска локальных сборников с использованием Visual Studio и автоматических сборок с использованием TeamCity. Решение, похоже, работает для обоих сценариев с первого взгляда, но на самом деле оно не дает ожидаемого результата: при построении решения для тестирования продукта в каталоге bin
я не получаю последней версии DLL, только последняя версия.
Проблема заключается в том, что хотя команда nuget update
обновляет все, как ожидалось, включая файл packages.config
и .csproj
, их новый контент не собирается сборкой, поэтому - как мне кажется, настройки HintPath из файла .csproj
по-прежнему отражают состояние "перед сборкой", поэтому старые библиотеки DLL копируются в каталог bin
. Я предполагаю, что файл .csproj
обрабатывается только один раз: перед запуском события предварительной сборки и изменения, сделанные событием предварительной сборки, игнорируются до следующей сборки.
Я рассмотрел следующие решения:
- По-видимому, предварительная сборка не является достаточной. Если бы была еще более ранняя точка, я мог бы вставить команду
nuget update
, мое решение, вероятно, сработало бы.
- Я прочитал, что могу переопределить HintPath-s в файле .csproj, указав ReferencePath. Но я сомневаюсь, что я мог бы легко понять правильный путь, или я мог бы установить его достаточно рано, чтобы сборка подхватила его.
- В качестве обходного решения я мог бы запустить сборки дважды: дублировать шаг сборки для решения тестового продукта в TeamCity, и я всегда мог бы построить решение дважды локально в Visual Studio.
Кто-нибудь выяснил, как автоматически обновлять пакет NuGet до последней версии во время сборки?
Ответы
Ответ 1
Взгляните на сообщение в блоге, которое я только что сделал относительно этого процесса. Вместо того, чтобы настраивать контент на сервере, я сделал это, добавив файл Nuget.Targets, который был установлен с помощью опции восстановления пакета Nuget. Красота этого подхода заключается в том, что он выполняется локально и на сервере (чтобы вы могли увидеть любые возможные побочные эффекты, прежде чем нарушать сборку)
Добавлено здесь: http://netitude.bc3tech.net/2014/11/28/auto-update-your-nuget-packages-at-build-time/
Ответ 2
Я думаю, что поставить автоматическое обновление для предварительного построения, это не стиль NuGet. Вы можете понять, что вам нужна эта операция каждый раз, когда вы это делаете. В основном потому, что это может увеличить время сборки. Например, когда вы используете TDD и часто перестраиваете проект и запускаете тесты, вы ожидаете, что это будет сделано быстро. Кроме того, он может обновлять неожиданные пакеты и ломать что-то, после чего вы можете потратить много времени, чтобы найти проблему.
Я предлагаю сделать обновление как отдельный шаг. На TeamCity вы можете использовать шаг NuGet installer
build. Для выполнения обновления просто установите два флажка в нижней части настройки шага:
![enter image description here]()
Кроме того, если вы хотите сохранить результат обновления после успешной сборки и прохождения теста, вы можете добавить более поздний шаг сборки, который фиксирует эти изменения в VCS (например, с помощью cmd или PowerShell).
Когда вы работаете на местном уровне, я лучше всего запускаю пакеты обновлений, прежде чем приступать к работе с проектом. Вы можете использовать Package Manager Console
для этого, с командой Update-Package -IncludePrerelease
.
Ответ 3
В последнем формате пакета nuget с использованием тегов "PackageReference" вы можете использовать следующее простое событие postbuild в вашем csproj для обновления файла nuspec с последними зависимостями.
<Target Name="AfterBuild">
<WriteLinesToFile File="dependencies.xml" Overwrite="true" Lines=""/>
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="<dependencies>"/>
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="<dependency id="%(PackageReference.Identity)" version="%(PackageReference.Version)" />" />
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="</dependencies >"/>
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted -command "$xml = [xml] (Get-Content Project.nuspec); $xml.package.metadata.RemoveChild($xml.package.metadata.dependencies); $dependencies = [xml](Get-Content dependencies.xml); $xml.Package.Metadata.AppendChild($xml.ImportNode($dependencies.Dependencies, $true)); $xml.Save('Project.nuspec')""/>
<Delete Files="dependencies.xml" />
</Target>
Единственным условием для этого является то, что у вас есть файл nuspec с остальными метаданными, упомянутыми в каталоге проекта. Вот пример файла nuspec:
<?xml version="1.0"?>
<package>
<metadata>
<id>Package Id</id>
<version>1.0.0</version>
<authors>Author name</authors>
<owners>Owner name</owners>
<description>Description</description>
<contentFiles>
<files include="**/content.zip" buildAction="None" copyToOutput="true" flatten="false" />
</contentFiles>
<dependencies>
</dependencies>
</metadata>
<files>
<file src="bin\Release\Project.dll" target="lib\net462" />
<file src="bin\Release\Project.pdb" target="lib\net462" />
<file src="bin\Release\file.zip" target="Content" />
</files>
</package>
Ответ 4
Решение MSBuild, которое я понял, заключается в переопределении свойства BuildDependsOn
. Поэтому я создал UpdateNugetPackages.target
, который выглядит так:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
UpdateNugetPackages;
$(BuildDependsOn);
</BuildDependsOn>
<UpdateCommand>"$(SolutionDir)pathToYourNugetExe.exe" update "$(SolutionDir)NameOfYourSolution.sln"</UpdateCommand>
</PropertyGroup>
<Target Name="UpdateNugetPackages">
<Exec Command="$(UpdateCommand)"></Exec>
</Target>
</Project>
UpdateCommand
определяет, где и с каким аргументом вызывается nuget.exe
. Не стесняйтесь принимать это для своих нужд.
Эта ссылка будет указана в вашем файле .csproj
. Проще всего:
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- After the initial decleration of the BuildDependsOn-Property. -->
<Import Project="UpdateNugetPackages.target" Condition="Exists('UpdateNugetPackages.target')" />
Имейте в виду, что порядок импорта имеет значение. Вам нужно импортировать целевой файл (UpdateNugetPackages.targets
), переопределяя (или фактически украшая) свойство BuildDependsOn
, после целевого файла Microsoft.Common.targets
, который его определяет. В противном случае свойство будет переопределено и удалит ваши изменения, так как начальное определение в Microsoft.Common.targets
не содержит никакого существующего значения в BuildDependsOn
. Microsoft.Common.targets
импортируется Microsoft.CSharp.targets
для проекта С#. Таким образом, ваш импорт должен после импортировать Microsoft.CSharp.targets
.