Skip to content

Commit ddc0512

Browse files
authored
[NuGet Symbol Server]Symbols validation status view (#6407)
1 parent c174c8e commit ddc0512

11 files changed

Lines changed: 116 additions & 35 deletions

File tree

src/NuGetGallery/Controllers/PackagesController.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,8 @@ public virtual async Task<ActionResult> DisplayPackage(string id, string version
467467
var model = new DisplayPackageViewModel(package, currentUser, packageHistory);
468468

469469
model.ValidatingTooLong = _validationService.IsValidatingTooLong(package);
470-
model.ValidationIssues = _validationService.GetLatestValidationIssues(package);
470+
model.PackageValidationIssues = _validationService.GetLatestPackageValidationIssues(package);
471+
model.SymbolsPackageValidationIssues = _validationService.GetLatestPackageValidationIssues(model.LatestSymbolsPackage);
471472
model.IsCertificatesUIEnabled = _contentObjectService.CertificatesConfiguration?.IsUIEnabledForUser(currentUser) ?? false;
472473

473474
model.ReadMeHtml = await _readMeService.GetReadMeHtmlAsync(package);

src/NuGetGallery/Services/IValidationService.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ public interface IValidationService
4545
/// </summary>
4646
/// <param name="package">The package whose validation issues should be fetched.</param>
4747
/// <returns>The validation issues encountered in the latest validation.</returns>
48-
IReadOnlyList<ValidationIssue> GetLatestValidationIssues(Package package);
48+
IReadOnlyList<ValidationIssue> GetLatestPackageValidationIssues(Package package);
49+
50+
/// <summary>
51+
/// Get the symbol package's validation issues from the latest validation.
52+
/// </summary>
53+
/// <param name="symbolPackage">The symbol package whose validation issues should be fetched.</param>
54+
/// <returns>The validation issues encountered in the latest validation.</returns>
55+
IReadOnlyList<ValidationIssue> GetLatestPackageValidationIssues(SymbolPackage symbolPackage);
4956
}
5057
}

src/NuGetGallery/Services/ValidationService.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,33 @@ public bool IsValidatingTooLong(Package package)
7575
return false;
7676
}
7777

