Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NuGet.SemanticVersion does not parse prerelease versions. #13408

Closed
kfertitta opened this issue Apr 24, 2024 · 19 comments
Closed

NuGet.SemanticVersion does not parse prerelease versions. #13408

kfertitta opened this issue Apr 24, 2024 · 19 comments
Labels
Functionality:SDK The NuGet client packages published to nuget.org Product:VS.Client Resolution:NotABug This issue appears to not be a bug Type:Bug

Comments

@kfertitta
Copy link

NuGet Product Used

Other/NA

Product Version

NuGet.VisualStudio 17.9.1

Worked before?

No response

Impact

I'm unable to use this version

Repro Steps & Context

The NuGet.VisualStudio package includes a SemanticVersion type with a TryParse method that does not accept version strings with a dot . after any prerelease tag.

For example, SemanticVersion.TryParse("17.6.0-preview.3") fails, whereas SemanticVersion.TryParse("17.6.0-preview-3") succeeds. The dot in a prerelease suffix is allowed by SemVer and accepted by the SemanticVersion type in the NuGet.Versioning package.

Unfortunately, we require semver parsing in our Visual Studio extension and must use the NuGet.VisualStudio package.

Verbose Logs

No response

@jgonz120
Copy link
Contributor

We are moving away from SemanticVersion in NuGet.VisualStudio. There are instances where have marked properties that use this version as obsolete.

@nkolev92 can you help figure out a way forward here?

@kfertitta
Copy link
Author

Yes, it's ironic that this package can't parse some of its own versions.

@nkolev92 nkolev92 added Product:VS.Client Functionality:SDK The NuGet client packages published to nuget.org and removed Triage:Untriaged labels Apr 24, 2024
@nkolev92
Copy link
Member

nkolev92 commented Apr 24, 2024

Hey @kfertitta

When the rewrite from NuGet2 to NuGet 3 (what eventually becomes current NuGet) happened around 2015-2017, NuGet had to basically become more than VS & NuGet.exe, the functionality was integrated into the .NET SDK & MSBuild.

NuGet.VisualStudio use to depend on an assembly NuGet.Core which was overloaded with functionality and made it challenging for the product to evolve.

Part of those decision were to basically simplify the Visual Studio functionality, by using string/string methods for id version: https://github.com/NuGet/NuGet.Client/blob/252bbee32a839623dc9af267f950d21cde5e9497/src/NuGet.Clients/NuGet.VisualStudio/Extensibility/IVsPackageInstaller.cs#L40-L41, and deprecate legacy types: https://github.com/NuGet/NuGet.Client/blob/252bbee32a839623dc9af267f950d21cde5e9497/src/NuGet.Clients/NuGet.VisualStudio/Extensibility/IVsPackageInstaller.cs#L85-L86.

Unfortunately I don't think we were thorough enough deprecate all the APIs, since we didn't add Obsolete attributes to all all types from: https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/NuGet.VisualStudio/LegacyTypes/.
There's a bunch of comments that call out Do Not Use.

https://github.com/NuGet/NuGet.Client/tree/dev/src/NuGet.Core/NuGet.Versioning has the full versioning functionality used the hood today, but we don't expose that in Visual Studio, since as I mentioned, the majority of the VS extensibility relies on string/string.

I don't expect us to port this functionality to the legacy type.

For what purposes do you need to parse different versions?
Maybe we can offer some different ideas or workarounds.

@nkolev92 nkolev92 added the WaitingForCustomer Applied when a NuGet triage person needs more info from the OP label Apr 24, 2024
@kfertitta
Copy link
Author

@nkolev92 , thank you for the reply. We have some pretty complex custom project systems. Our project wizards present the user with various lists of domain-specific packages from which they can choose to add to their project. It's a mini package manager in some ways, so we need basic equality comparison, sort comparison, prerelease detection, etc.

