NuGet / Home

Repo for NuGet Client issues
Other
1.5k stars 252 forks source link

CPM - Pre-Restore hook not working / does not exist #13906

Open msherms2 opened 2 weeks ago

msherms2 commented 2 weeks ago

NuGet Product Used

dotnet.exe, NuGet.exe

Product Version

dotnet 8, nuget 6.10+

Worked before?

Linked post implied this once worked, unknown info

Impact

I'm unable to use this version

Repro Steps & Context

Short: We need a hook that allows a PreRestore event to occur.

Longer: Until slnx files become more mature, which will help the "where" to put the such event, I still don't think this will solve the issue.

This is directly used for Central Package Management (CPM). I've got a wide array of interlaced dependencies separated into multiple repositories. Changing this is not an option. To keep third party and local packages in sync, we thought CPM would be good, so we keep a central repository and keep our Directory.Packages.Props files managed there. At the pipeline build time, we simply fetch that file to the $(SolutionDir) and bam, build successful.

The problems come when developing locally. It's the wish of every developer to simply fetch and pull code from git and just click build, and have it work, but no PreBuild or PreRelease event type functionality could be found to invoke a download of that Directory.Packages.Props file.

The linked item here seems to no longer work: https://github.com/NuGet/Home/issues/4781 The item above has a few targets from various target files which seem to apply before restore, but when I tried it did not work. Everything i tried would restore first, fail (and pull versions despite the failure....different issue), and never try to execute the pull (since it failed before it).

Is this supported but has been disabled? Does it only fail because events can only exist in csproj files, before slnx solves that? Any insight into this would be helpful.

Verbose Logs

No response

donnie-msft commented 2 weeks ago

Have you tried a Directory.Solution.targets? That should allow you to extend the build when building a solution from the command-line. For more information, see https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-solution-build?view=vs-2022

Let us know if you're mostly interested in extending restore in Visual Studio. In that scenario, you could possibly run a target before CollectPackageReferences.

msherms2 commented 2 weeks ago

Have you tried a Directory.Solution.targets? That should allow you to extend the build when building a solution from the command-line. For more information, see https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-solution-build?view=vs-2022

Let us know if you're mostly interested in extending restore in Visual Studio. In that scenario, you could possibly run a target before CollectPackageReferences.

I was optimistic and even excited at this, but once I got the solution open to try it, I read that document more clearly.

Customizing the solution build in this way applies only to command-line builds with MSBuild.exe. It does not apply to builds inside Visual Studio.

I can't have our developers unable to use VS and required to use msbuild.exe directly. In addition the details after that at least imply that the solution.targets file gets imported after the build. I see now that you wrote it was from command line, so clearly my reading comprehension could use a tune up. :)

Of note, I did in the original post say I tried CollectPackageReferences, following the example of the closed issue I linked - but if you have a more specific example you've seen work, I am happy to try it. Every time I tried any kind of reference like that, I could clearly see no code was executed before it ran the restore.

thanks

nkolev92 commented 2 weeks ago

Hey @msherms2,

Not sure if I have an exact suggestion to address your problem right now, but here are clarifications about the capabilities you're looking into and how they're used.

CollectPackageReferences (and other NuGet Collect targets) is an extensibility point that allows SDKs, example, .NET SDK to automatically add certain packages conditionally. It allows for more complex logic than just adding an item. This is a target that runs during NuGet's "figure out what the project needs" phase.

It runs on every CLI restore. Due to technical reasons, it runs only for .NET SDK based projects in Visual Studio. If you're using old style csproj, it won't work.

Very importantly, this task must be fast and efficient. It is not meant to download things. Even if you you were to download, you'd need to ensure that the file is included in the evaluation for restore which is hard because you're in the middle of it. You'd also be making inferences about PackageVersion and all other item collection targets and the order in which they run, but there's no guarantee.

You seem to really want a toolset download, which is normally something done with a different step. .\configure.ps1, or in the SKD case, similar to what dotnet/arcade does, https://github.com/dotnet/arcade.

