4

I like to create a NuGet package with a .props file in it.

The .props file has following content:

<Project>
  <ItemGroup>
    <PackageReference Include="GitVersion.Tool" Version="[5.1.1]" PrivateAssets="All" ExcludeAssets="All" />
    <PackageReference Include="dotnet-sonarscanner" Version="[4.7.1]" PrivateAssets="All" ExcludeAssets="All" />
    <PackageReference Include="ReportGenerator" Version="[4.4.6]" PrivateAssets="All" ExcludeAssets="All" />
    <PackageReference Include="NuGet.CommandLine" Version="[5.4.0]" PrivateAssets="All" ExcludeAssets="All" />
    <PackageReference Include="CycloneDX" Version="[0.9.0]" PrivateAssets="All" ExcludeAssets="All" />
    <PackageReference Include="trx2junit" Version="[1.3.0]" PrivateAssets="All" ExcludeAssets="All" />
  </ItemGroup>

  <ItemGroup>
    <NukeSpecificationFiles Include="**\*.json" Exclude="bin\**;obj\**" />
    <NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />
    <None Remove="*.csproj.DotSettings;*.ref.*.txt" />

    <!-- Common build related files -->
    <None Include="..\build.ps1" />
    <None Include="..\build.sh" />

    <None Include="..\.nuke" LinkBase="config" />
    <None Include="..\global.json" LinkBase="config" Condition="Exists('..\global.json')" />
    <None Include="..\nuget.config" LinkBase="config" Condition="Exists('..\nuget.config')" />
    <None Include="..\GitVersion.yml" LinkBase="config" Condition="Exists('..\GitVersion.yml')" />
    <None Include="..\CODEOWNERS" LinkBase="config" Condition="Exists('..\CODEOWNERS')" />

    <None Include="..\.teamcity\settings.kts" LinkBase="ci" Condition="Exists('..\.teamcity\settings.kts')" />
    <None Include="..\.github\workflows\*.yml" LinkBase="ci" />
    <None Include="..\azure-pipelines.yml" LinkBase="ci" Condition="Exists('..\azure-pipelines.yml')" />
    <None Include="..\Jenkinsfile" LinkBase="ci" Condition="Exists('..\Jenkinsfile')" />
    <None Include="..\appveyor.yml" LinkBase="ci" Condition="Exists('..\appveyor.yml')" />
    <None Include="..\.gitlab-ci.yml" LinkBase="ci" Condition="Exists('..\.gitlab-ci.yml')" />
    <None Include="..\.travis.yml" LinkBase="ci" Condition="Exists('..\.travis.yml')" />
  </ItemGroup>
</Project>

After packing and pushing the nuget to the feed, the nuget gets consumed by other projects, which works.

The consuming project interprets the .props and also all conditional files and also the PackageReferences gets added.

When I build to project with VS2019 then all works fine. But when I build with dotnet build the PackageReferences from .props file don't get added.

I checked the project.assets.json and they are different. The VS2019 adds the tools to the asset file:

...
"CycloneDX/0.9.0": {
  "type": "package"
},
"dotnet-sonarscanner/4.7.1": {
  "type": "package"
},
"GitVersion.Tool/5.1.1": {
  "type": "package"
},
...

but dotnet build doesn't add it.

Is there a property or flag I need to add to the dotnet restore command? Or do you have an idea why the behavoir is different.

My goals is that the consuming projects have the dotnet tools as private assets in their projects.

crip
  • 145
  • 1
  • 8

2 Answers2

1

I found a solution to your problem as I was also struggling with the same issue.

Solution

Provide NuGet packages as Package Reference and consume them transitively. For that, you can set PrivatAssets to None to Include all assets (or dependent on what you exactly want to provide transitively, but compile and runtime should be part of it). Also check Controlling depencency assets for details.

Your .csproj would contain the following declarations:

<Project Sdk="Microsoft.NET.Sdk">
  
  <ItemGroup>
<PackageReference Include="GitVersion.Tool" Version="[5.1.1]" PrivateAssets="None" />
<PackageReference Include="dotnet-sonarscanner" Version="[4.7.1]" PrivateAssets="None" />
<PackageReference Include="ReportGenerator" Version="[4.4.6]" PrivateAssets="None" />
<PackageReference Include="NuGet.CommandLine" Version="[5.4.0]" PrivateAssets="None" />
<PackageReference Include="CycloneDX" Version="[0.9.0]" PrivateAssets="None" />
<PackageReference Include="trx2junit" Version="[1.3.0]" PrivateAssets="None" />
  </ItemGroup>

  <ItemGroup>
    <None Include="build\YourPackage.props" Pack="true" PackagePath="build\" />
  </ItemGroup>
</Project>

And your corresponding YourPackage.props looks like before, but without the references.

Your consuming projects can then simply reference YourPackage (and optionally control what should be consumed at all):

<PackageReference Include="YourPackage" Version="x.y" /> 

Elaboration on Original Problem

I also wanted to import PackageReferences via NuGet packages and it worked fine when building locally in Visual Studio. However, the package references were not imported on our build servers where we are running dotnet build (dotnet build did not work locally, either).

After some research, I stumbled over this Guidance for the content of MSBuild props and targets, specifically:

There are a few things that must not be done in packages' .props and .targets, such as not specifying properties and items that affect restore, as those will be automatically excluded.

  • ...
  • Some examples of items that must not be added or updated: PackageReference, PackageVersion, PackageDownload, etc

This somehow makes sense, since the NuGet providing the .props/.targets is imported with restore and provides itself references that are to be handled in the exact same step. I doubt that dotnet restore can handle that at all. (It also epxlains, whz I need to build twice in Visual Studio to make it work at all.)

Ildrial
  • 344
  • 3
  • 10
0

No there is not a flag. You need to use dotnet pack instead.

coderpatros
  • 464
  • 5
  • 9