Skip to content

Commit ac41391

Browse files
author
Christy Henriksson
authored
Merge pull request #6691 from NuGet/dev
[ReleasePrep][2018.11.20]RI of dev into master
2 parents abacf65 + 3b53ede commit ac41391

41 files changed

Lines changed: 1003 additions & 258 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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.Collections.Generic;
5+
using System.Linq;
6+
using NuGet.Services.Validation;
7+
using NuGet.Services.Validation.Issues;
8+
9+
namespace NuGetGallery
10+
{
11+
public static class PackageValidationSetExtensions
12+
{
13+
public static IReadOnlyList<ValidationIssue> GetValidationIssues(this PackageValidationSet validationSet)
14+
{
15+
IReadOnlyList<ValidationIssue> issues = null;
16+
17+
if (validationSet != null)
18+
{
19+
// Get the failed validation set's validation issues. The issues are ordered by their
20+
// key so that it appears that issues are appended as more validations fail.
21+
issues = validationSet
22+
.PackageValidations
23+
.SelectMany(v => v.PackageValidationIssues)
24+
.OrderBy(i => i.Key)
25+
.Select(i => ValidationIssue.Deserialize(i.IssueCode, i.Data))
26+
.ToList();
27+
28+
// Filter out unknown issues and deduplicate the issues by code and data. This also deduplicates cases
29+
// where there is extraneous data in the serialized data field or if the issue code is unknown.
30+
issues = issues
31+
.GroupBy(x => new { x.IssueCode, Data = x.Serialize() })
32+
.Select(x => x.First())
33+
.ToList();
34+
}
35+
36+
// If the package failed validation but we could not find an issue that explains why, use a generic error message.
37+
if (issues == null || !issues.Any())
38+
{
39+
issues = new[] { ValidationIssue.Unknown };
40+
}
41+
42+
return issues;
43+
}
44+
}
45+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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 NuGet.Services.Validation;
6+
using NuGet.Services.Validation.Issues;
7+
8+
namespace NuGetGallery
9+
{
10+
internal static class ValidationIssueExtensions
11+
{
12+
/// <summary>
13+
/// Returns a Markdown representation describing the <see cref="ValidationIssue"/> in a user-friendly way.
14+
/// </summary>
15+
public static string ToMarkdownString(this ValidationIssue validationIssue, string announcementsUrl, string twitterUrl)
16+
{
17+
if (validationIssue == null)
18+
{
19+
throw new ArgumentNullException(nameof(validationIssue));
20+
}
21+
22+
if (announcementsUrl == null)
23+
{
24+
throw new ArgumentNullException(nameof(announcementsUrl));
25+
}
26+
27+
if (twitterUrl == null)
28+
{
29+
throw new ArgumentNullException(nameof(twitterUrl));
30+
}
31+
32+
switch (validationIssue.IssueCode)
33+
{
34+
case ValidationIssueCode.PackageIsSigned:
35+
return $"This package could not be published since it is signed. We do not accept signed packages at this moment. To be notified about package signing and more, watch our [Announcements]({announcementsUrl}) page or follow us on [Twitter]({twitterUrl}).";
36+
case ValidationIssueCode.ClientSigningVerificationFailure:
37+
var clientIssue = (ClientSigningVerificationFailure)validationIssue;
38+
return clientIssue != null
39+
? $"**{clientIssue.ClientCode}**: {clientIssue.ClientMessage}"
40+
: "This package's signature was unable to get verified.";
41+
case ValidationIssueCode.PackageIsZip64:
42+
return "Zip64 packages are not supported.";
43+
case ValidationIssueCode.OnlyAuthorSignaturesSupported:
44+
return "Signed packages must only have an author signature. Other signature types are not supported.";
45+
case ValidationIssueCode.AuthorAndRepositoryCounterSignaturesNotSupported:
46+
return "Author countersignatures and repository countersignatures are not supported.";
47+
case ValidationIssueCode.OnlySignatureFormatVersion1Supported:
48+
return "**NU3007:** Package signatures must have format version 1.";
49+
case ValidationIssueCode.AuthorCounterSignaturesNotSupported:
50+
return "Author countersignatures are not supported.";
51+
case ValidationIssueCode.PackageIsNotSigned:
52+
return "This package must be signed with a registered certificate. [Read more...](https://aka.ms/nuget-signed-ref)";
53+
case ValidationIssueCode.PackageIsSignedWithUnauthorizedCertificate:
54+
var certIssue = (UnauthorizedCertificateFailure)validationIssue;
55+
return $"The package was signed, but the signing certificate {(certIssue != null ? $"(SHA-1 thumbprint {certIssue.Sha1Thumbprint})" : "")} is not associated with your account. You must register this certificate to publish signed packages. [Read more...](https://aka.ms/nuget-signed-ref)";
56+
case ValidationIssueCode.SymbolErrorCode_ChecksumDoesNotMatch:
57+
return "The checksum does not match for the dll(s) and corresponding pdb(s).";
58+
case ValidationIssueCode.SymbolErrorCode_MatchingAssemblyNotFound:
59+
return "The uploaded symbols package contains pdb(s) for a corresponding dll(s) not found in the nuget package.";
60+
case ValidationIssueCode.SymbolErrorCode_PdbIsNotPortable:
61+
return "The uploaded symbols package contains one or more pdbs that are not portable.";
62+
default:
63+
return "There was an unknown failure when validating your package.";
64+
}
65+
}
66+
}
67+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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.Collections.Generic;
6+
using System.Linq;
7+
using System.Net.Mail;
8+
using NuGet.Services.Entities;
9+
10+
namespace NuGetGallery.Infrastructure.Mail
11+
{
12+
public static class EmailRecipientsHelper
13+
{
14+
public static IReadOnlyList<MailAddress> GetAllOwners(PackageRegistration packageRegistration, bool requireEmailAllowed)
15+
{
16+
if (packageRegistration == null)
17+
{
18+
throw new ArgumentNullException(nameof(packageRegistration));
19+
}
20+
21+
var recipients = new List<MailAddress>();
22+
var owners = requireEmailAllowed
23+
? packageRegistration.Owners.Where(o => o.EmailAllowed)
24+
: packageRegistration.Owners;
25+
26+
foreach (var owner in owners)
27+
{
28+
recipients.Add(owner.ToMailAddress());
29+
}
30+
31+
return recipients;
32+
}
33+
34+
public static IReadOnlyList<MailAddress> GetOwnersSubscribedToPackagePushedNotification(PackageRegistration packageRegistration)
35+
{
36+
if (packageRegistration == null)
37+
{
38+
throw new ArgumentNullException(nameof(packageRegistration));
39+
}
40+
41+
var recipients = new List<MailAddress>();
42+
foreach (var owner in packageRegistration.Owners.Where(o => o.NotifyPackagePushed))
43+
{
44+
recipients.Add(owner.ToMailAddress());
45+
}
46+
47+
return recipients;
48+
}
49+
}
50+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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.Collections.Generic;
6+
using System.Linq;
7+
using System.Net.Mail;
8+
using Markdig;
9+
using NuGet.Services.Entities;
10+
using NuGet.Services.Messaging.Email;
11+
12+
namespace NuGetGallery.Infrastructure.Mail.Messages
13+
{
14+
public class PackageAddedMessage : MarkdownEmailBuilder
15+
{
16+
private readonly IMessageServiceConfiguration _configuration;
17+
private readonly string _packageUrl;
18+
private readonly string _packageSupportUrl;
19+
private readonly string _emailSettingsUrl;
20+
private readonly IEnumerable<string> _warningMessages;
21+
private readonly bool _hasWarnings;
22+
23+
public PackageAddedMessage(
24+
IMessageServiceConfiguration configuration,
25+
Package package,
26+
string packageUrl,
27+
string packageSupportUrl,
28+
string emailSettingsUrl,
29+
IEnumerable<string> warningMessages)
30+
{
31+
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
32+
Package = package ?? throw new ArgumentNullException(nameof(package));
33+
_packageUrl = packageUrl ?? throw new ArgumentNullException(nameof(packageUrl));
34+
_packageSupportUrl = packageSupportUrl ?? throw new ArgumentNullException(nameof(packageSupportUrl));
35+
_emailSettingsUrl = emailSettingsUrl ?? throw new ArgumentNullException(nameof(emailSettingsUrl));
36+
_warningMessages = warningMessages;
37+
_hasWarnings = warningMessages != null && warningMessages.Any();
38+
}
39+
40+
public override MailAddress Sender => _configuration.GalleryNoReplyAddress;
41+
42+
public Package Package { get; }
43+
44+
public override IEmailRecipients GetRecipients()
45+
{
46+
var to = EmailRecipientsHelper.GetOwnersSubscribedToPackagePushedNotification(Package.PackageRegistration);
47+
return new EmailRecipients(to);
48+
}
49+
50+
public override string GetSubject()
51+
{
52+
if (_hasWarnings)
53+
{
54+
return $"[{_configuration.GalleryOwner.DisplayName}] Package published with warnings - {Package.PackageRegistration.Id} {Package.Version}";
55+
}
56+
else
57+
{
58+
return $"[{_configuration.GalleryOwner.DisplayName}] Package published - {Package.PackageRegistration.Id} {Package.Version}";
59+
}
60+
}
61+
62+
protected override string GetMarkdownBody()
63+
{
64+
return GetBodyInternal(EmailFormat.Markdown);
65+
}
66+
67+
protected override string GetPlainTextBody()
68+
{
69+
return GetBodyInternal(EmailFormat.PlainText);
70+
}
71+
72+
protected override string GetHtmlBody()
73+
{
74+
return GetBodyInternal(EmailFormat.Html);
75+
}
76+
77+
private string GetBodyInternal(EmailFormat format)
78+
{
79+
var warningMessages = GetWarningMessages();
80+
81+
var markdown = $@"The package [{Package.PackageRegistration.Id} {Package.Version}]({_packageUrl}) was recently published on {_configuration.GalleryOwner.DisplayName} by {Package.User.Username}. If this was not intended, please [contact support]({_packageSupportUrl}).";
82+
83+
if (!string.IsNullOrEmpty(warningMessages))
84+
{
85+
markdown += warningMessages;
86+
}
87+
88+
string body;
89+
switch (format)
90+
{
91+
case EmailFormat.PlainText:
92+
body = ToPlainText(markdown);
93+
break;
94+
case EmailFormat.Markdown:
95+
body = markdown;
96+
break;
97+
case EmailFormat.Html:
98+
body = Markdown.ToHtml(markdown);
99+
break;
100+
default:
101+
throw new ArgumentOutOfRangeException(nameof(format));
102+
}
103+
104+
return body + EmailMessageFooter.ForPackageOwnerNotifications(format, _configuration.GalleryOwner.DisplayName, _emailSettingsUrl);
105+
}
106+
107+
private string GetWarningMessages()
108+
{
109+
var warningMessagesPlaceholder = string.Empty;
110+
if (_hasWarnings)
111+
{
112+
warningMessagesPlaceholder = Environment.NewLine + Environment.NewLine + string.Join(Environment.NewLine, _warningMessages);
113+
}
114+
return warningMessagesPlaceholder;
115+
}
116+
}
117+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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.Linq;
6+
using System.Net.Mail;
7+
using System.Text;
8+
using NuGet.Services.Entities;
9+
using NuGet.Services.Messaging.Email;
10+
using NuGet.Services.Validation;
11+
12+
namespace NuGetGallery.Infrastructure.Mail.Messages
13+
{
14+
public class PackageValidationFailedMessage : MarkdownEmailBuilder
15+
{
16+
private readonly IMessageServiceConfiguration _configuration;
17+
private readonly Package _package;
18+
private readonly PackageValidationSet _validationSet;
19+
private readonly string _packageUrl;
20+
private readonly string _packageSupportUrl;
21+
private readonly string _announcementsUrl;
22+
private readonly string _twitterUrl;
23+
24+
public PackageValidationFailedMessage(
25+
IMessageServiceConfiguration configuration,
26+
Package package,
27+
PackageValidationSet validationSet,
28+
string packageUrl,
29+
string packageSupportUrl,
30+
string announcementsUrl,
31+
string twitterUrl)
32+
{
33+
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
34+
_package = package ?? throw new ArgumentNullException(nameof(package));
35+
_validationSet = validationSet ?? throw new ArgumentNullException(nameof(validationSet));
36+
_packageUrl = packageUrl ?? throw new ArgumentNullException(nameof(packageUrl));
37+
_packageSupportUrl = packageSupportUrl ?? throw new ArgumentNullException(nameof(packageSupportUrl));
38+
_announcementsUrl = announcementsUrl ?? throw new ArgumentNullException(nameof(announcementsUrl));
39+
_twitterUrl = twitterUrl ?? throw new ArgumentNullException(nameof(twitterUrl));
40+
}
41+
42+
public override MailAddress Sender => _configuration.GalleryNoReplyAddress;
43+
44+
public override IEmailRecipients GetRecipients()
45+
{
46+
var to = EmailRecipientsHelper.GetAllOwners(_package.PackageRegistration, requireEmailAllowed: false);
47+
return new EmailRecipients(to);
48+
}
49+
50+
public override string GetSubject()
51+
=> $"[{_configuration.GalleryOwner.DisplayName}] Package validation failed - {_package.PackageRegistration.Id} {_package.Version}";
52+
53+
protected override string GetMarkdownBody()
54+
{
55+
var validationIssues = _validationSet.GetValidationIssues();
56+
57+
var bodyBuilder = new StringBuilder();
58+
bodyBuilder.Append($@"The package [{_package.PackageRegistration.Id} {_package.Version}]({_packageUrl}) failed validation because of the following reason(s):
59+
");
60+
61+
foreach (var validationIssue in validationIssues)
62+
{
63+
bodyBuilder.Append($@"
64+
- {validationIssue.ToMarkdownString(_announcementsUrl, _twitterUrl)}");
65+
}
66+
67+
bodyBuilder.Append($@"
68+
69+
Your package was not published on {_configuration.GalleryOwner.DisplayName} and is not available for consumption.
70+
71+
");
72+
73+
if (validationIssues.Any(i => i.IssueCode == ValidationIssueCode.Unknown))
74+
{
75+
bodyBuilder.Append($"Please [contact support]({_packageSupportUrl}) to help fix your package.");
76+
}
77+
else
78+
{
79+
var issuePluralString = validationIssues.Count() > 1 ? "all the issues" : "the issue";
80+
bodyBuilder.Append($"You can reupload your package once you've fixed {issuePluralString} with it.");
81+
}
82+
83+
return bodyBuilder.ToString();
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)