Skip to content

Commit cad6c08

Browse files
author
Scott Bommarito
authored
Introduce package deprecation entities and migration (#6820)
1 parent ee8b51e commit cad6c08

14 files changed

Lines changed: 533 additions & 0 deletions

src/NuGet.Services.Entities/NuGet.Services.Entities.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
<Compile Include="PackageAuthor.cs" />
6868
<Compile Include="PackageDelete.cs" />
6969
<Compile Include="PackageDependency.cs" />
70+
<Compile Include="PackageDeprecation.cs" />
71+
<Compile Include="PackageDeprecationStatus.cs" />
7072
<Compile Include="PackageEditReadMeState.cs" />
7173
<Compile Include="PackageFramework.cs" />
7274
<Compile Include="PackageHistory.cs" />

src/NuGet.Services.Entities/Package.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.ComponentModel.DataAnnotations;
77
using System.ComponentModel.DataAnnotations.Schema;
8+
using System.Linq;
89

910
namespace NuGet.Services.Entities
1011
{
@@ -22,6 +23,8 @@ public Package()
2223
PackageTypes = new HashSet<PackageType>();
2324
SupportedFrameworks = new HashSet<PackageFramework>();
2425
SymbolPackages = new HashSet<SymbolPackage>();
26+
Deprecations = new HashSet<PackageDeprecation>();
27+
AlternativeOf = new HashSet<PackageDeprecation>();
2528
Listed = true;
2629
}
2730
#pragma warning restore 618
@@ -251,5 +254,22 @@ public bool HasReadMe
251254

252255
[StringLength(500)]
253256
public string LicenseExpression { get; set; }
257+
258+
/// <summary>
259+
/// Gets and sets the deprecations associated with this package.
260+
/// </summary>
261+
/// <remarks>
262+
/// In the future, a package may have multiple deprecations associated with it, one visible and others hidden.
263+
/// The visible deprecation will be the deprecation shown in the UI to users.
264+
/// The hidden deprecations will consist of information about the package that we recommend package owners apply to their package.
265+
/// For now, we only support a single deprecation per package (the visible deprecation).
266+
/// </remarks>
267+
public virtual ICollection<PackageDeprecation> Deprecations { get; set; }
268+
269+
/// <summary>
270+
/// Gets and sets the list of deprecations that recommend this package as an alternative.
271+
/// See <see cref="PackageDeprecation.AlternatePackage"/>.
272+
/// </summary>
273+
public virtual ICollection<PackageDeprecation> AlternativeOf { get; set; }
254274
}
255275
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.ComponentModel.DataAnnotations;
6+
using System.ComponentModel.DataAnnotations.Schema;
7+
8+
namespace NuGet.Services.Entities
9+
{
10+
/// <summary>
11+
/// Represents a package deprecation.
12+
/// </summary>
13+
public class PackageDeprecation
14+
: IEntity
15+
{
16+
/// <summary>
17+
/// Gets or sets the primary key for the entity.
18+
/// </summary>
19+
public int Key { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets the package affected by this deprecation.
23+
/// </summary>
24+
public virtual Package Package { get; set; }
25+
26+
/// <summary>
27+
/// Gets or sets the key of the package affected by this deprecation.
28+
/// </summary>
29+
[Index(IsUnique = true)]
30+
public int PackageKey { get; set; }
31+
32+
/// <summary>
33+
/// Gets or sets the status of this deprecation.
34+
/// </summary>
35+
/// <remarks>
36+
/// A <see cref="PackageDeprecation"/> with a <see cref="PackageDeprecationStatus"/> of <see cref="PackageDeprecationStatus.NotDeprecated"/> is meaningless, so <see cref="Status"/> must be at least <c>1</c>.
37+
/// </remarks>
38+
[Range(1, int.MaxValue)]
39+
public PackageDeprecationStatus Status { get; set; }
40+
41+
/// <summary>
42+
/// Gets or sets the alternate package registration entity.
43+
/// It is recommended that users use this package registration instead of the deprecated package.
44+
/// </summary>
45+
public virtual PackageRegistration AlternatePackageRegistration { get; set; }
46+
47+
/// <summary>
48+
/// Gets or sets the alternate package registration entity key.
49+
/// It is recommended that users use this package registration instead of the deprecated package.
50+
/// </summary>
51+
public int? AlternatePackageRegistrationKey { get; set; }
52+
53+
/// <summary>
54+
/// Gets or sets the alternate package entity.
55+
/// It is recommended that users use this package instead of the deprecated package.
56+
/// </summary>
57+
public virtual Package AlternatePackage { get; set; }
58+
59+
/// <summary>
60+
/// Gets or sets the alternate package entity key.
61+
/// It is recommended that users use this package instead of the deprecated package.
62+
/// </summary>
63+
public int? AlternatePackageKey { get; set; }
64+
65+
/// <summary>
66+
/// Gets or sets the user that executed the package deprecation.
67+
/// </summary>
68+
public virtual User DeprecatedByUser { get; set; }
69+
70+
/// <summary>
71+
/// Gets or sets the key of the user that executed the package deprecation.
72+
/// </summary>
73+
public int? DeprecatedByUserKey { get; set; }
74+
75+
/// <summary>
76+
/// The date when the package was deprecated.
77+
/// </summary>
78+
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
79+
public DateTime DeprecatedOn { get; set; }
80+
81+
/// <summary>
82+
/// Gets or sets the user-provided custom message for this package deprecation.
83+
/// </summary>
84+
public string CustomMessage { get; set; }
85+
86+
/// <summary>
87+
/// Gets or sets the CVSS rating for this deprecation.
88+
/// </summary>
89+
/// <remarks>
90+
/// CVSS ratings are from 0.0 to 10.0 and have a single point of precision.
91+
/// </remarks>
92+
[Range(0, 10)]
93+
public decimal? CVSSRating { get; set; }
94+
95+
/// <summary>
96+
/// Gets or sets the serialized JSON object containing an array of CVE ID's related to this deprecation.
97+
/// The JSON object should have a version property that defines the version of its schema.
98+
/// </summary>
99+
public string CVEIds { get; set; }
100+
101+
/// <summary>
102+
/// Gets or sets the serialized JSON object containing an array of CWE ID's related to this deprecation.
103+
/// The JSON object should have a version property that defines the version of its schema.
104+
/// </summary>
105+
public string CWEIds { get; set; }
106+
}
107+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace NuGet.Services.Entities
7+
{
8+
/// <summary>
9+
/// Indicates package deprecation status and reason(s).
10+
/// </summary>
11+
[Flags]
12+
public enum PackageDeprecationStatus
13+
{
14+
/// <summary>
15+
/// The package is not deprecated.
16+
/// </summary>
17+
NotDeprecated = 0,
18+
19+
/// <summary>
20+
/// The package is deprecated because of some other undefined reason.
21+
/// </summary>
22+
Other = 1,
23+
24+
/// <summary>
25+
/// The package is deprecated because it is legacy and no longer maintained.
26+
/// </summary>
27+
Legacy = 2,
28+
29+
/// <summary>
30+
/// The package is deprecated because it is vulnerable.
31+
/// </summary>
32+
Vulnerable = 4
33+
}
34+
}

src/NuGet.Services.Entities/PackageRegistration.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public PackageRegistration()
1515
Packages = new HashSet<Package>();
1616
ReservedNamespaces = new HashSet<ReservedNamespace>();
1717
RequiredSigners = new HashSet<User>();
18+
AlternativeOf = new HashSet<PackageDeprecation>();
1819
}
1920

2021
[StringLength(Constants.MaxPackageIdLength)]
@@ -37,5 +38,11 @@ public PackageRegistration()
3738
public virtual ICollection<User> RequiredSigners { get; set; }
3839

3940
public int Key { get; set; }
41+
42+
/// <summary>
43+
/// Gets and sets the list of deprecations that recommend this package registration as an alternative.
44+
/// See <see cref="PackageDeprecation.AlternatePackageRegistration"/>.
45+
/// </summary>
46+
public virtual ICollection<PackageDeprecation> AlternativeOf { get; set; }
4047
}
4148
}

