15

I want to call executable tools like NUnit which I manage via NuGet in MSBuild:

<Target Name="Test">
  <CreateItem Include="$(BuildCompileDirectory)\*.Tests.*dll">
    <Output TaskParameter="Include" ItemName="TestAssemblies" />
  </CreateItem>
  <NUnit
    Assemblies="@(TestAssemblies)"
    ToolPath="$(PackagesDirectory)\NUnit.2.5.10.11092\tools"
    WorkingDirectory="$(BuildCompileDirectory)"
    OutputXmlFile="$(BuildDirectory)\$(SolutionName).Tests.xml" />
</Target>

The problem is that the folder of a NuGet packages is containing the version number of the package. For instance nunit-console.exe is in the folder packages\NUnit.2.5.10.11092\tools. If I update the NUnit package this path will change and I have to update my MSBuild script. That isn't acceptable.

MSBuild doesn't allow Wildcards in directories, so this isn't working:

ToolPath="$(PackagesDirectory)\NUnit.*\tools"

How can I call tools in MSBuild without having to update my build script whenever I update a NuGet package?

Martin Buberl
  • 45,844
  • 25
  • 100
  • 144
  • 2
    In MsBuild 15 you can use `PackageReference` with `GeneratePathProperty="true"`. See https://www.patriksvensson.se/2019/09/how-to-find-a-nuget-package-path-from-msbuild . – Mike Rosoft May 14 '20 at 15:57

2 Answers2

13

You can use MSBuild Transforms to get the relative directory of a specific tool:

<ItemGroup>
  <NunitPackage Include="$(PackagesDirectory)\NUnit.*\tools\nunit-console.exe"/>
</ItemGroup>

<Target Name="Test">
  <CreateItem Include="$(BuildCompileDirectory)\*.Tests.*dll">
    <Output TaskParameter="Include" ItemName="TestAssemblies" />
  </CreateItem>
  <NUnit
    Assemblies="@(TestAssemblies)"
    ToolPath="@(NunitPackage->'%(relativedir)')"
    WorkingDirectory="$(BuildCompileDirectory)"
    OutputXmlFile="$(BuildDirectory)\$(SolutionName).Tests.xml" />
</Target>
Matt Lacey
  • 65,560
  • 11
  • 91
  • 143
Martin Buberl
  • 45,844
  • 25
  • 100
  • 144
2

The comment of Mike Rosoft links to Patrik Svensson his blog post and it helped me as follows:

  • Add GeneratePathProperty="true" to PackageReference of the NuGet package you want to have the location of.
  • Use it as $(PkgPackage_Name) whereby the dots are replaced by an underscore. Note the Pkg prefix.

This example forces Nswag to use the 32 bit dotnet.exe by overwriting the existing NSwagExe_Net60 property. This was necessary on an x86 project.

  <PropertyGroup>
    <NSwagExe_Net60>"$(MSBuildProgramFiles32)\dotnet\dotnet.exe" "$(PkgNSwag_MSBuild)\tools\Net60\dotnet-nswag.dll"</NSwagExe_Net60>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NSwag.MSBuild" Version="13.16.1" GeneratePathProperty="true">
  </ItemGroup>
ofthelit
  • 1,341
  • 14
  • 33