Testura/Testura.Code

Allow a user to add NuGet packages to the compilation

Opened this issue · 5 comments

It would be really nice if there was a way to add Nuget packages to a compilation.

I suspect we are probably going to need a fluent builder of some form and then the ability to add a package to the compilation.

The follow-up question to this, is does the compilation class/interface need a refactor?

@jeffward01 I know you said you had a number of fluent builders waiting to be brought in, I wonder whether NuGet was one of them?

No I don't have any Fluent Builder for that, most of my builders are to generate code itself, like methods, or attributes, or things like:

this.Property => someValue;

I don't understand why you'd need NugetPackages to the Compilation. You can inject in any using statement that you want, and generate any code you want. The using statements I don't think need to be valid.

Can you give me an example for this so that I can understand better? It sounds like its something you are working on actively

Whilst I agree the usings don’t need to be valid, there doesn’t seem to be an easy way to add aNuGet package using Roslyn. You would have to download the NuGet package, extract it and then reference it. I’m in a situation where I need to generate mappings for a csv parser on the fly based on the classes created in a specific namespace. The base class for the mappings comes from a third-party assembly hosted on NuGet. Hopefully that gives some context. I’m happy to work on the integration and add this as a separate package. Thanks, Sean. From: Jeff Ward @.> Sent: 29 November 2022 06:09 To: Testura/Testura.Code @.> Cc: Sean Farrow @.>; Author @.> Subject: Re: [Testura/Testura.Code] Allow a user to add NuGet packages to the compilation (Issue #102) No I don't have any Fluent Builder for that, most of my builders are to generate code itself, like methods, or attributes, or things like: this.Property => someValue; I don't understand why you'd need NugetPackages to the Compilation. You can inject in any using statement that you want, and generate any code you want. The using statements I don't think need to be valid. Can you give me an example for this so that I can understand better? It sounds like its something you are working on actively — Reply to this email directly, view it on GitHub<#102 (comment)>, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AALDK7TJTHYEXT3WLAURFZDWKWMWRANCNFSM6AAAAAASOBAFLU. You are receiving this because you authored the thread.Message ID: @.***>

Honestly what I would do is just install the nuget packages separately. For example, I have some Solution / Project genration code that generates an API solution (similar to clean architecture). and first I scaffold the project empty files, then I install the nuget packages, and lastly I generate the code.

I think that the nuget packages might be a little bit out of scope of the Testura, it would add complexity, but it is a helpful thing to add, I can see it being useful but would love to here other opinions on this @MilleBo

Personally, I suggest we put it in the back-log, because testing will be needed and such, and I suggest we implement option 2 from my below suggestions

From my experience, programmatically managing nuget packages is a bit complex. If we add the feature to 'install it', then we must add the feature to update it, then remove it. Then what about 'Private pacakges' that look like this:

    <PackageReference Include="Microsoft.SourceLink.AzureRepos.Git" Version="1.1.1">
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
        </PackageReference>

or this:

    <PackageReference Include="Microsoft.SourceLink.AzureRepos.Git" Version="1.1.1">
         // Some of the included assets have been removed, edge cases would need to be tested
            <IncludeAssets>runtime;   contentfiles; analyzers; </IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
        </PackageReference>

Then you have to mange SemVar, and updating with pre-release, or not pre-release, then also look at 'can it be installed, are their circular dependencies? One or more Target Frameworks, Directory.Build.props files, using Nuget.Config and credentials to manage nuget artifacts.

The good news is most of that code that manages that stuff is already in various libraries including the Nuget.SDK and dotnet-outdated (see below)

I have alot of the code for the above points already implemented for my own projects that I can share with you, but those were not the Builders I was referring to.

For this, I offer you three solutions that I am aware of and have used myself and I can help with it, by either sharing my existing code or by suggesting patterns.

  1. Use Cli.Wrap and manually install packages via the command line. I found that Async was a bit of a pain with this, so I would always call .GetAwaiter().GetResult(); when I did this methods.
  1. Another method I have done and have the code for was I extracted the nuget SDK itself, and now have a nuget package installer that I can handle via SDK's. I used the code here for inspiration: https://github.com/dotnet-outdated/dotnet-outdated/tree/master/src/DotNetOutdated.Core/Services

My code that I extracted has not been tested or debugged. It works for my projects, but I would have to pull it out. Its very very similar to that code.

@MilleBo @SeanFarrow -- If you guys suggest, I can convert my code here to a builder and implement it, however I won't have time to do so for a week or two if I am being honest - perhaps I can find time to rip it out and put it in a PR - but it will need to be tested. Let me know

  1. The third way I have done it in the past is by modifying the project files themselves. And 'regenerating' the XML, or reading the XML and then injecting my new XML where its supposed to go. This method worked fine, but I don't currently use it.

How i install packages
Currently I use method 1 to 'install packages'.

How i update pacakges
And To update packages I use either Method 2 (this is the better option), but in some areas of the code, i was a bit lazy (busy) and have to implement method 2 later, so instead i manage the package updates with using a combination of:

I hope that these solutions were helpful, let me know if you would like me to share any code


Honestly, I suggest to you that you should just do option 1, using https://github.com/Tyrrrz/CliWrap and push the 'easy button'. Option 2 of course is more better because it does not spawn an outside process, but option 1 is quicker.

If I were you I would:

  • Step 1: Parse the CSV or input file
  • Step 2: Identity the nuget packages to install
  • Step 3: Install the nuget packages
  • Step 4: Use Testura Code to generate the files

Let me know if i can help

I also use this quite often https://github.com/daveaglick/Buildalyzer

Buildalyzer lets you run MSBuild from your own code and returns information about the project. By default, it runs a design-time build which is higher performance than a normal build because it doesn't actually try to compile the project. You can use it to perform analysis of MSBuild projects, get project properties, or create a Roslyn Workspace using Buildalyzer.Workspaces. It runs MSBuild out-of-process and therefore should work anywhere, anytime, and on any platform you can build the project yourself manually on the command line.