78-
public IReadOnlyList<ValidationIssue> GetLatestValidationIssues(Package package)
78+
public IReadOnlyList<ValidationIssue> GetLatestPackageValidationIssues(Package package)
79+
{
80+
return GetValidationIssues(package.Key, package.PackageStatusKey, ValidatingType.Package);
81+
}
82+
83+
public IReadOnlyList<ValidationIssue> GetLatestPackageValidationIssues(SymbolPackage symbolPackage)
84+
{
85+
if (symbolPackage == null)
86+
{
87+
return new List<ValidationIssue>();
88+
}
89+
90+
return GetValidationIssues(symbolPackage.Key, symbolPackage.StatusKey, ValidatingType.SymbolPackage);
91+
}
92+
93+
private IReadOnlyList<ValidationIssue> GetValidationIssues(int entityKey, PackageStatus status, ValidatingType validatingType)
7994
{
8095
IReadOnlyList<ValidationIssue> issues = new ValidationIssue[0];
8196

8297
// Only query the database for validation issues if the package has failed validation.
83-
if (package.PackageStatusKey == PackageStatus.FailedValidation)
98+
if (status == PackageStatus.FailedValidation)
8499
{
85100
// Grab the most recently completed validation set for this package. Note that the orchestrator will stop
86101
// processing a validation set if all validation succeed, OR, one or more validation fails.
87-
var validationSet = _validationSets
102+
var validationSet = _validationSets?
88103
.GetAll()
89-
.Where(s => s.PackageKey == package.Key)
104+
.Where(s => s.PackageKey == entityKey && s.ValidatingType == validatingType)
90105
.Where(s => s.PackageValidations.All(v => v.ValidationStatus == ValidationStatus.Succeeded) ||
91106
s.PackageValidations.Any(v => v.ValidationStatus == ValidationStatus.Failed))
92107
.Include(s => s.PackageValidations.Select(v => v.PackageValidationIssues))

src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public DisplayPackageViewModel(Package package, User currentUser, IOrderedEnumer
2626
PushedBy = GetPushedBy(package, currentUser);
2727
PackageFileSize = package.PackageFileSize;
2828

29-
LatestSymbolPackage = package
29+
LatestSymbolsPackage = package
3030
.SymbolPackages
3131
.OrderByDescending(sp => sp.Created)
3232
.FirstOrDefault();
@@ -61,7 +61,8 @@ public DisplayPackageViewModel(Package package, User currentUser, string pushedB
6161
}
6262

6363
public bool ValidatingTooLong { get; set; }
64-
public IReadOnlyList<ValidationIssue> ValidationIssues { get; set; }
64+
public IReadOnlyList<ValidationIssue> PackageValidationIssues { get; set; }
65+
public IReadOnlyList<ValidationIssue> SymbolsPackageValidationIssues { get; set; }
6566
public DependencySetsViewModel Dependencies { get; set; }
6667
public IEnumerable<DisplayPackageViewModel> PackageVersions { get; set; }
6768
public string Copyright { get; set; }
@@ -70,7 +71,7 @@ public DisplayPackageViewModel(Package package, User currentUser, string pushedB
7071
public int DownloadsPerDay { get; private set; }
7172
public int TotalDaysSinceCreated { get; private set; }
7273
public long PackageFileSize { get; private set; }
73-
public SymbolPackage LatestSymbolPackage { get; private set; }
74+
public SymbolPackage LatestSymbolsPackage { get; private set; }
7475

7576
public bool HasSemVer2Version { get; }
7677
public bool HasSemVer2Dependency { get; }

src/NuGetGallery/Views/Packages/DisplayPackage.cshtml

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
var absolutePackageUrl = Url.Absolute(Url.Package(Model.Id));
1111

12-
var hasSymbolPackageAvailable = Model.LatestSymbolPackage != null && Model.LatestSymbolPackage.StatusKey == PackageStatus.Available;
12+
var hasSymbolsPackageAvailable = Model.LatestSymbolsPackage != null && Model.LatestSymbolsPackage.StatusKey == PackageStatus.Available;
13+
var showSymbolsPackageStatus = Model.LatestSymbolsPackage != null && Model.LatestSymbolsPackage.StatusKey != PackageStatus.Available;
1314

1415
PackageManagerViewModel[] packageManagers;
1516

@@ -199,14 +200,14 @@
199200
@<text>
200201
<strong>Package publishing failed.</strong> This package could not be published due to the following reason(s):
201202
<ul class="failed-validation-alert-list">
202-
@foreach (var issue in Model.ValidationIssues)
203+
@foreach (var issue in Model.PackageValidationIssues)
203204
{
204205
<li>@Html.Partial("_ValidationIssue", issue)</li>
205206
}
206207
</ul>
207-
@if (!Model.ValidationIssues.Any(i => i.IssueCode == ValidationIssueCode.Unknown))
208+
@if (!Model.PackageValidationIssues.Any(i => i.IssueCode == ValidationIssueCode.Unknown))
208209
{
209-
var issuePluralString = Model.ValidationIssues.Count() > 1 ? "all the issues" : "the issue";
210+
var issuePluralString = Model.PackageValidationIssues.Count() > 1 ? "all the issues" : "the issue";
210211
<text>Once you've fixed @issuePluralString with your package, you can reupload it with the same ID and version.</text>
211212
}
212213
else
@@ -238,20 +239,20 @@
238239
@if (Model.HasNewerRelease)
239240
{
240241
@ViewHelpers.AlertInfo(
241-
@<text>
242-
There is a newer version of this package available.
243-
<br /> See the version list below for details.
244-
</text>
245-
)
242+
@<text>
243+
There is a newer version of this package available.
244+
<br /> See the version list below for details.
245+
</text>
246+
)
246247
}
247248
else if (Model.HasNewerPrerelease)
248249
{
249250
@ViewHelpers.AlertInfo(
250-
@<text>
251-
There is a newer prerelease version of this package available.
252-
<br /> See the version list below for details.
253-
</text>
254-
)
251+
@<text>
252+
There is a newer prerelease version of this package available.
253+
<br /> See the version list below for details.
254+
</text>
255+
)
255256
}
256257

257258
@if (Model.Listed && Model.IsIndexed.HasValue && !Model.IsIndexed.Value && Model.Available)
@@ -269,6 +270,43 @@
269270
@ViewHelpers.AlertIsSemVer2Package(Model.HasSemVer2Version, Model.HasSemVer2Dependency)
270271
}
271272

273+
@if (showSymbolsPackageStatus)
274+
{
275+
if (Model.LatestSymbolsPackage.StatusKey == PackageStatus.Validating)
276+
{
277+
@ViewHelpers.AlertWarning(
278+
@<text>
279+
The symbols for this package have not been indexed yet. They are not available
280+
for download from the NuGet.org symbol server. Symbols will be indexed and will
281+
be available for download after both validation and indexing are complete.
282+
Symbols validation and indexing may take up to an hour. <a href="https://aka.ms/NuGetSymbolsPackageValidation">Read more</a>.
283+
</text>
284+
)
285+
}
286+
else if (Model.LatestSymbolsPackage.StatusKey == PackageStatus.FailedValidation)
287+
{
288+
@ViewHelpers.AlertDanger(
289+
@<text>
290+
<strong>Symbols package publishing failed.</strong> The associated symbols package could not be published due to the following reason(s):
291+
<ul class="failed-validation-alert-list">
292+
@foreach (var issue in Model.SymbolsPackageValidationIssues)
293+
{
294+
<li>@Html.Partial("_ValidationIssue", issue)</li>
295+
}
296+
</ul>
297+
@if (!Model.SymbolsPackageValidationIssues.Any(i => i.IssueCode == ValidationIssueCode.Unknown))
298+
{
299+
var issuePluralString = Model.SymbolsPackageValidationIssues.Count() > 1 ? "all the issues" : "the issue";
300+
<text>Once you've fixed @issuePluralString with your symbols package, you can re-upload it.</text>
301+
}
302+
else
303+
{
304+
<text>Please contact <a href="mailto:[email protected]">support@nuget.org</a> to help fix your symbols package.</text>
305+
}
306+
</text>)
307+
}
308+
}
309+
272310
@if (!Model.Listed && Model.Available)
273311
{
274312
if (Model.CanDisplayPrivateMetadata)
@@ -467,7 +505,7 @@
467505
</td>
468506
<td>
469507
<a href="@Url.Package(packageVersion)" title="@packageVersion.FullVersion">
470-
@packageVersion.Version.Abbreviate(30)
508+
@packageVersion.Version.Abbreviate(30)
471509
</a>
472510
</td>
473511
<td>
@@ -626,12 +664,12 @@
626664
<a href="@Url.PackageDownload(2, Model.Id, Model.Version)" data-track="outbound-manual-download" title="Download the raw nupkg file." rel="nofollow">Download Package</a>
627665
&nbsp;(@Model.PackageFileSize.ToUserFriendlyBytesLabel())
628666
</li>
629-
if (hasSymbolPackageAvailable)
667+
if (hasSymbolsPackageAvailable)
630668
{
631669
<li>
632670
<i class="ms-Icon ms-Icon--CloudDownload" aria-hidden="true"></i>
633671
<a href="@Url.SymbolPackageDownload(2, Model.Id, Model.Version)" data-track="outbound-manual-download" title="Download the raw snupkg file." rel="nofollow">Download Symbols</a>
634-
&nbsp;(@Model.LatestSymbolPackage.FileSize.ToUserFriendlyBytesLabel())
672+
&nbsp;(@Model.LatestSymbolsPackage.FileSize.ToUserFriendlyBytesLabel())
635673
</li>
636674
}
637675
<li class="no-clickonce">

src/NuGetGallery/Views/Packages/_ValidationIssue.cshtml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@
5858
</text>
5959
break;
6060
}
61+
case ValidationIssueCode.SymbolErrorCode_ChecksumDoesNotMatch:
62+
<text>
63+
The checksum does not match for the dll(s) and corresponding pdb(s).
64+
</text>
65+
break;
66+
case ValidationIssueCode.SymbolErrorCode_MatchingPortablePDBNotFound:
67+
<text>
68+
The uploaded symbols package contains pdb(s) for a corresponding dll(s) not found in the nuget package.
69+
</text>
70+
break;
6171
default:
6272
<text>
6373
There was an unknown failure when validating your package.

src/NuGetGallery/Views/Shared/Gallery/Header.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@{
22
var ShowWarningIndicator = Config.Current.DeprecateNuGetPasswordLogins && (User.HasPasswordLogin() || (!User.HasMultiFactorAuthenticationEnabled() && User.WasMicrosoftAccountUsedForSignin()));
33
var ShowPasswordDeprecationBanner = TempData.ContainsKey("ShowPasswordDeprecationWarning")
4-
&& Convert.ToBoolean((string)TempData["ShowPasswordDeprecationWarning"])
4+
&& Convert.ToBoolean(TempData["ShowPasswordDeprecationWarning"].ToString())
55
&& Request.IsAuthenticated
66
&& Config.Current.DeprecateNuGetPasswordLogins
77
&& User.HasPasswordLogin();

tests/NuGetGallery.Facts/Controllers/PackagesControllerFacts.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -744,15 +744,15 @@ public async Task GetsValidationIssues()
744744
new TestIssue("This should not be deduplicated by the controller layer"),
745745
};
746746

747-
validationService.Setup(v => v.GetLatestValidationIssues(It.IsAny<Package>()))
747+
validationService.Setup(v => v.GetLatestPackageValidationIssues(It.IsAny<Package>()))
748748
.Returns(expectedIssues);
749749

750750
// Act
751751
var result = await controller.DisplayPackage("Foo", version: null);
752752

753753
// Assert
754754
var model = ResultAssert.IsView<DisplayPackageViewModel>(result);
755-
Assert.Equal(model.ValidationIssues, expectedIssues);
755+
Assert.Equal(model.PackageValidationIssues, expectedIssues);
756756
}
757757

