Skip to content
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

Merged
merged 13 commits into from
Aug 9, 2018

Conversation

shishirx34
Copy link
Contributor

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.

</PackageReference>
<PackageReference Include="NuGet.Services.Validation.Issues">
<Version>2.26.0-master-33196</Version>
<Version>2.28.0-master-37018</Version>
Copy link
Member

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?

Copy link
Contributor Author

@shishirx34 shishirx34 Aug 7, 2018

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.

Copy link
Member

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"),
Copy link
Member

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>
Copy link
Member

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?

Copy link
Contributor Author

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);
Copy link
Member

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);
}
Copy link
Member

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?

@shishirx34
Copy link
Contributor Author

@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>
Copy link
Contributor

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)
{
Copy link
Contributor

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
{
Copy link
Contributor

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?

Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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
Copy link
Member

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; }
Copy link
Member

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?

Copy link
Contributor Author

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
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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>>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shishirx34 @joelverhagen

So was ResolveKeyed the solution to get DI registrations to work for the specific generic type args?

Copy link
Contributor Author

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
{
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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;
}
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor Author

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)
Copy link
Member

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)
Copy link
Contributor

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?

Copy link
Contributor Author

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; }
Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Member

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.

Copy link
Member

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;
Copy link
Member

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.

Copy link
Contributor Author

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; }
Copy link
Member

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?

Copy link
Contributor Author

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>
Copy link
Member

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?

Copy link
Contributor Author

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;
Copy link
Member

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).

Copy link
Contributor Author

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
Copy link
Member

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)}");
}
Copy link
Member

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.

Copy link
Contributor Author

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;
}
Copy link
Member

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?

Copy link
Member

@chenriksson chenriksson left a 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>
Copy link
Member

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.

@shishirx34
Copy link
Contributor Author

I've verified these changes in DEV with the new configs. Looks good.

Copy link
Contributor

@agr agr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@shishirx34 shishirx34 merged commit 3805e2e into dev Aug 9, 2018
@shishirx34 shishirx34 deleted the symbol-push-validation branch August 9, 2018 01:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants