-
Notifications
You must be signed in to change notification settings - Fork 641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NuGet Symbol Server] Add Symbol push validation support #6276
Conversation
</PackageReference> | ||
<PackageReference Include="NuGet.Services.Validation.Issues"> | ||
<Version>2.26.0-master-33196</Version> | ||
<Version>2.28.0-master-37018</Version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a stable version to update to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see one in manage nuget packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe our (undocumented) process for ServerCommon is to kick off a stable build when making changes there. I had similiar feedback in another PR, which is why I mention it.
.Register(c => { | ||
return new AsynchronousPackageValidationInitiator( | ||
c.ResolveKeyed<IPackageValidationEnqueuer>("PackageValidationEnqueuerBindingKey"), | ||
c.ResolveKeyed<IPackageValidationEnqueuer>("SymbolsPackageValidationEnqueuerBindingKey"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these be constants - to keep this in sync w/ code above?
</PackageReference> | ||
<PackageReference Include="NuGet.Versioning"> | ||
<Version>4.8.0-preview4.5287</Version> | ||
</PackageReference> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! I assume these dependencies are pulled in from Gallery.Core?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
/// <returns> | ||
/// The task which signals the completion of the validation initiation. The result of the <see cref="Task"/> | ||
/// is the <see cref="PackageStatus"/> that should be applied to the package.</returns> | ||
Task<PackageStatus> StartSymbolsPackageValidationAsync(SymbolPackage symbolPackage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little strange that the initiator has APIs for both nupkg and snupkg packages, but are only configured for one or the other.
It it possible to have a IPackageValidationInitiator<TPackage>
so that the initiator can only enqueue based on the configured package type?
await _symbolPackageService.UpdateStatusAsync(symbolPackage, | ||
symbolPackageStatus, | ||
commitChanges: false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would having an IPackageEntity
interface for use by Package
and SymbolsPackage
allow more code reuse?
72ffa71
to
f72c497
Compare
@chenriksson - I have managed to refactor the code and setup DI appropriately(thanks @joelverhagen), I tested this in synchronous and blocked async mode, looks good. Please take a look at the refactoring. |
@@ -8,18 +8,18 @@ namespace NuGetGallery | |||
/// <summary> | |||
/// Initiates validation for a specific package. | |||
/// </summary> | |||
public interface IPackageValidationInitiator | |||
public interface IPackageValidationInitiator<IPackageEntity> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IPackageEntity [](start = 49, length = 14)
Generic type arguments should start with T
. It also could be useful to have where
constraint to restrict it to the classes implementing the IPackageEntity
@@ -61,6 +58,11 @@ public async Task<PackageCommitResult> CreateAndUploadSymbolsPackage(Package pac | |||
} | |||
else if (symbolPackage.StatusKey == PackageStatus.Available) | |||
{ | |||
if (symbolPackage.Published == null) | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: !symbolPackage.Published.HasValue
?
@@ -13,9 +13,9 @@ namespace NuGetGallery | |||
/// Initiates asynchronous validation on a package by enqueuing a message containing the package identity and a new | |||
/// <see cref="Guid"/>. The <see cref="Guid"/> represents a unique validation request. | |||
/// </summary> | |||
public class AsynchronousPackageValidationInitiator : IPackageValidationInitiator | |||
public class AsynchronousPackageValidationInitiator<TPackage> : IPackageValidationInitiator<TPackage> where TPackage: IPackageEntity | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it have to be generic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My suggestion... see my comment here
My concern was that you could create a snupkg
initiator with an (invalid) API to initiate nupkg
validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not as familiar w/ symbols work though, so feel free to suggest something different. Just thinking this could help with code reuse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@agr - code reusability for pushing to Package validation topic and symbol validation topic. The DI initializes these generic types to be used in Validation service.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TPackageEntity
is not used for anything in this class. IPackageValidationInitiator
can be made non-generic with Task<PackageStatus> StartValidationAsync(IPackageEntity package)
method instead and then the code would still work unless I am missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked and resolved this query offline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked offline: this makes DI setup quite complicated, so disregard.
@@ -13,9 +13,9 @@ namespace NuGetGallery | |||
/// Initiates asynchronous validation on a package by enqueuing a message containing the package identity and a new | |||
/// <see cref="Guid"/>. The <see cref="Guid"/> represents a unique validation request. | |||
/// </summary> | |||
public class AsynchronousPackageValidationInitiator : IPackageValidationInitiator | |||
public class AsynchronousPackageValidationInitiator<TPackage> : IPackageValidationInitiator<TPackage> where TPackage: IPackageEntity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we wrap this line at where
?
|
||
string Version { get; } | ||
|
||
ValidatingType Type { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is ValidatingType
an enum that should be added with this PR? Do you need it - why not just check instance type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it is an enum. This completely removes the dependency of checking the type in initiator. Also, it is going to be specific to each IPackageEntity
so it makes sense to put it in here.
@@ -39,6 +39,14 @@ | |||
|
|||
namespace NuGetGallery | |||
{ | |||
public static class BindingKeys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PackageValidationBindingKeys
? I think BindingKeys
may be too general given this is nested in the DefaultDependenciesModule
class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep it as a general class for binding constants, going forward use it for any DI setup that requires binding. This isn't specific for PackageValidation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Common coding standard I've seen is to keep 1:1 relation between classes and files, with names matching.
Given this, would consider moving BindingKeys
into separate file or nesting under DefaultDependenciesModule
class.
c.ResolveKeyed<IPackageValidationEnqueuer>(BindingKeys.SymbolsPackageValidationEnqueuer), | ||
c.Resolve<IAppConfiguration>(), | ||
c.Resolve<IDiagnosticsService>()); | ||
}).As<IPackageValidationInitiator<SymbolPackage>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So was ResolveKeyed
the solution to get DI registrations to work for the specific generic type args?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed instantiating the AsynchronousPackageValidationInitiator
and ImmediateValidationInitiator
to be Generic
which was causing the problem. See the code below of RegisterGenerics
which sets up the DI appropriately.
@@ -13,9 +13,9 @@ namespace NuGetGallery | |||
/// Initiates asynchronous validation on a package by enqueuing a message containing the package identity and a new | |||
/// <see cref="Guid"/>. The <see cref="Guid"/> represents a unique validation request. | |||
/// </summary> | |||
public class AsynchronousPackageValidationInitiator : IPackageValidationInitiator | |||
public class AsynchronousPackageValidationInitiator<TPackage> : IPackageValidationInitiator<TPackage> where TPackage: IPackageEntity | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not as familiar w/ symbols work though, so feel free to suggest something different. Just thinking this could help with code reuse.
@@ -8,18 +8,18 @@ namespace NuGetGallery | |||
/// <summary> | |||
/// Initiates validation for a specific package. | |||
/// </summary> | |||
public interface IPackageValidationInitiator | |||
public interface IPackageValidationInitiator<TEntity> where TEntity: IPackageEntity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: would name <TPackageEntity>
@@ -9,9 +9,9 @@ namespace NuGetGallery | |||
/// A validation initiator that immediately marks the package as validated. In other words, no asynchronous | |||
/// validation is performed by this implementation. | |||
/// </summary> | |||
public class ImmediatePackageValidator : IPackageValidationInitiator | |||
public class ImmediatePackageValidator<TPackage> : IPackageValidationInitiator<TPackage> where TPackage: IPackageEntity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: TPackageEntity
if (!symbolPackage.Published.HasValue) | ||
{ | ||
symbolPackage.Published = DateTime.UtcNow; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was comparing this code with nupkg
validation initiation... and they look very different.
public async Task<PackageCommitResult> CommitPackageAsync(Package package, Stream packageFile) |
Just wondering, since the design reuses much of the validation infrastructure (even a copy)... why do the code paths look different? Again, feel free to ignore since I don't have as much context here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created this file for symbol specific stuff, the validation here isn't a copy though. The Package upload doesn't allow an overwrite, symbols does. It is meant to be different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By "copy", I meant to say snupkg
files share much of the same validation pipeline as nupkg
files from what I remember... but Gallery just sends the initiate messages to a different service bus / pipeline instance.
From Gallery's perspective... wouldn't initiating a validation, and receiving validation status look about the same between nupkg
and snupkg
packages?
e.g., shouldn't Gallery set package.Published = DateTime.UtcNow
in roughly the same place for both nupkg
and snupkg
?
Or are the code paths between the two that different in the Gallery?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
talked offline to clarify the differences here.
@@ -95,5 +101,13 @@ public IReadOnlyList<ValidationIssue> GetLatestValidationIssues(Package package) | |||
|
|||
return issues; | |||
} | |||
|
|||
public async Task StartSymbolsPackageValidationAsync(SymbolPackage symbolPackage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: naming is a little inconsistent with corresponding nupkg
API.
Maybe just StartValidationAsync(SymbolPackage)
is enough?
@@ -95,5 +101,13 @@ public IReadOnlyList<ValidationIssue> GetLatestValidationIssues(Package package) | |||
|
|||
return issues; | |||
} | |||
|
|||
public async Task StartValidationAsync(SymbolPackage symbolPackage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will need the same validation functionality for symbols and for packages: 1. revalidation, browsing state, monitoring. It's not part of the MVP but is it tracked with issues?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, #6049
|
||
string Version { get; } | ||
|
||
ValidatingType Type { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider renaming this to "PackageType". Validation type is not an attribute of the package, it's a behavior derived from the type of the package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am reusing this from the Validations side for consistency, we use this to identify the package. While I agree with you, I do not think we should diverge for this enum. I'll alias it here I guess for ease.
|
||
namespace NuGetGallery | ||
{ | ||
public interface IPackageEntity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider IPackageEntity : IEntity
, to restrict usage of this interface to entity types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding doc comments to specify the need for this type -- to reuse code between nupkg
and snupkg
packages.
|
||
public string Id => PackageRegistration.Id; | ||
|
||
public ValidatingType Type => ValidatingType.Package; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type
could be confused with GetType()
. Consider renaming to ValidatingType
.
Is this used in this PR? Would remove if not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removing this.
{ | ||
string Id { get; } | ||
|
||
string Version { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any shared code paths as part of this PR that would require NormalizedVersion
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not the code I am touching. I wouldn't refactor much for anything else right now.
|
||
namespace NuGetGallery | ||
{ | ||
public class SymbolPackage | ||
: IEntity, IEquatable<SymbolPackage> | ||
: IEntity, IPackageEntity, IEquatable<SymbolPackage> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outside the scope of this PR... but why does SymbolPackage
implement IEquatable
, and Package
does not? Is there functionality only specific to symbols that requires this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
public string Version => Package?.Version; | ||
|
||
public ValidatingType Type => ValidatingType.SymbolPackage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above (Package.cs).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be deleted. missed it.
@@ -39,6 +39,14 @@ | |||
|
|||
namespace NuGetGallery | |||
{ | |||
public static class BindingKeys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Common coding standard I've seen is to keep 1:1 relation between classes and files, with names matching.
Given this, would consider moving BindingKeys
into separate file or nesting under DefaultDependenciesModule
class.
else | ||
{ | ||
throw new ArgumentException($"Unknown IPackageEntity type: {nameof(package)}"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why add ValidatingType
to Package
and SymbolPackage
, but not IPackageEntity
? Seems like it complicates the code here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see @skofman1's comment. I think it doesn't make sense to put the ValidatingType
on the entity.
if (!symbolPackage.Published.HasValue) | ||
{ | ||
symbolPackage.Published = DateTime.UtcNow; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By "copy", I meant to say snupkg
files share much of the same validation pipeline as nupkg
files from what I remember... but Gallery just sends the initiate messages to a different service bus / pipeline instance.
From Gallery's perspective... wouldn't initiating a validation, and receiving validation status look about the same between nupkg
and snupkg
packages?
e.g., shouldn't Gallery set package.Published = DateTime.UtcNow
in roughly the same place for both nupkg
and snupkg
?
Or are the code paths between the two that different in the Gallery?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may have a few nits remaining, but nothing blocking.
</PackageReference> | ||
<PackageReference Include="NuGet.Services.Validation.Issues"> | ||
<Version>2.26.0-master-33196</Version> | ||
<Version>2.28.0-master-37018</Version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe our (undocumented) process for ServerCommon is to kick off a stable build when making changes there. I had similiar feedback in another PR, which is why I mention it.
I've verified these changes in DEV with the new configs. Looks good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addresses #6235
Added test coverage, I have verified this locally, will check in DEV. Sending out a separate PR for the new configs for symbol validation service bus and topic.