Having worked on VS extension for many years, I do recognize the difficulty of maintaining some level of parity between out-of-VS functionality and the core underlying machinery, such as that in NuGet.Client. That said, with so much of the project system (CPS-based ones, such as ours) and NuGet bleeding internally into one another, we're needing more NuGet client support within VS, not less. I'm actually in the process of opening an issue to suggest adding the ability to the VS NuGet APIs to query sources (nuget sources) and search for packages (nuget list packageid:abc). At present, we're actually trying to get by with shipping nuget.exe inside our VSIX and then shelling out to it and parsing stdout to get that functionality. Incredibly hacky, but it seems there are no other options.

@dotnet-policy-service dotnet-policy-service bot added WaitingForClientTeam Customer replied, needs attention from client team. Do not apply this label manually. and removed WaitingForCustomer Applied when a NuGet triage person needs more info from the OP labels Apr 25, 2024
@jeffkl jeffkl added Triage:NeedsTriageDiscussion and removed WaitingForClientTeam Customer replied, needs attention from client team. Do not apply this label manually. labels May 13, 2024
@nkolev92 nkolev92 added Priority:3 Issues under consideration. With enough upvotes, will be reconsidered to be added to the backlog. and removed Triage:NeedsTriageDiscussion labels May 13, 2024
@jeffkl
Copy link
Contributor

jeffkl commented May 13, 2024

