How to wrap a NUnit Engine Extension as a NuGet package? - nuget

I am working on a nunit engine extension which will be shipped as a nuget package.
Following the advises in How to implement NUnit's NUnit.Engine.ITestEventListener i was able to write the extension.
This solution is working as long as the project which contains the extension (the .cs file as well as the .addins file) is being imported to the target project which will perform the nunit tests.
As soon as I create a nuget package (following Quickstart: Create and publish a NuGet package using Visual Studio (.NET Standard, Windows only)) from the extension project and install this package to a test project, the extension doesn't work anymore.
I assume there is a problem with providing the .addins file within the nuget package so that the nunit engine in the target project can find the extension.
I already tried to ship the .addins file within the nuget package by adding the following lines to the .csproj file of the extension project.
<ItemGroup>
<Content Include="file.addins">
<Pack>true</Pack>
</Content>
</ItemGroup>
If I add the .addins file to the target project by hand, the engine extension starts working.
How can a nunit engine extension be shipped as a nuget package without any adjustments by hand?
Im using NUnit(3.13.2).
Im quite new to nunit, nuget and writing questions on stack overflow. So if I'm missing something obvious here, I'm sorry.

This is one of those areas where I wish things were less complicated, unfortunately. Since extensions are found through a relative path from the NUnit engine to the package content, it depends on where both the engine and runner are located and where the package is located on your machine.
Here are some initial guidelines...
How to structure the package itself... your extension assembly itself should be in the tools directory. If there are other assemblies with it, which it references, it's best to also include a .addins file in the same directory, which lists that assembly on a single line. That way, the NUnit engine will save time by only examining the extension assembly.
A NuGet extension package will automatically be found by the engine if the runner has been installed as a nuget package as well. This works no matter how the packages are installed on your machine, i.e. using packages.config or in a nuget cache, provided both packages were installed the same way. (That proviso is a real gotcha and it may be that a future version of the engine needs to actually understand nuget.) See the addins file provided with the the NUnit 3 console runner as an example of why this works.
The same thing is true if both the runner and the extension are installed as chocolatey packages, because they are both in the chocolatey cache. If you do provide one (which I recomend) it has to be a "native" package - one that includes the actual binaries. A chocolatey package that merely invokes the nuget package will not work. See the source for any of the NUnit-provided extensions for an example of how this this is done.
If the executing copy of the engine (usually in the same directory as the runner) is anywhere else, there is no automatic way for the extension to be found. This includes the case where you are building a runner yourself and want the extension to be available while you are developing. In that case, you need to fully understand how the engine finds extensions (see the docs) and manually create an addins file (next to any that was distributed with the engine) containing the proper relative path.
This is especially complicated if you are developing an extension for general release. Then you have to deal with various runners installed in different ways by different people. OTOH, if you are doing this for internal use in your company, you may only need to deal with one of them. If you add more specifics about your goal to the question, I'll edit this with some more specific suggestions.

Related

What is nuget props file and what is it for?

