Skip to content

Commit b3d7dc9

Browse files
authored
Introduce a version-specific ID column for display purposes (#8504)
* Add new ID column to packages table * Add field length Progress on #3349
1 parent c7a2355 commit b3d7dc9

14 files changed

Lines changed: 356 additions & 37 deletions

File tree

src/NuGet.Services.Entities/Package.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace NuGet.Services.Entities
1212
public class Package
1313
: IPackageEntity
1414
{
15+
private string _id;
1516

1617
#pragma warning disable 618 // TODO: remove Package.Authors completely once production services definitely no longer need it
1718
public Package()
@@ -264,7 +265,17 @@ public bool HasEmbeddedReadme
264265

265266
public virtual ICollection<SymbolPackage> SymbolPackages { get; set; }
266267

267-
public string Id => PackageRegistration.Id;
268+
/// <summary>
269+
/// The package ID with casing specific to this version if available, otherwise it will fallback to the ID on
270+
/// the package registration. WARNING: this property should not be used for comparisons in LINQ to SQL because
271+
/// it may be null sometimes. Use <see cref="PackageRegistration.Id"/> instead.
272+
/// </summary>
273+
[StringLength(Constants.MaxPackageIdLength)]
274+
public string Id
275+
{
276+
get => _id ?? PackageRegistration?.Id;
277+
set => _id = value;
278+
}
268279

269280
public EmbeddedLicenseFileType EmbeddedLicenseType { get; set; }
270281

src/NuGetGallery.Core/Services/CorePackageService.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,17 @@ public virtual async Task UpdateIsLatestAsync(PackageRegistration packageRegistr
202202
}
203203
}
204204

205+
// Update the ID on the PackageRegistration if the value differs only by case from the absolute latest
206+
// (stable or prerelease) SemVer 2.0.0 package. This is a best effort flow because in general package IDs
207+
// are compared in a case-insensitive manner and therefore the PackageRegistration ID casing should not
208+
// have any functional impact. The specific casing is only a display concern.
209+
if (latestSemVer2Package != null
210+
&& string.Equals(latestSemVer2Package.Id, packageRegistration.Id, StringComparison.OrdinalIgnoreCase)
211+
&& !string.Equals(latestSemVer2Package.Id, packageRegistration.Id, StringComparison.Ordinal))
212+
{
213+
packageRegistration.Id = latestSemVer2Package.Id;
214+
}
215+
205216
if (commitChanges)
206217
{
207218
await _packageRepository.CommitChangesAsync();

src/NuGetGallery.Services/PackageManagement/PackageService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,8 @@ public virtual Package EnrichPackageFromNuGetPackage(
636636
PackageStreamMetadata packageStreamMetadata,
637637
User user)
638638
{
639+
package.Id = packageMetadata.Id;
640+
639641
// Version must always be the exact string from the nuspec, which OriginalVersion will return to us.
640642
// However, we do also store a normalized copy for looking up later.
641643
package.Version = packageMetadata.Version.OriginalVersion;

src/NuGetGallery/Areas/Admin/Controllers/DeleteController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ private DeleteSearchResult CreateDeleteSearchResult(Package package)
109109
{
110110
return new DeleteSearchResult
111111
{
112-
PackageId = package.PackageRegistration.Id,
112+
PackageId = package.Id,
113113
PackageVersionNormalized = !string.IsNullOrEmpty(package.NormalizedVersion)
114114
? package.NormalizedVersion
115115
: NuGetVersion.Parse(package.Version).ToNormalizedString(),

src/NuGetGallery/Helpers/ViewModelExtensions/PackageViewModelFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public PackageViewModel Setup(PackageViewModel viewModel, Package package)
3535

3636
viewModel.FullVersion = NuGetVersionFormatter.ToFullString(package.Version);
3737

38-
viewModel.Id = package.PackageRegistration.Id;
38+
viewModel.Id = package.Id;
3939
viewModel.Version = String.IsNullOrEmpty(package.NormalizedVersion) ?
4040
NuGetVersionFormatter.Normalize(package.Version) :
4141
package.NormalizedVersion;

src/NuGetGallery/Infrastructure/LuceneDocumentFactory.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,23 @@ public Document Create(Package package)
4949

5050
// Style 1: As-Is Id, no tokenizing (so you can search using dot or dash-joined terms)
5151
// Boost this one
52-
field = new Field("Id", package.PackageRegistration.Id, Field.Store.NO, Field.Index.ANALYZED);
52+
field = new Field("Id", package.Id, Field.Store.NO, Field.Index.ANALYZED);
5353
document.Add(field);
5454

5555
// Style 2: dot+dash tokenized (so you can search using undotted terms)
56-
field = new Field("Id", SplitId(package.PackageRegistration.Id), Field.Store.NO, Field.Index.ANALYZED);
56+
field = new Field("Id", SplitId(package.Id), Field.Store.NO, Field.Index.ANALYZED);
5757
field.Boost = 0.8f;
5858
document.Add(field);
5959

6060
// Style 3: camel-case tokenized (so you can search using parts of the camelCasedWord).
6161
// De-boosted since matches are less likely to be meaningful
62-
field = new Field("Id", CamelSplitId(package.PackageRegistration.Id), Field.Store.NO, Field.Index.ANALYZED);
62+
field = new Field("Id", CamelSplitId(package.Id), Field.Store.NO, Field.Index.ANALYZED);
6363
field.Boost = 0.25f;
6464
document.Add(field);
6565

6666
// If an element does not have a Title, fall back to Id, same as the website.
6767
var workingTitle = String.IsNullOrEmpty(package.Title)
68-
? package.PackageRegistration.Id
68+
? package.Id
6969
: package.Title;
7070

7171
// As-Is (stored for search results)
@@ -113,7 +113,7 @@ public Document Create(Package package)
113113
document.Add(new Field("FlattenedPackageTypes", package.FlattenedPackageTypes.ToStringSafe(), Field.Store.YES, Field.Index.NO));
114114
document.Add(new Field("Hash", package.Hash.ToStringSafe(), Field.Store.YES, Field.Index.NO));
115115
document.Add(new Field("HashAlgorithm", package.HashAlgorithm.ToStringSafe(), Field.Store.YES, Field.Index.NO));
116-
document.Add(new Field("Id-Original", package.PackageRegistration.Id, Field.Store.YES, Field.Index.NO));
116+
document.Add(new Field("Id-Original", package.Id, Field.Store.YES, Field.Index.NO));
117117
document.Add(new Field("IsVerified-Original", package.PackageRegistration.IsVerified.ToString(), Field.Store.YES, Field.Index.NO));
118118
document.Add(new Field("LastUpdated", package.LastUpdated.ToString(CultureInfo.InvariantCulture), Field.Store.YES, Field.Index.NO));
119119
if (package.LastEdited != null)

src/NuGetGallery/Migrations/202104062157118_AddVersionSpecificId.Designer.cs

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace NuGetGallery.Migrations
2+
{
3+
using System;
4+
using System.Data.Entity.Migrations;
5+
6+
public partial class AddVersionSpecificId : DbMigration
7+
{
8+
public override void Up()
9+
{
10+
AddColumn("dbo.Packages", "Id", c => c.String(maxLength: 128));
11+
}
12+
13+
public override void Down()
14+
{
15+
DropColumn("dbo.Packages", "Id");
16+
}
17+
}
18+
}

src/NuGetGallery/Migrations/202104062157118_AddVersionSpecificId.resx

Lines changed: 126 additions & 0 deletions
Large diffs are not rendered by default.

src/NuGetGallery/NuGetGallery.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@
303303
<Compile Include="Migrations\202007220027197_AddEmbeddedReadmeTypeColumn.designer.cs">
304304
<DependentUpon>202007220027197_AddEmbeddedReadmeTypeColumn.cs</DependentUpon>
305305
</Compile>
306+
<Compile Include="Migrations\202104062157118_AddVersionSpecificId.cs" />
307+
<Compile Include="Migrations\202104062157118_AddVersionSpecificId.designer.cs">
308+
<DependentUpon>202104062157118_AddVersionSpecificId.cs</DependentUpon>
309+
</Compile>
306310
<Compile Include="Modules\CookieComplianceHttpModule.cs" />
307311
<Compile Include="RequestModels\DeletePackagesApiRequest.cs" />
308312
<Compile Include="Services\ImageDomainValidator.cs" />
@@ -1640,6 +1644,9 @@
16401644
<EmbeddedResource Include="Migrations\202007220027197_AddEmbeddedReadmeTypeColumn.resx">
16411645
<DependentUpon>202007220027197_AddEmbeddedReadmeTypeColumn.cs</DependentUpon>
16421646
</EmbeddedResource>
1647+
<EmbeddedResource Include="Migrations\202104062157118_AddVersionSpecificId.resx">
1648+
<DependentUpon>202104062157118_AddVersionSpecificId.cs</DependentUpon>
1649+
</EmbeddedResource>
16431650
<EmbeddedResource Include="OData\QueryAllowed\Data\apiv1packages.json" />
16441651
<EmbeddedResource Include="OData\QueryAllowed\Data\apiv1search.json" />
16451652
<EmbeddedResource Include="OData\QueryAllowed\Data\apiv2getupdates.json" />

0 commit comments

Comments
 (0)