src/NuGetGallery.Core/Entities/EntitiesContext.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,37 @@ protected override void OnModelCreating(DbModelBuilder modelBuilder)
367367
modelBuilder.Entity<SymbolPackage>()
368368
.Property(s => s.RowVersion)
369369
.IsRowVersion();
370+
371+
modelBuilder.Entity<PackageDeprecation>()
372+
.HasKey(d => d.Key);
373+
374+
modelBuilder.Entity<Package>()
375+
.HasMany(p => p.Deprecations)
376+
.WithRequired(d => d.Package)
377+
.HasForeignKey(d => d.PackageKey)
378+
.WillCascadeOnDelete(true);
379+
380+
modelBuilder.Entity<Package>()
381+
.HasMany(p => p.AlternativeOf)
382+
.WithOptional(d => d.AlternatePackage)
383+
.HasForeignKey(d => d.AlternatePackageKey)
384+
.WillCascadeOnDelete(false);
385+
386+
modelBuilder.Entity<PackageRegistration>()
387+
.HasMany(p => p.AlternativeOf)
388+
.WithOptional(d => d.AlternatePackageRegistration)
389+
.HasForeignKey(d => d.AlternatePackageRegistrationKey)
390+
.WillCascadeOnDelete(false);
391+
392+
modelBuilder.Entity<PackageDeprecation>()
393+
.HasOptional(d => d.DeprecatedByUser)
394+
.WithMany()
395+
.HasForeignKey(d => d.DeprecatedByUserKey)
396+
.WillCascadeOnDelete(false);
397+
398+
modelBuilder.Entity<PackageDeprecation>()
399+
.Property(v => v.CVSSRating)
400+
.HasPrecision(3, 1);
370401
}
371402
#pragma warning restore 618
372403
}