I have looked around and read a lot but couldn't find a definitive answer that would explain as to what the "nuget.props" file is and what is it used for.
Any explanation and maybe with some example?
Starting with some background information, .NET projects are built with MSBuild. A C# project's .csproj is just a MSBuild project file with a file extension that signals by convention that it's C# and not some other language, but to MSBuild it's just a project file. MSBuild has only a few base types, properties, items, targets and tasks. By convention, properties and items go in files with extension .props, while tasks and targets go in files ending in .targets. That's why if you look at old-style csproj files you'll see <Import Project="path\to\Microsoft.Common.CSharp.props" /> and <Import Project="path\to\Microsoft.Common.CSharp.targets" />. New, SDK style projects is basically syntactic sugar to do exactly the same thing.
Next, the MSBuild and .NET teams made the build system extensible. So, rather than being limited to what Microsoft built into the C# compiler/build system, you can replace parts of the build system, or add additional things into it. Without NuGet, the way to do this is to create your own .props and .targets file somewhere, then edit your .csproj and add <Import ... /> statements. This can work fine if your props and targets are in the same source code repository as what's using it, but editing your csproj and hardcoding the path to the props and targets files doesn't work so well otherwise.
NuGet can help with this. If you create a package with the appropriate conventions, NuGet will make sure the props and targets are discovered and used in the build. With projects using packages.config, NuGet will edit the csproj for you on install/upgrade/uninstall. Projects using PackageReference, NuGet will write a file to the intermediate directory (obj/ folder) named nuget.g.props and nuget.g.targets, which imports all the props and targets files from all the referenced NuGet packages, and the build system uses these files.
The first example I could think of why someone would want to do this is if you want to use a newer version of the .NET compiler than is installed on your system. Simply reference the Microsoft.Net.Compilers package, and the .props and .targets in the package will replace the compile targets/tasks in the system-installed build system, and use the one from the package instead. This allows you to use new language features before the compiler is installed on your system, or if you want to make sure all builds of your code use the same compiler, even if different developers or CI agents have different versions of things installed.
Another example may be pre-compiled scripts. If you have your own scripting language, create build tools that converts them into C# files, then write MSBuild props and targets that will run before the "real build" to convert your custom language into C#, save the generated .cs files into the intermediate folder, add MSBuild Compile items for these generated files, then the C# compiler will compile it with all the other .cs files in the project. You'll need a reasonable amount of knowledge of MSBuild and the .NET build system, but it's possible.

What is the most standard way to get the latest version of an assembly solution-wide using NuGet?

My company is moving to using NuGet for our internal dependencies for desktop applications. This works fine for versioned imports, but in some cases (like during pre-Beta on a product) we'd like to grab the latest version of the dependency on our build servers and have the csproj files find it without issue.
We'd like to use automatic package restore, but that seems to be constrained by a specific version (as noted in this question). Using nuget restore followed by nuget update is also a possibility, but it doesn't seem to work solution-wide the way that restore does (and we have a couple dozen projects that have to share the same version of the same dependency).
Our best solution so far has been to add a hint path to the dependency binary in a non-versioned manner, i.e.,
<Reference Include="Dependency">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Dependency\lib\net40\Dependency.dll</HintPath>
</Reference>
And use the pre-build event to run
nuget.exe install Dependency -NoCache -ExcludeVersion
Is there a better way to do this? It would be nice to do it the most standard way possible so that we can get tooling support and new developers to the project can more easily know how to add their own dependencies via NuGet.
As of Nuget.exe v2.8.3, there isn't any way to do a solution-wide restore and update (at least when not all the projects in a given folder hierarchy are part of a solution). We ended up using the workflow described in How do I update a single nuget package in a project from the command line?.

Get current version of package outside of Visual Studio

We are migrating over to using packages and NuGet for managing our dependencies on 3rd party components. This works well when referencing packages from within Visual Studio or building on the build server via msbuild.
However there are a number of files that we would like to access in our build scripts and installers. Previously these would be in source control with a well known path, now as the version of the package that we are consuming changes so the path to the package and hence the files is changing.
Is there a simple way I can get the path to a given package? The best solution I currently have is to search for all packages.config files and extract the package version from them.
Examples of the files that we need to access are
The NUnit console executable from the NUnit.Runners package for running unit tests.
License files from various packages that we redistribute with our installer.
Using the packages.config file is a pretty good solution. NuGet itself uses two approaches:
Reading the package information from the packages.config and using that to resolve to the packages path.
Enumerating all the directories in the packages directory.
You could use NuGet.Core to do either of the above if you do not want to write the code yourself. The classes that can be used are the DefaultPackagePathResolver, the PackageReferenceFile and LocalPackageRepository or SharedPackageRepository.
One problem with the second approach is that sometimes NuGet may occasionally leave behind NuGet packages that are not necessarily referenced by a project. In that case looking at the package directories may give you the incorrect information.
The only other approach I can think of might be to read the project files looking for the assembly references. Although that would not work for a solution level package such as NUnit.Runners.

Using nuget to update project files outside of Package Manager Console

