Consolidate packages with Cake build - cakebuild

Can Cake build verify if the NuGet packages in a multi-project VS solution are consolidated?
I would like the build to fail if there are multiple versions of the same NuGet dependency in use.

Is your solution using PackageReference? If so you could use Microsoft.Build.CentralPackageVersions in your MSBuild solution to manage and enforce package versions.
While this is is not a solution in Cake but in MSBuild script, it should work fine together with Cake.

Related

Cake NuGetRestore Could not locate nuget.exe

I have created simple .NET5 console application which can be successfully run using "dotnet restore" and "dotnet run". Application is using one package Newtonsoft.Json.
I want to restore NuGet packages using NuGetRestore() but in result I get "Could not locate nuget.exe".
I am using Cake .NET Tool in version 1.1.0 and default configuration.
As far as I remember, previously when I was using Cake before version 1.0.0 nuget.exe was downloaded to 'tools' folder.
What am I missing? How to make sure nuget.exe is downloaded/provided by Cake?
In order for the NuGet tool to be downloaded to the tools folder, you need to include the NuGet.CommandLine package in your Cake build script. e.g.
#tool nuget:?package=NuGet.CommandLine&version=5.9.1
Related info:
Example build.cake file referencing NuGet.CommandLine
NuGet.exe related documentation
Cake itself never did download nuget.exe. The example bootstrapper for Cake Runner for .NET Framework does this in certain conditions. Example bootstrapper for Cake .NET Tool does not download nuget.exe and you need to make yourself sure to have it available, either by updating the bootstrapper, using the tool prepocessor directive in your build script, or any other mechanism outside of Cake.

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?.

How do I correctly install nuget packages outside of VS and keep track of them?

I'm trying to use nuget.exe outside of Visual Studio as part of our build infrastructure. The idea is that the various build tools are fetched by a bootstrapper script that initializes a working copy. The bootstrapper does this by using a file that specifies the required tools and their version.
Broken approach 1 - use manually edited packages.config
At first, it seemed like a good idea to keep a manually edited packages.config file and use nuget restore to install them during bootstrapping. However, this does not work for tools that have dependencies, unless I list every single dependency in the packages.config as well, a much to arduous approach to be feasible, because I found no easy way to recursively find all dependencies of a package.
See also using nuget.exe commandline to install dependency .
Broken approach 2 - use nuget install to update packages.config
The second idea was then to use nuget install to install the packages, and let that command update the packages.config, very similar to the Install-Package cmdlet in the package manager console. But, surprisingly, nuget install does not support this! It either takes a packages.config or a package ID as parameter, but I found no way to update the packages.config with the new package and its dependencies.
This problem can also be found in another (two year old) SO question, see nuget.exe install not updating packages.config (or .csproj)?.
Is there a working (and non-hacky) approach at all?
This must be a problem that many people face when using nuget outside of VS, so what is the best approach in that case?
Of course, I could just parse the packages.config and emit a nuget install for each package, but I really don't want to re-invent the dependency management part of nuget, this is what I'm using nuget for in the first place. So I'm left with the feeling that either an -WithDependencies switch on nuget restore or an -UpdatePackagesConfig switch on nuget install is missing...
Note that there are other SO questions regarding the broken approaches described above. What I'd like to know it what the best approach is to solve the root problem, i.e. manage packages with dependencies outside of VS.
nuget install does not currently make changes to the project file.
nuget install can be used to either restore the NuGet packages listed in a packages.config file or download and extract them.
If you do not need the project being modified then your solution of reading the packages in the packages.config file and calling nuget install seems like a reasonable approach.
If you need the project to be modified then you could look at one of the following:
Ripple - a command line tool that adds extra features to NuGet. It has a ripple install command line which is similar to nuget install but it also updates the project file. It has a lot of other features for supporting build servers so this might be a good fit.
NuGet packages outside of Visual Studio with SharpDevelop - this was an experiment I put together to see whether full NuGet support could be achieved, including PowerShell scripts, from the command line without using Visual Studio. It uses PowerShell and quite a bit of SharpDevelop.
Customise NuGet.exe to do what you need. nuget update, for example, does modify the project file, at least for file references, but will not run PowerShell scripts. So you could take the NuGet.exe source code and extend it.
Of the above only 3) would give you exactly what you need. The other two would require a bit of work to read the packages from the packages.config file or some other list and then install them.
See my answer to Why does the nuget command line tool not follow dependencies?
nuget install My.Package.Id will follow dependencies. However, if you want to install multiple packages, you will need to create a batch file with a separate nuget install command for each package. These are top-level packages. You don't need to "install" the dependencies, as they will get downloaded automatically.
If you ultimately want a packages.config file, I imagine you can generate one by enumerating all the packages that were downloaded. However, you would have to take care not to include multiple versions of the same package.
I believe that how nuget 3 works with project.json files may do what you are looking for. Essentially my understanding is that the unit of dependency becomes the package and not necessarily individual assemblies. From what I recall, the idea is the have only one place to manage these types of package references which the project (IDE/Editor), package manager, and other command line tools can use.
What I don't understand and feel somewhat frustrated about is that it appears that the project.json concept is being canceled. I don't know if plans are to reintroduce it at anytime in the future. In the mean time I keep on hearing updated info on tooling that takes advantage of project.json such as nuget so where you can actually rely on this is something that is unclear to me at this point.

nant: best way to separate out nunit test dependency from production package

I have a nant project that builds my c# library, but has a dependency currently on nunit for building the test library portion of my project. Our users of the package have complained that they don't want this dependency in a production environment.
I'm new to nant configuration, so am looking for ways of making this dependency optional, or where you need to opt-in to it it for development building, perhaps as a target flag.
I don't think you can do so in Nant. But, since nant would work on the project files, you can add a condition to the project file like this -
<ItemGroup>
<MetaDataFile Condition="'$(Configuration)'=='Debug'" Include="$(BuildProjectFolderPath)/SubFolders/MyTestListFile.vsmdi">
<TestList>My Test List Name</TestList>
</MetaDataFile>
<TestContainer Condition="'$(Configuration)'=='Debug'" Include="$(OutDir)\MyTests.dll" />
Found this here.

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.