I am trying to use MSBuild to automatically update package versions based on the branch name. This works for the project itself, but referenced projects (that use the same MSBuild targets) use the default version - meaning that my targets are not running. For example, assume I have the following projects:
ConsoleApp1
ProjectReference: ClassLibrary1
ClassLibrary1
When building the above, I get the following nuspec/nugets:
ConsoleApp1 version 0.0.2-beta00001
dependency id="ClassLibrary1" version="1.0.0"
ClassLibrary version 0.0.2-beta00001
Note that the PackageVersion that is being pulled through is the default for the ProjectReference, while the project itself is building with the discovered package version.
I've tried changing GetTargetPathDependsOn as well as BeforeTargets="GetTargetPath;GetProjectsReferencingProjectJson" (after poking around in the Nuget Pack MSBuild), but they don't seem to be having an effect.
<PropertyGroup>
<BuildDependsOn>
OverridePackageVersion;
$(BuildDependsOn);
</BuildDependsOn>
<GetTargetPathDependsOn>
OverridePackageVersion;
$(GetTargetPathDependsOn);
</GetTargetPathDependsOn>
</PropertyGroup>
<Target Name="OverridePackageVersion"
BeforeTargets="GetTargetPath;GetProjectsReferencingProjectJson"
DependsOnTargets="GetDefaultVersion">
<CreateProperty
Value=""
Condition="'$(AutoPackagePreName)'=='$(ReleaseBranchName)'">
<Output TaskParameter="Value" PropertyName="AutoPackagePreName" />
</CreateProperty>
<CreateProperty
Value="$([System.String]::Format( $(AutoPackagePreNumberFormat), $([MSBuild]::Add($(AutoPackagePreNumber), 0)) ))">
<Output TaskParameter="Value" PropertyName="AutoPackagePreNumber" />
</CreateProperty>
<!-- Final Override -->
<CreateProperty
Value="$(AutoPackageVersion)"
Condition="'$(AutoPackagePreName)'==''">
<Output TaskParameter="Value" PropertyName="PackageVersion" />
</CreateProperty>
<CreateProperty
Value="$(AutoPackageVersion)-$(AutoPackagePreName)$(AutoPackagePreNumber)"
Condition="'$(AutoPackagePreName)'!=''">
<Output TaskParameter="Value" PropertyName="PackageVersion" />
</CreateProperty>
<CreateProperty
Value="$(PackageVersion)"
Condition="'$(UpdateVersion)'=='true'">
<Output TaskParameter="Value" PropertyName="Version" />
</CreateProperty>
<Message Importance="High" Text="Selected package version $(PackageVersion)." />
</Target>
Is this at all possible, or am I going to have to use Powershell in my CI?
The full source is available.
The targets you'd need to run before for the recent NuGet and .NET Core 2.* SDK versions are CollectPackageReferences;PrepareForBuild. To get it working in older versions, I used Restore;_GenerateRestoreProjectSpec in addition but these should no longer be necessary on recent tooling. See my Directory.Builds.targets i'm using to create a public NuGet package.
At the moment, dependency package versions are locked down during restore time and read from the obj\project.assets.json file, this is why the restore-specific targets are used. Note that restore doesn't import props/targets files from NuGet packages so you currently cannot consume versioning logic via a NuGet package containing build assets that work for project-to-project references. See the GitHub issue for it - the plan seems to be to move from reading the assets file to re-evaluating the versions from referenced projects instead of locking them down during restore.
Related
As part of my build process I want to run a dotnet tool before the compile.
I can add this section to my sdk project file:
<ItemGroup>
<PackageDownload Include="MyTool" Version="[1.0.1]" />
</ItemGroup>
Then the tool is downloaded and is available inside:
\Users\me\.nuget\packages\MyTool\1.0.1\tools\netcoreapp3.1\any\
I can then add a prebuild target like this:
<Target Name="PreBuild" BeforeTargets="CoreCompile">
<Exec Command="dotnet C:\Users\me\.nuget\packages\MyTool\1.0.1\tools\netcoreapp3.1\any\MyTool.dll <MyOptions> />
</Target>
This works, but obviously I do not want absolute references to my user profile (or version) in the path.
Is there a way to substitute path with an environment variable?
I have tried adding GeneratePathProperty="true" to the PackageDownload but $(PkgMyTool) is undefined.
I also tried referencing the tool with <PackageReference> but this fails due to SDK incompatibility. My Tool is netcore3.1 and this project is netstandard2.0.
You can use only the macros provided by the framework. You can find them here. Almost all of them are referring to the relative path of your project. I suggest you to copy your tool inside a project folder and you can make use of these macros.
The best solution I had success with thus far is this:
<Target Name="PreBuild" BeforeTargets="CoreCompile">
<Exec Command="dotnet tool update MyTool --tool-path=$(TargetDir)\tools --version=1.0.1" />
<Exec Command="$(TargetDir)\tools\MyTool <MyOptions> />
</Target>
And it DOES save me from the nitty gritty details like \netcoreapp3.1\any but it does not reuse the tool from NuGet cache, meaning it has to be downloaded on every build.
I still hope someone will provide a better answer.
I am building a self-contained .Net Core worker service which I run as a windows service. Now I want to create an installe using Wix, however when I try to harvest all the needed DLL's for installation I get the following error:
An error occurred loading a configuration file: The parameter 'exePath' is invalid.
I've read this post which states the heat.exe might be broken. But I downloaded the tools via NuGet (3.11.2) which should theoretically be fine. My Beforebuild target looks as following:
<Exec Command="dotnet publish ..\Parlando.PVS.PackingSlipService\Parlando.PVS.PackingSlipService.csproj -c $(Configuration) -r win10-x86" />
<ItemGroup>
<LinkerBindInputPaths Include="%(ProjectReference.RootDir)%(ProjectReference.Directory)bin\$(Configuration)\%(ProjectReference.TargetFrameworkIdentifier)\win10-x86\publish" />
</ItemGroup>
<HeatDirectory
DirectoryRefId="INSTALLFOLDER"
OutputFile="$(ProjectDir)\HeatGeneratedFileList.wxs"
Directory="..\Parlando.PVS.PackingSlipService\bin\Release\netcoreapp3.1\win10-x86\publish"
ComponentGroupName="HeatGenerated"
ToolPath="$(WixToolPath)"
AutogenerateGuids="True"
SuppressCom="True"
SuppressRegistry="True"
SuppressFragments="True"
SuppressRootDirectory="True"
NoLogo="true" />
<ItemGroup>
<Compile Include="$(ProjectDir)\HeatGeneratedFileList.wxs" Condition="'%(ProjectReference.IsDotnetSDKProject)' == 'True'" />
</ItemGroup>
This should generate a .wxs file that I reference in the Product.wxs file when installing the service. My product.wxs does so as followed:
<ServiceInstall
Id="ServiceInstaller"
Type="ownProcess"
Name="Parlando.PVS.PackingSlipService"
DisplayName="Parlando.PVS.PackingSlipService"
Description="Service installed by Parlando to create packingslips and invoices."
Start="auto"
Account="LocalSystem"
ErrorControl="normal" />
<ServiceControl
Id="ServiceInstaller"
Start="install"
Stop="both"
Remove="uninstall"
Name="Parlando.PVS.PackingSlipService" />
</Component>
<ComponentRef Id="HeatGenerated" />
How can i use the heat.exe in such a way that I can access the DLL list in my Product.wxs and install my service via MSI?
Apperantly this error has nothing to do with the provided settings for the Wix installer, but rather the machine that Wix is installed on.
After testing my program on a different machine, all worked fine.
I have three projects I'm building
FooBar.Abstractions
FooBar.AspNetCore
FooBar.AspNetCore.IntegrationTesting
The FooBar.AspNetCore and the FooBar.AspNetCore.IntegrationTesting projects both have references to FooBar.Abstractions. I want to package and ship all three of these as individual NuGet packages.
I started with a NuGet.config file that looks like this locally:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="aspnetcore_abstractions" value="./src/FooBar.Abstractions/bin/Debug/" />
</packageSources>
</configuration>
Then I add the package to my projects
<ItemGroup>
<PackageReference Include="FooBar.Abstractions" Version="2.0.0-preview1" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
</ItemGroup>
This really sucks though as each time I make a change in the FooBar.Abstractions project I have to go into my C:\.nuget\packages folder and delete the cache before my FooBar.AspNetCore project can restore the newly compiled version from my solution.
If I just add FooBar.Abstractions as a project reference, and then I ship the two packages to NuGet.org, how does that affect users that install the two packages across different projects in their solutions. Does NuGet and .Net figure it all out, knowing that they're the same referenced assembly? I assume in this case the FooBar.AspNetCore project will ship with the FooBar.Abstractions.dll in it if I add it as a project reference.
I don't know if that causes conflicts knowing that the package ships that .dll, then a customer installs the Abstractions package explicitly that contains the same .dll.
How do you handle this with NuGet packaging with the newest versions of NuGet? How do I constrain FooBar.AspNetCore to use the same FooBar.Abstractions.dll version between the package reference and the NuGet package others will install? I can't force PackageReference Include="FooBar.Abstractions" Version="2.2" if I'm adding it as a project reference instead can I?
When you pack a project with at project reference, NuGet converts the project reference into a NuGet dependency. It figures out the dependency version based on what version that project would be if it were packed. There is no need to use PackageReference when packing. As you discovered/explained, doing so makes local development much more difficult.
Therefore the solution to your problem is to just use ProjectReference when the projects are in the same source code repository.
I have a Dotnet Core 2.1 project which has both a nuspec and a csproj file - one major hassle is that the csproj describes dependencies like this:
<ItemGroup>
<PackageReference Include="Refit" Version="4.6.16" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1" />
<PackageReference Include="Refit.HttpClientFactory" Version="4.6.16" />
</ItemGroup>
While the nuspec does this:
<dependencies>
<dependency id="Refit" version="4.6.16" />
<dependency id="Refit.HttpClientFactory" version="4.6.16" />
<dependency id="Microsoft.AspNetCore.All" version="2.1" />
</dependencies>
Both are easily out of sync and keeping the same information twice is annoying.
Is there a way to avoid that?
There is certain to be a easy way for this, just use dotnet pack instead of nuget pack and .csproj files instead of .nuspec files.
dotnet pack supports 2 ways to specify the nuget package properties.
The legacy way: using .nuspec file, which would disable the 2nd way
The new way: specifying them in .csproj file
dotnet pack supports both ways but you must add a NuspecFile property to reference the .nuspec file and there are a lot of bugs and feature missings for the legacy way, which means you can only use the new one.
dotnet pack executes restore and build on the project and packs it with a automatically generated .nuspec file resolving all nuget metadata properties in .csproj as .nuspec properties and all projects references as nuget package references (This is not available with manually specified .nuspec file), so that versioning, dependency, and package file structure things can be automatically ensured.
My own library could be an example. Version and dependency things are specified for only once at where they are supposed to be and there are no longer any annoying duplicate configurations. Executing dotnet pack on the solution directory would generate all good .nupkgs on the dist directory.
I have a couple packages that include content files (an example would be the wurfl package for getting device data from a user agent, it includes it's database file in the nuget package marked as content).
When adding these packages in an asp.net 5 setting, the content doesn't get added anywhere.
Where or how do I get at the content of these nuget packages added to my solution?
http://blog.nuget.org/20150729/Introducing-nuget-uwp.html
Deprecated Features
Starting with NuGet 3.1 when using project.json, we are deprecating support for executing the install.ps1/uninstall.ps1 scripts and delivering elements in the /content folder of packages. Installing packages that have these elements will not execute the install.ps1 file and will not copy content to your project.
Read the link for more on why...
This is an old question, but my even so old solution seems to work still for Net 5. Here it is:
Include a YourPacakgeName.targets file in your package like this:
<file src="YourPacakgeName.targets" target="build" />
The content of the .targets file should then be:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<MySourceFiles Include="$(MSBuildThisFileDirectory)..\Content\**\*.*"/>
</ItemGroup>
<Target Name="CopyFiles" BeforeTargets="Build" AfterTargets="Clean">
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="$(MSBuildProjectDirectory)\%(RecursiveDir)"
SkipUnchangedFiles="true"
/>
</Target>
</Project>
Effectively this copies the content files before a build and after a clean action.