From ade5cf669f0a01d8377033d04f69dfae4f24afa0 Mon Sep 17 00:00:00 2001 From: Michelle Yun Date: Wed, 19 Oct 2022 19:54:57 -0700 Subject: [PATCH 1/4] Nuget package versions are case insensitive --- .../PackageActions/NuGetPackageActions.cs | 2 +- .../PackageManagers/NuGetProjectManager.cs | 34 +++++++++++++++++-- .../NuGetProjectManagerTests.cs | 17 ++++++++-- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/Shared/PackageActions/NuGetPackageActions.cs b/src/Shared/PackageActions/NuGetPackageActions.cs index 8fa90fff..b9edb731 100644 --- a/src/Shared/PackageActions/NuGetPackageActions.cs +++ b/src/Shared/PackageActions/NuGetPackageActions.cs @@ -86,7 +86,7 @@ public async Task DoesPackageExistAsync( { bool exists = await resource.DoesPackageExistAsync( packageUrl.Name, - NuGetVersion.Parse(packageUrl.Version), + NuGetVersion.Parse(packageUrl.Version.ToLowerInvariant()), _sourceCacheContext, _logger, cancellationToken); diff --git a/src/Shared/PackageManagers/NuGetProjectManager.cs b/src/Shared/PackageManagers/NuGetProjectManager.cs index 35d01438..360f1e58 100644 --- a/src/Shared/PackageManagers/NuGetProjectManager.cs +++ b/src/Shared/PackageManagers/NuGetProjectManager.cs @@ -20,6 +20,7 @@ namespace Microsoft.CST.OpenSource.PackageManagers using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; + using Microsoft.Extensions.Primitives; public class NuGetProjectManager : TypedManager { @@ -149,6 +150,11 @@ private async Task GetRegistrationEndpointAsync() throw new InvalidOperationException($"Can't find the latest version of {purl}"); packageVersion = latestVersion; } + // NuGet package versions are case insensitive + else + { + packageVersion = packageVersion.ToLowerInvariant(); + } // Construct a new PackageURL that's guaranteed to have a version. PackageURL purlWithVersion = new (purl.Type, purl.Namespace, packageName, packageVersion, purl.Qualifiers, purl.Subpath); @@ -177,8 +183,8 @@ public override Uri GetPackageAbsoluteUri(PackageURL purl) throw new InvalidOperationException($"Can't find the latest version of {purl}");; // Construct a new PackageURL that's guaranteed to have a version, the latest version is used if no version was provided. - PackageURL purlWithVersion = !string.IsNullOrWhiteSpace(purl.Version) ? - purl : new PackageURL(purl.Type, purl.Namespace, purl.Name, latestVersion, purl.Qualifiers, purl.Subpath); + string guaranteedVersion = !string.IsNullOrWhiteSpace(purl.Version) ? purl.Version.ToLowerInvariant() : latestVersion; + PackageURL purlWithVersion = new PackageURL(purl.Type, purl.Namespace, purl.Name, guaranteedVersion, purl.Qualifiers, purl.Subpath); NuGetPackageVersionMetadata? packageVersionMetadata = await Actions.GetMetadataAsync(purlWithVersion, useCache: useCache); @@ -207,7 +213,28 @@ public override Uri GetPackageAbsoluteUri(PackageURL purl) return metadata; } + + /// + public override async Task PackageVersionExistsAsync(PackageURL purl, bool useCache = true) + { + Logger.Trace("PackageExists {0}", purl?.ToString()); + if (purl is null) + { + Logger.Trace("Provided PackageURL was null."); + return false; + } + + if(purl.Version.IsBlank()) + { + Logger.Trace("Provided PackageURL version was null or blank."); + return false; + } + // NuGet packages are case insensitive. Convert purl to lowercase before comparing against package versions list. + var versionLowercase = purl.Version.ToLowerInvariant(); + return (await EnumerateVersionsAsync(purl, useCache)).Contains(versionLowercase); + } + /// /// Updates the package version specific values in . /// @@ -221,9 +248,10 @@ private async Task UpdateVersionMetadata(PackageMetadata metadata, NuGetPackageV } string nameLowercase = packageVersionPackageVersionMetadata.Name.ToLowerInvariant(); + string versionLowercase = metadata.PackageVersion.ToLowerInvariant(); // Set the version specific URI values. - metadata.VersionUri = $"{metadata.PackageManagerUri}/packages/{nameLowercase}/{metadata.PackageVersion}"; + metadata.VersionUri = $"{metadata.PackageManagerUri}/packages/{nameLowercase}/{versionLowercase}"; metadata.ApiVersionUri = packageVersionPackageVersionMetadata.CatalogUri.ToString(); // Construct the artifact contents url. diff --git a/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs b/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs index c9b6707a..694ec322 100644 --- a/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs +++ b/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs @@ -31,14 +31,14 @@ public class NuGetProjectManagerTests { "https://api.nuget.org/v3/registration5-gz-semver2/razorengine/index.json", Resources.razorengine_json }, { "https://api.nuget.org/v3/catalog0/data/2022.03.11.23.17.27/razorengine.4.2.3-beta1.json", Resources.razorengine_4_2_3_beta1_json }, }.ToImmutableDictionary(); - + // Map PackageURLs to metadata as json. private readonly IDictionary _metadata = new Dictionary() { { "pkg:nuget/razorengine@4.2.3-beta1", Resources.razorengine_4_2_3_beta1_metadata_json }, { "pkg:nuget/razorengine", Resources.razorengine_latest_metadata_json }, }.ToImmutableDictionary(); - + // Map PackageURLs to the list of versions as json. private readonly IDictionary _versions = new Dictionary() { @@ -73,6 +73,19 @@ public NuGetProjectManagerTests() _projectManager = new NuGetProjectManager(".", new NuGetPackageActions(), _httpFactory); } + [DataTestMethod] + [DataRow("pkg:nuget/razorengine@4.2.3-beta1")] + [DataRow("pkg:nuget/razorengine@4.2.3-Beta1")] + public async Task PackageVersionExistsSucceeds(string purlString) + { + PackageURL purl = new(purlString); + _projectManager = new NuGetProjectManager(".", null, _httpFactory); + + bool exists = await _projectManager.PackageVersionExistsAsync(purl, useCache: false); + + Assert.IsTrue(exists); + } + [DataTestMethod] [DataRow("pkg:nuget/razorengine@4.2.3-beta1", "RazorEngine - A Templating Engine based on the Razor parser.", "Matthew Abbott, Ben Dornis, Matthias Dittrich")] // Normal package [DataRow("pkg:nuget/razorengine", "RazorEngine - A Templating Engine based on the Razor parser.", "Matthew Abbott, Ben Dornis, Matthias Dittrich", "4.5.1-alpha001")] // Normal package, no specified version From ba232caf5dc8087d2e5475ceb156ec67657f6ea0 Mon Sep 17 00:00:00 2001 From: Michelle Yun Date: Fri, 21 Oct 2022 07:58:17 -0700 Subject: [PATCH 2/4] Version dependency update and addressing comments --- src/Shared.CLI/Shared.CLI.csproj | 2 +- src/Shared/PackageManagers/NuGetProjectManager.cs | 8 ++++---- src/Shared/Shared.Lib.csproj | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Shared.CLI/Shared.CLI.csproj b/src/Shared.CLI/Shared.CLI.csproj index 52341326..62fb1e9d 100644 --- a/src/Shared.CLI/Shared.CLI.csproj +++ b/src/Shared.CLI/Shared.CLI.csproj @@ -49,7 +49,7 @@ - + diff --git a/src/Shared/PackageManagers/NuGetProjectManager.cs b/src/Shared/PackageManagers/NuGetProjectManager.cs index 360f1e58..83ac3972 100644 --- a/src/Shared/PackageManagers/NuGetProjectManager.cs +++ b/src/Shared/PackageManagers/NuGetProjectManager.cs @@ -183,8 +183,8 @@ public override Uri GetPackageAbsoluteUri(PackageURL purl) throw new InvalidOperationException($"Can't find the latest version of {purl}");; // Construct a new PackageURL that's guaranteed to have a version, the latest version is used if no version was provided. - string guaranteedVersion = !string.IsNullOrWhiteSpace(purl.Version) ? purl.Version.ToLowerInvariant() : latestVersion; - PackageURL purlWithVersion = new PackageURL(purl.Type, purl.Namespace, purl.Name, guaranteedVersion, purl.Qualifiers, purl.Subpath); + PackageURL purlWithVersion = !string.IsNullOrWhiteSpace(purl.Version) ? + purl : new PackageURL(purl.Type, purl.Namespace, purl.Name, latestVersion, purl.Qualifiers, purl.Subpath); NuGetPackageVersionMetadata? packageVersionMetadata = await Actions.GetMetadataAsync(purlWithVersion, useCache: useCache); @@ -231,8 +231,8 @@ public override async Task PackageVersionExistsAsync(PackageURL purl, bool } // NuGet packages are case insensitive. Convert purl to lowercase before comparing against package versions list. - var versionLowercase = purl.Version.ToLowerInvariant(); - return (await EnumerateVersionsAsync(purl, useCache)).Contains(versionLowercase); + StringComparer invICCmp = StringComparer.InvariantCultureIgnoreCase; + return (await EnumerateVersionsAsync(purl, useCache)).Contains(purl.Version, invICCmp); } /// diff --git a/src/Shared/Shared.Lib.csproj b/src/Shared/Shared.Lib.csproj index 54ce7e81..b34c2110 100644 --- a/src/Shared/Shared.Lib.csproj +++ b/src/Shared/Shared.Lib.csproj @@ -42,7 +42,7 @@ - + From a98426ea7b80744b31fd760bb74585ef2e56e554 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Fri, 21 Oct 2022 09:10:38 -0700 Subject: [PATCH 3/4] Suggested Changes for 358 --- .../PackageManagers/NuGetProjectManager.cs | 16 +++------------- .../NuGetProjectManagerTests.cs | 1 + 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Shared/PackageManagers/NuGetProjectManager.cs b/src/Shared/PackageManagers/NuGetProjectManager.cs index 83ac3972..f34cdb52 100644 --- a/src/Shared/PackageManagers/NuGetProjectManager.cs +++ b/src/Shared/PackageManagers/NuGetProjectManager.cs @@ -150,12 +150,6 @@ private async Task GetRegistrationEndpointAsync() throw new InvalidOperationException($"Can't find the latest version of {purl}"); packageVersion = latestVersion; } - // NuGet package versions are case insensitive - else - { - packageVersion = packageVersion.ToLowerInvariant(); - } - // Construct a new PackageURL that's guaranteed to have a version. PackageURL purlWithVersion = new (purl.Type, purl.Namespace, packageName, packageVersion, purl.Qualifiers, purl.Subpath); @@ -230,9 +224,8 @@ public override async Task PackageVersionExistsAsync(PackageURL purl, bool return false; } - // NuGet packages are case insensitive. Convert purl to lowercase before comparing against package versions list. - StringComparer invICCmp = StringComparer.InvariantCultureIgnoreCase; - return (await EnumerateVersionsAsync(purl, useCache)).Contains(purl.Version, invICCmp); + // NuGet packages are case insensitive. + return (await EnumerateVersionsAsync(purl, useCache)).Contains(purl.Version, StringComparer.InvariantCultureIgnoreCase); } /// @@ -247,11 +240,8 @@ private async Task UpdateVersionMetadata(PackageMetadata metadata, NuGetPackageV return; } - string nameLowercase = packageVersionPackageVersionMetadata.Name.ToLowerInvariant(); - string versionLowercase = metadata.PackageVersion.ToLowerInvariant(); - // Set the version specific URI values. - metadata.VersionUri = $"{metadata.PackageManagerUri}/packages/{nameLowercase}/{versionLowercase}"; + metadata.VersionUri = $"{metadata.PackageManagerUri}/packages/{packageVersionPackageVersionMetadata.Name}/{metadata.PackageVersion}"; metadata.ApiVersionUri = packageVersionPackageVersionMetadata.CatalogUri.ToString(); // Construct the artifact contents url. diff --git a/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs b/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs index 694ec322..1b49e4dc 100644 --- a/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs +++ b/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs @@ -76,6 +76,7 @@ public NuGetProjectManagerTests() [DataTestMethod] [DataRow("pkg:nuget/razorengine@4.2.3-beta1")] [DataRow("pkg:nuget/razorengine@4.2.3-Beta1")] + [DataRow("pkg:nuget/rAzOrEnGiNe@4.2.3-Beta1")] public async Task PackageVersionExistsSucceeds(string purlString) { PackageURL purl = new(purlString); From 22db4636df17ebca5388acd9c10e18840d17fd01 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Sat, 22 Oct 2022 10:09:38 -0700 Subject: [PATCH 4/4] A few fixes I missed in my first pass. --- .../PackageActions/NuGetPackageActions.cs | 2 +- .../PackageManagers/NuGetProjectManager.cs | 26 +++++++++---------- .../NuGetProjectManagerTests.cs | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Shared/PackageActions/NuGetPackageActions.cs b/src/Shared/PackageActions/NuGetPackageActions.cs index b9edb731..8fa90fff 100644 --- a/src/Shared/PackageActions/NuGetPackageActions.cs +++ b/src/Shared/PackageActions/NuGetPackageActions.cs @@ -86,7 +86,7 @@ public async Task DoesPackageExistAsync( { bool exists = await resource.DoesPackageExistAsync( packageUrl.Name, - NuGetVersion.Parse(packageUrl.Version.ToLowerInvariant()), + NuGetVersion.Parse(packageUrl.Version), _sourceCacheContext, _logger, cancellationToken); diff --git a/src/Shared/PackageManagers/NuGetProjectManager.cs b/src/Shared/PackageManagers/NuGetProjectManager.cs index f34cdb52..ff7c119e 100644 --- a/src/Shared/PackageManagers/NuGetProjectManager.cs +++ b/src/Shared/PackageManagers/NuGetProjectManager.cs @@ -232,8 +232,8 @@ public override async Task PackageVersionExistsAsync(PackageURL purl, bool /// Updates the package version specific values in . /// /// The object to update with the values for this version. - /// The representing this version. - private async Task UpdateVersionMetadata(PackageMetadata metadata, NuGetPackageVersionMetadata packageVersionPackageVersionMetadata) + /// The representing this version. + private async Task UpdateVersionMetadata(PackageMetadata metadata, NuGetPackageVersionMetadata packageVersionMetadata) { if (metadata.PackageVersion is null) { @@ -241,45 +241,45 @@ private async Task UpdateVersionMetadata(PackageMetadata metadata, NuGetPackageV } // Set the version specific URI values. - metadata.VersionUri = $"{metadata.PackageManagerUri}/packages/{packageVersionPackageVersionMetadata.Name}/{metadata.PackageVersion}"; - metadata.ApiVersionUri = packageVersionPackageVersionMetadata.CatalogUri.ToString(); + metadata.VersionUri = $"{metadata.PackageManagerUri}/packages/{packageVersionMetadata.Name}/{metadata.PackageVersion}"; + metadata.ApiVersionUri = packageVersionMetadata.CatalogUri.ToString(); // Construct the artifact contents url. - metadata.VersionDownloadUri = GetNupkgUrl(packageVersionPackageVersionMetadata.Name, metadata.PackageVersion); + metadata.VersionDownloadUri = GetNupkgUrl(packageVersionMetadata.Name, metadata.PackageVersion); // TODO: size and hash // Homepage url - metadata.Homepage = packageVersionPackageVersionMetadata.ProjectUrl?.ToString(); + metadata.Homepage = packageVersionMetadata.ProjectUrl?.ToString(); // Authors and Maintainers - UpdateMetadataAuthorsAndMaintainers(metadata, packageVersionPackageVersionMetadata); + UpdateMetadataAuthorsAndMaintainers(metadata, packageVersionMetadata); // Repository await UpdateMetadataRepository(metadata); // Dependencies - IList dependencyGroups = packageVersionPackageVersionMetadata.DependencySets.ToList(); + IList dependencyGroups = packageVersionMetadata.DependencySets.ToList(); metadata.Dependencies ??= dependencyGroups.SelectMany(group => group.Packages, (dependencyGroup, package) => new { dependencyGroup, package}) .Select(dependencyGroupAndPackage => new Dependency() { Package = dependencyGroupAndPackage.package.ToString(), Framework = dependencyGroupAndPackage.dependencyGroup.TargetFramework?.ToString()}) .ToList(); // Keywords - metadata.Keywords = new List(packageVersionPackageVersionMetadata.Tags.Split(", ")); + metadata.Keywords = new List(packageVersionMetadata.Tags.Split(", ")); // Licenses - if (packageVersionPackageVersionMetadata.LicenseMetadata is not null) + if (packageVersionMetadata.LicenseMetadata is not null) { metadata.Licenses ??= new List(); metadata.Licenses.Add(new License() { - Name = packageVersionPackageVersionMetadata.LicenseMetadata.License, - Url = packageVersionPackageVersionMetadata.LicenseMetadata.LicenseUrl.ToString() + Name = packageVersionMetadata.LicenseMetadata.License, + Url = packageVersionMetadata.LicenseMetadata.LicenseUrl.ToString() }); } // publishing info - metadata.UploadTime = packageVersionPackageVersionMetadata.Published?.DateTime; + metadata.UploadTime = packageVersionMetadata.Published?.DateTime; } /// diff --git a/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs b/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs index 1b49e4dc..48ea1c80 100644 --- a/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs +++ b/src/oss-tests/ProjectManagerTests/NuGetProjectManagerTests.cs @@ -77,7 +77,7 @@ public NuGetProjectManagerTests() [DataRow("pkg:nuget/razorengine@4.2.3-beta1")] [DataRow("pkg:nuget/razorengine@4.2.3-Beta1")] [DataRow("pkg:nuget/rAzOrEnGiNe@4.2.3-Beta1")] - public async Task PackageVersionExistsSucceeds(string purlString) + public async Task TestNugetCaseInsensitiveHandlingPackageExistsSucceeds(string purlString) { PackageURL purl = new(purlString); _projectManager = new NuGetProjectManager(".", null, _httpFactory);