758758
private class TestIssue : ValidationIssue

tests/NuGetGallery.Facts/Services/ValidationServiceFacts.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,22 @@ public void IgnoresPackagesThatHaventFailedValidations(PackageStatus status)
206206
_package.PackageStatusKey = status;
207207

208208
// Act
209-
var issues = _target.GetLatestValidationIssues(_package);
209+
var issues = _target.GetLatestPackageValidationIssues(_package);
210210

211211
// Assert
212212
_validationSets.Verify(x => x.GetAll(), Times.Never());
213213
}
214214

215+
[Fact]
216+
public void ReturnsEmptyListForNullSymbolsPackage()
217+
{
218+
// Arrange and act
219+
var issues = _target.GetLatestPackageValidationIssues(symbolPackage: null);
220+
221+
Assert.NotNull(issues);
222+
Assert.Empty(issues);
223+
}
224+
215225
[Fact]
216226
public void DeduplicatesValidationIssuesByCodeAndData()
217227
{
@@ -281,7 +291,7 @@ public void DeduplicatesValidationIssuesByCodeAndData()
281291
.Returns(new[] { packageValidationSet }.AsQueryable());
282292

283293
// Act
284-
var issues = _target.GetLatestValidationIssues(_package);
294+
var issues = _target.GetLatestPackageValidationIssues(_package);
285295

286296
// Assert
287297
_validationSets.Verify(x => x.GetAll(), Times.Once);
@@ -326,7 +336,7 @@ public void ReturnsSingleUnknownIssueIfNoneArePersisted()
326336
.Returns(new[] { packageValidationSet }.AsQueryable());
327337

328338
// Act
329-
var issues = _target.GetLatestValidationIssues(_package);
339+
var issues = _target.GetLatestPackageValidationIssues(_package);
330340

331341
// Assert
332342
_validationSets.Verify(x => x.GetAll(), Times.Once);
@@ -397,7 +407,7 @@ public void FetchesValidationIssues()
397407
.Returns(new[] { packageValidationSet1, packageValidationSet2, packageValidationSet3 }.AsQueryable());
398408

399409
// Act
400-
var issues = _target.GetLatestValidationIssues(_package);
410+
var issues = _target.GetLatestPackageValidationIssues(_package);
401411

402412
// Assert
403413
_validationSets.Verify(x => x.GetAll(), Times.Once());

tests/NuGetGallery.Facts/ViewModels/DisplayPackageViewModelFacts.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public void TheCtorReturnsLatestSymbolPackageByDateCreated()
155155

156156
var viewModel = new DisplayPackageViewModel(package, null, packageHistory: Enumerable.Empty<Package>().OrderBy(x => 1));
157157

158-
Assert.Equal(symbolPackageList[0], viewModel.LatestSymbolPackage);
158+
Assert.Equal(symbolPackageList[0], viewModel.LatestSymbolsPackage);
159159
}
160160

161161
[Fact]

0 commit comments

Comments
 (0)