Devolutions / Devolutions/UniGetUI
[ENHANCEMENT] Migrate NuGet V2 APIs to V3 APIs
- Dominant language
- C#
- Stars
- 26.1k
- Forks
- 924
- Avg merge
- 15h 52m
- Merged PRs (30d)
- 52
Description
### Please confirm these before moving forward.
- [x] I have searched for my feature proposal and have not found a work-in-progress/duplicate/resolved/discarded issue.
- [x] This improvement refers to an existing feature. If you want to suggest a new feature, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=new-feature&projects=&template=feature-request.yml&title=%5BFEATURE+REQUEST%5D+%28Enter+your+description+here%29).
- [x] This improvement is not a bug. If you want to report a bug, please use [this template](https://github.com/Devolutions/UniGetUI/issues/new?labels=bug&projects=&template=bug-issue.yml&title=%5BBUG%5D+%28Enter+your+description+here%29).
### Describe the improvement
Hi there I'm Charles Bissonnette, the Engineering Manager for http://NuGet.Org and I would like to bring this issue to the team. UniGetUI is still relying on V2 NuGet API and our telemetry shows that UniGetUI ends up consuming a huge portion of DataBase's DTU. It is important that you migrate UniGetUI's direct NuGet V2/OData integration to NuGet V3 for the generic NuGet-backed managers (.NET Tool, Windows PowerShell, and PowerShell 7), while preserving compatibility for feeds that cannot provide V3 resources.
## Current implementation
The shared implementation is primarily in:
- `src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGet.cs`
- `src/UniGetUI.PackageEngine.Managers.Generic.NuGet/Internal/NuGetManifestLoader.cs`
- `src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGetDetailsHelper.cs`
It currently uses V2/OData endpoints such as `Search()`, `Packages()`, `FindPackagesById()`, `Packages(Id=...,Version=...)`, and `GetUpdates()`, and parses Atom/OData XML responses.
## Proposed implementation steps
1. **Inventory and define compatibility boundaries**
- Enumerate every direct V2 URL, OData query, XML response parser, and test fixture in the generic NuGet implementation.
- Keep Chocolatey's `choco` CLI integration separate; do not convert it solely because Chocolatey sources use `/api/v2/`.
- Identify which configured sources support a NuGet V3 service index and define the fallback behavior for sources that do not.
2. **Introduce a NuGet V3 resource-index client**
- Add a focused internal client/abstraction that loads `{source}/index.json`.
- Parse the service index and select resources by advertised `@type`, including `SearchQueryService`, `RegistrationsBaseUrl`, and `PackageBaseAddress/3.0.0` (or compatible versions).
- Normalize source URLs and cache the resolved resource index per source for the lifetime of the relevant operation/session.
- Handle unavailable or malformed indexes with useful logging and a controlled V2 fallback where supported.
3. **Migrate package search**
- Replace V2 `Search()` and `Packages()` URL construction in `BaseNuGet.FindPackages_UnSafe()` with the V3 SearchQueryService.
- Send the query using V3 parameters (`q`, `skip`, `take`, `prerelease`, and `semVerLevel` where supported).
- Deserialize V3 JSON instead of extracting `` elements with regular expressions.
- Preserve the existing result limit, pagination, prerelease behavior, source association, duplicate handling, and highest-version selection.
- Preserve the intent of `UseSubstringSearch`; use exact package-ID/version resources where a search endpoint cannot provide equivalent behavior.
4. **Replace batch update lookup**
- Remove the dependency on V2 `GetUpdates()`, which has no direct V3 equivalent.
- For each installed package/source group, obtain available versions and relevant registration metadata using V3 PackageBaseAddress and/or RegistrationsBaseUrl resources.
- Compare versions locally using the existing version semantics, including prerelease filtering and ignoring versions that are not newer.
- Preserve package scope, source identity, update dates, logging, and failure reporting.
- Add bounded concurrency and caching so update checks do not create unbounded request fan-out.
5. **Migrate package versions and package content URLs**
- Replace `FindPackagesById()` in `BaseNuGetDetailsHelper` with the V3 flat-container version index:
`{packageBaseAddress}/{lowercase-id}/index.json`.
- Update `NuGetManifestLoader.GetNuPkgUrl()` to use the V3 flat-container package path:
`{packageBaseAddress}/{lowercase-id}/{lowercase-version}/{lowercase-id}.{lowercase-version}.nupkg`.
- Account for normalized lowercase IDs and versions, URL escaping, and feeds with nonstandard resource URL layouts.
- Add tests for IDs and versions containing characters that require normalization or escaping.
6. **Migrate package metadata and details**
- Replace the V2 `Packages(Id='...',Version='...')` manifest URL in `NuGetManifestLoader` with V3 registration metadata and/or the package `.nuspec` URL.
- Adapt `BaseNuGetDetailsHelper` to consume V3 JSON metadata and package `.nuspec` content rather than depending on V2 Atom fields such as ``, ``, and ``.
- Preserve descriptions, authors/publishers, licenses, release notes, update dates, dependencies, icon URLs, installer URLs, installer sizes, and cached manifest behavior.
- Prefer structured parsing over regular-expression parsing where practical, while retaining robust handling for incomplete package metadata.
7. **Update manager source definitions**
- Change the .NET Tool default and known source to `https://api.nuget.org/v3/index.json`.
- Change the PowerShell Gallery sources to their supported V3 service-index endpoint, confirming the endpoint and behavior for both Windows PowerShell and PowerShell 7.
- Preserve custom-source support and V2 fallback for feeds that do not expose the required V3 resources.
- Do not change Chocolatey's source behavior unless a compatible V3 migration is explicitly validated.
8. **Add migration and regression tests**
- Add HTTP fixture tests for service-index parsing and resource selection.
- Add tests for V3 search JSON, pagination, prerelease filtering, duplicate versions, and malformed responses.
- Add tests for flat-container version enumeration and package URL generation.
- Add tests for registration metadata and `.nuspec` parsing, including dependencies, icons, licenses, and missing fields.
- Add tests for local update comparison and bounded/cached requests.
- Retain V2 fallback tests for custom feeds where fallback is implemented.
- Update existing tests that assert V2 URLs, V2 XML, or V2-specific behavior.
9. **Documentation and rollout**
- Update code comments and documentation that describe the integration as V2/OData-specific.
- Document supported V3 resources and the fallback behavior.
- Run the relevant test projects, formatting checks, and build checks.
- Review behavior against nuget.org, PowerShell Gallery, a V2-only custom feed, and a custom V3 feed before removing any fallback code.
## Acceptance criteria
- The .NET Tool, Windows PowerShell, and PowerShell 7 managers use NuGet V3 resources for supported feeds.
- Search, version listing, package details, package downloads, icons, dependencies, and update detection continue to work.
- Prerelease filtering, pagination, caching, logging, proxy behavior, and source identity remain functional.
- V2-only custom sources do not regress when fallback is available; unsupported feeds fail clearly when neither API is usable.
- Chocolatey's CLI-based behavior remains unchanged.
- Automated tests cover V3 resource discovery, search, metadata, versions, updates, content URLs, and fallback behavior.
### Describe how this improvement could help users
Moving from NuGet V2/OData to V3 would align UniGetUI with the current NuGet server API model, avoid dependence on legacy XML/OData endpoints, improve interoperability with modern NuGet-compatible feeds, and provide a more maintainable foundation for search, metadata, package downloads, and update detection. It should also make feed capabilities explicit through service-index discovery and allow UniGetUI to retain compatibility with older custom repositories where possible.
Contributor guide
Assessment
This issue has not been assessed yet.