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

Невозможно автоматически обновить пакет 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 до последней версии во время сборки?

4b9b3361

Ответ 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="&lt;dependencies&gt;"/>
     <WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="&lt;dependency id=&quot;%(PackageReference.Identity)&quot; version=&quot;%(PackageReference.Version)&quot; /&gt;" />
     <WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="&lt;/dependencies &gt;"/>
     <Exec Command="powershell -NonInteractive -executionpolicy Unrestricted -command &quot;$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')&quot;"/>
     <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.