src/NuGetGallery/Migrations/201901142143060_AddDeprecationEntities.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: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace NuGetGallery.Migrations
2+
{
3+
using System;
4+
using System.Data.Entity.Migrations;
5+
6+
public partial class AddDeprecationEntities : DbMigration
7+
{
8+
public override void Up()
9+
{
10+
CreateTable(
11+
"dbo.PackageDeprecations",
12+
c => new
13+
{
14+
Key = c.Int(nullable: false, identity: true),
15+
PackageKey = c.Int(nullable: false),
16+
Status = c.Int(nullable: false),
17+
AlternatePackageRegistrationKey = c.Int(),
18+
AlternatePackageKey = c.Int(),
19+
DeprecatedByUserKey = c.Int(),
20+
DeprecatedOn = c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"),
21+
CustomMessage = c.String(),
22+
CVSSRating = c.Decimal(precision: 3, scale: 1),
23+
CVEIds = c.String(),
24+
CWEIds = c.String(),
25+
})
26+
.PrimaryKey(t => t.Key)
27+
.ForeignKey("dbo.Packages", t => t.AlternatePackageKey)
28+
.ForeignKey("dbo.Packages", t => t.PackageKey, cascadeDelete: true)
29+
.ForeignKey("dbo.Users", t => t.DeprecatedByUserKey)
30+
.ForeignKey("dbo.PackageRegistrations", t => t.AlternatePackageRegistrationKey)
31+
.Index(t => t.PackageKey, unique: true)
32+
.Index(t => t.AlternatePackageRegistrationKey)
33+
.Index(t => t.AlternatePackageKey)
34+
.Index(t => t.DeprecatedByUserKey);
35+
36+
Sql("ALTER TABLE [dbo].[PackageDeprecations] ADD CONSTRAINT [dbo.PackageDeprecations_CVSSRating] CHECK ([CVSSRating] >= 0 AND [CVSSRating] <= 10)");
37+
38+
}
39+
40+
public override void Down()
41+
{
42+
DropForeignKey("dbo.PackageDeprecations", "AlternatePackageRegistrationKey", "dbo.PackageRegistrations");
43+
DropForeignKey("dbo.PackageDeprecations", "DeprecatedByUserKey", "dbo.Users");
44+
DropForeignKey("dbo.PackageDeprecations", "PackageKey", "dbo.Packages");
45+
DropForeignKey("dbo.PackageDeprecations", "AlternatePackageKey", "dbo.Packages");
46+
DropIndex("dbo.PackageDeprecations", new[] { "DeprecatedByUserKey" });
47+
DropIndex("dbo.PackageDeprecations", new[] { "AlternatePackageKey" });
48+
DropIndex("dbo.PackageDeprecations", new[] { "AlternatePackageRegistrationKey" });
49+
DropIndex("dbo.PackageDeprecations", new[] { "PackageKey" });
50+
DropTable("dbo.PackageDeprecations");
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)