Nuget.exe only supports managing packages at a file system/configuration level. The powershell commands command the magic that update the .proj files.
With that said, i need the ability to update a csproj file with the latest version of a NuGet package outside of visual studio (automated).
Basically, how do I use Install-Package (or any of the other methods) inside of an external powershell script of my own?
UPDATE:
I would like to ability to add project references outside of VS for the following reason.
My company has a lot of shared libraries that depend on each other in some cases. I am using TFS Nugetter to build and publish nuget packages from TFS. I want to ensure that the developers can't queue a build (package) unless the project can build and run on all the newer versions. This ensures that all the newer versions of the libraries work with all the newer versions of its dependencies. If the build fails, then you need to update your nuget reference in VS and fix the compiler errors/unit tests.
I have been looking at the NuGet source and I think I found an easy way to reuse NuGet source to modify proj files outside of VS (kinda).
System.Type t = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0", true);
var dte = (DTE)System.Activator.CreateInstance(t, true);
dte.Solution.Open(
#"C:\Users\paul.knopf\Documents\Visual Studio 2010\Projects\SLNMemory\SLNMemory.sln");
Basically, open an in-memory version of visual studio, run the nuget commands, then save.
In a build step, after GetWorkspace, I would like to run this in-memory vs to update all nuget references to the latest version.
What do you think? It would definitely be slow, but we would be on the same code base and have all the functionality we need.
Automating Visual Studio as you describe is certainly a possibility.
Another way I looked at was using SharpDevelop to install NuGet packages outside of Visual Studio. The NuGet PowerShell cmdlets were modified to accept a solution and you could automate installation, including the use of PowerShell scripts in a NuGet package, from the command line. The code has not been updated so it targets an old version of NuGet but could be updated. Again this is similar to your solution and fairly heavyweight solution.

NuGet pack is not packaging all files in the output directory. What am I missing?

I'm trying to create a NuGet package from a .csproj. I have successfully compiled the project and the output folder contains all of the necessary files (my assembly and all of its dependencies). However, NuGet only seems to be placing the assembly created by the .csproj into the package and not any of its dependencies. My command line looks like this:
nuget pack MyProject.csproj -Property Configuration=Release
and my resulting .nupkg file only has my assembly in the lib folder. I have successfully gotten NuGet to work for other projects, but it just so happens that this project is referencing the Enterprise Library logging block, but it was NOT retrieved via NuGet. I'm not sure if that could be related to my problem or not.
Any thoughts on why it's not picking up the dependenices?
If you need to keep your nuspec file up-to-date automatically, its really just an XML file (as I'm sure you know) so there are some very nice tools you can use from MSBuild to automate nuspec creation/updates. Out of the box, MSBuild provides a few tasks that can update or transform XML, and I've used MSBuild Community Tasks to customize the initial nuspec. For example, the default nuspec contains a few lines with broilerplate that I don't need, so I use XmlUpdate tasks to delete them.
Although I have not looked into scanning the csproj file for non-nuget references, I think its likely possible with a little research. Here are some links to blog entries describing my experiences with NuGet automation, they may help you get a head start:
Creating Packages with NuGet the MSBuild Way - This article includes some basic NuSpec updates because the package described is not that different from the type of package NuGet already knows how to automate.
Manage Your MEF Parts With Nuget - This article includes some more complex updates to support distributing MEF parts as runtime-only references.
If you plan on doing this alot, don't want to mess with MSBuild, or just want to get back the behavior you liked from the pre-1360 version of ProjectFactory.cs, NuGet supports third-party extension through MEF. You could go into the source control and grab the earlier code that you liked and create a custom command (for example custompack) that provides that behavior. Then you could use it from the command line like so:
nuget custompack MyProject.csproj -Property Configuration=Release
I think this is a really cool aspect of NuGet but I haven't played with it myself yet. Here is an article that explains how to do it:
Extend NuGet Command Line
So even though David mentioned that NuGet is not designed to support this scenario, if the scenario is correct for you then you can go this route to extend NuGet to meet your needs.