tldr; The way I read your scenario, I don't think you need a pre-restore hook, you need something that happens before any operation, so I'd consider that file you have as part of the toolset.

msherms2 commented 1 week ago

Hey @msherms2,

Not sure if I have an exact suggestion to address your problem right now, but here are clarifications about the capabilities you're looking into and how they're used.

CollectPackageReferences (and other NuGet Collect targets) is an extensibility point that allows SDKs, example, .NET SDK to automatically add certain packages conditionally. It allows for more complex logic than just adding an item. This is a target that runs during NuGet's "figure out what the project needs" phase.

It runs on every CLI restore. Due to technical reasons, it runs only for .NET SDK based projects in Visual Studio. If you're using old style csproj, it won't work.

Very importantly, this task must be fast and efficient. It is not meant to download things. Even if you you were to download, you'd need to ensure that the file is included in the evaluation for restore which is hard because you're in the middle of it. You'd also be making inferences about PackageVersion and all other item collection targets and the order in which they run, but there's no guarantee.

You seem to really want a toolset download, which is normally something done with a different step. .\configure.ps1, or in the SKD case, similar to what dotnet/arcade does, https://github.com/dotnet/arcade.

tldr; The way I read your scenario, I don't think you need a pre-restore hook, you need something that happens before any operation, so I'd consider that file you have as part of the toolset.

Thanks for responding and sorry for the delay - long weekend. I think the capability you're referring to sounds promising and probably what I want - the ability to run a configure.ps1 file as the first thing that happens is exactly what i want - you're right, I only care that it's before restore, but anytime earlier would be fine. Following the linked arcade, I'm not sure I exactly see how that fits in, can you help me figure out how to use this functionality?

nkolev92 commented 1 week ago

I don't think you can use arcade. I was offering an example of how people achieve what you're trying to do. You'd potentially need to define an MSBuild SDK, https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2022.

Alternatively, you can just have a separate configuration script that can be powershell, msbuild or whatever your team is comfortable maintaining.

msherms2 commented 1 week ago

I don't think you can use arcade. I was offering an example of how people achieve what you're trying to do. You'd potentially need to define an MSBuild SDK, https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2022.

Alternatively, you can just have a separate configuration script that can be powershell, msbuild or whatever your team is comfortable maintaining.

I just need to make sure we're not having a disjoint. Currently VS does not have a trigger for "before anything" and can only handle project custom actions. So invoking a separate configuration script won't be possible before restore, because pre-build triggers at a project level definitely happen before that. My initial email covers everything I've tried.

With that, are you saying there is some kind of configuration level script functionality exists to do this? A way to associate a .sln with a configure.ps1 script that executes at an initial state?

For MSBuild SDK types, I'm still not really seeing how that can inject an action pre-everything. It seems in the examples on the page linked, the closest to that would be the SDK being fetched from a nuget package, which would be during restore. When i mentioned alpine before i didn't think I could use it, but in trying to analyze the code and why you thought it was a suitable example, I saw some code in the project files, but nothing I could see as hugely relevant to my case.

nkolev92 commented 1 week ago

There's not way to force something that requires msbuild evaluation invalidation to happen equivalently before restore in VS and CLI.

It seems in the examples on the page linked, the closest to that would be the SDK being fetched from a nuget package, which would be during restore

MSBuild SDKs specified in the SDK element are separate from restore and they happen at evaluation time.

msherms2 commented 3 days ago

There's not way to force something that requires msbuild evaluation invalidation to happen equivalently before restore in VS and CLI.

It seems in the examples on the page linked, the closest to that would be the SDK being fetched from a nuget package, which would be during restore

That's a shame. I understand building two different ways would have differences but it seems counterintuitive they'd make it so difficult to not have deterministic equivalent outcomes. Why would one ever want VS to behave differently?

MSBuild SDKs specified in the SDK element are separate from restore and they happen at evaluation time.

Okay, so it sounds like this may be a viable option. So my gameplan is to define a project level SDK to be imported at evaluation time, and this SDK has some script execution associated with it that will ultimately factor in as an evaluation time custom action?