Team Review: There are two options:

  1. Reference NuGet.Versioning and use the NuGetVersion class to parse semantic versions. Your extension will need to redistribute NuGet.Versioning.dll so that you can access the types at runtime since NuGet does not make these available in Visual Studio (https://github.com/NuGet/NuGet.Client/blob/dev/docs/nuget-sdk.md).
  2. Create your own class for parsing a semantic version. You can copy-paste the implementation in NuGet.Versioning.

@jeffkl jeffkl closed this as not planned Won't fix, can't repro, duplicate, stale May 13, 2024
@jeffkl jeffkl added Resolution:NotABug This issue appears to not be a bug and removed Priority:3 Issues under consideration. With enough upvotes, will be reconsidered to be added to the backlog. labels May 13, 2024
@kfertitta
Copy link
Author

kfertitta commented May 13, 2024

@jeffkl I'm not clear on how 1. above is an option. If an extension ships NuGet.Client packages with our extension, we'll break VS. That's the whole reason for there being a NuGet.VisualStudio package in the first place, I believe. Am I missing something?

@jeffkl
Copy link
Contributor

jeffkl commented May 13, 2024

NuGet.Versioning.dll has a new version for each release and is strong name signed. Within the devenv.exe process, multiple versions of the "same" assembly will be loaded side-by-side just fine since its a .NET Framework application. So the NuGet Package Manager might load NuGet.Versioning.dll version 6.9.2.1 from %VSINSTALLDIR%\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.Versioning.dll

NuGet.Versioning, Version=6.9.2.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35

Then your extension would include NuGet.Versioning from the latest package which is 6.9.1.3

NuGet.Versioning, Version=6.9.1.3, Culture=neutral, PublicKeyToken=31bf3856ad364e35

At runtime, the built-in NuGet functionality will use the first one and your extension will load yours. If there's ever a time where your extension is using the exact same version, the NuGet.Versioning.dll that ships with NuGet will be used by your extension since it will be loaded first. But that should be okay since its unlikely we'll be making breaking changes to how NuGetVersion.Parse() works.

@kfertitta
Copy link
Author

@jeffkl Yes, our preference would, in fact, be to go ahead and ship NuGet client packages with our extension to get the much more extensive functionality there relative to the IVsXX interfaces. I had thought that was frowned upon (or even verboten), as it leads to assemblies running SxS in devenv.exe, as you described. There are no binding redirects for these assemblies.

If we're clear to use NuGet client packages within our extension by shipping them, we'll do it.

@nkolev92
Copy link
Member

nkolev92 commented May 14, 2024

I think redistributing the exact assembly would limit options going forward if say we wanted to tweak the VS support.

A less likely to cause problems method might be to repackage (ilmerge/il-repack etc) within your assembly.

I have a write-up on that in #9611.
Some more docs on this: https://github.com/NuGet/NuGet.Client/blob/dev/docs/nuget-sdk.md.

@kfertitta
Copy link
Author

Thanks @nkolev92 . Indeed, we've used ilmerge in the past for such things. I think that's the best approach given the scope of what we need in our extensions is growing wrt NuGet. To facilitate reuse amongst our extensions, I think I'll create a special NuGet "metapackage" that references the NuGet.Client packages and uses ilmerge to bundle it all into a single assembly that we can safely ship with our extensions.

@kfertitta
Copy link
Author

@nkolev92 Actually, wondering if NuGet.Client's usage of VS-MEF will cause issues here. I know assembly identity is not considered when VS-MEF scans assemblies for exports, so perhaps the copy deployed with our extension might be picked up instead of the NuGet.Client copy. Working with @AArnott some years back, the general guidance was to not export types from assemblies that could be shared between more than one VS extension.

@AArnott
Copy link
Contributor

AArnott commented May 20, 2024

I haven't read the whole thread here, but I have two thought:

  1. ILMerge is evil. It causes so many issues I have never found a justified use of it.
  2. @kfertitta is correct in that MEF (not just VS-MEF) ignores assembly identity. If you use ILMerge and then import or export types that were merged into your assembly, but are also imported/exported by anyone outside your assembly, you will hit bad errors including InvalidCastException.

@kfertitta
Copy link
Author

kfertitta commented May 20, 2024

Thanks for the quick reply @AArnott . The gist of this thread, and others linked to it, is that VS extensions, such as ours, which are pretty complicated full-on custom project systems, increasingly need NuGet.Client functionality. The IVsXXX interfaces are, understandably, quite limited and it seems an unreasonable expectation that these interfaces track the functionality in NuGet.Client. That leaves us wondering how we get this kind of functionality. Seems like we need to somehow "participate" in whatever sharing mechanism must be going on between DNPS and the Package Manager, etc (which I've not yet studied). It's a pretty big issue for us.

@nkolev92
Copy link
Member

All APIs that the .NET Project System uses are in NuGet.VisualStudio and NuGet.VisualStudio.Contracts, so we don't really have any other integrations.

@nkolev92
Copy link
Member

That leaves us wondering how we get this kind of functionality

As far as new additions to the APIs go, our approach is to evaluate each API individually, so we'd want to make sure we have tracking issue for the exact APIs needed (for example, we can turn this issue into something like that, but I think we'd start with an explicit list of which APIs are needed).

It's worth noting that NuGet.VisualStudio and NuGet.VisualStudio.Contracts do not reference any other assemblies today, so that'd be a big departure from the current approach.

@kfertitta
Copy link
Author

So, seems that shipping nuget.exe with our extension, shelling out to it and parsing stdout is the only viable approach for anything not yet available in the VS shell APIs.

@AArnott
Copy link
Contributor

AArnott commented May 21, 2024

That isn't what I got from @nkolev92's comment, @kfertitta. It sounds like referencing NuGet.VisualStudio and NuGet.VisualStudio.Contracts and using those APIs is fair game.

@kfertitta
Copy link
Author

Correct, @AArnott . Those are definitely fair game. It's just that they're pretty limited relative to what we need in our project systems. And, as reported initially in this thread, the semver parsing doesn't work properly.

@zivkan
Copy link
Member

zivkan commented May 22, 2024

the semver parsing doesn't work properly

pedantic: the parsing conforms to SemVer v1, not SemVer v2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Functionality:SDK The NuGet client packages published to nuget.org Product:VS.Client Resolution:NotABug This issue appears to not be a bug Type:Bug
Projects
None yet
Development

No branches or pull requests

6 participants