-
Notifications
You must be signed in to change notification settings - Fork 79
Implement configuration ingestion #5636
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
base: main
Are you sure you want to change the base?
Implement configuration ingestion #5636
Conversation
5835a33 to
898d740
Compare
898d740 to
2407049
Compare
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.
Pull request overview
This PR implements configuration ingestion functionality to allow the Product Construction Service to validate and persist configuration data (subscriptions, channels, default channels, and branch merge policies) from external sources. The implementation introduces a new interface for externally synced entities, validation logic for entity uniqueness and field constraints, and CRUD operations for managing configuration data.
Key changes:
- Introduces
IExternallySyncedEntity<TId>interface to standardize entity identification across YAML models and database models - Implements comprehensive validation framework for configuration entities with uniqueness checking
- Adds CRUD operations in
SqlBarClientandConfigurationIngestorto create, update, and delete configuration entities with proper namespace isolation
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Microsoft.DotNet.Darc/DarcLib/Models/Yaml/IExternallySyncedEntity.cs | New interface defining contract for externally synced entities with unique identifiers |
| src/Microsoft.DotNet.Darc/DarcLib/Models/Yaml/SubscriptionYaml.cs | Implements IExternallySyncedEntity using subscription Id as unique identifier |
| src/Microsoft.DotNet.Darc/DarcLib/Models/Yaml/ChannelYaml.cs | Implements IExternallySyncedEntity using channel name as unique identifier |
| src/Microsoft.DotNet.Darc/DarcLib/Models/Yaml/DefaultChannelYaml.cs | Implements IExternallySyncedEntity using repository/branch/channel tuple; adds Id field for ingestion |
| src/Microsoft.DotNet.Darc/DarcLib/Models/Yaml/BranchMergePoliciesYaml.cs | Implements IExternallySyncedEntity using repository/branch tuple as unique identifier |
| src/Maestro/Maestro.Data/Models/Repository.cs | Adds UniqueId property to RepositoryBranch for consistency with IExternallySyncedEntity pattern |
| src/Maestro/Maestro.Data/Models/DefaultChannel.cs | Implements IExternallySyncedEntity on database model for alignment with YAML model |
| src/Maestro/Maestro.DataProviders/ISqlBarClient.cs | Adds interface methods for subscription CRUD operations used in configuration ingestion |
| src/Maestro/Maestro.DataProviders/SqlBarClient.cs | Implements CRUD methods with conflict detection, validation, and conversion between client/DAO models |
| src/Maestro/Maestro.DataProviders/Exceptions/EntityConflictException.cs | New exception type for handling duplicate entity conflicts during ingestion |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/IConfigurationIngestor.cs | Updated interface signature to return entity changes and require namespace parameter |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/ConfigurationIngestor.cs | Core ingestion orchestration including validation, entity comparison, and database persistence |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/ConfigurationData.cs | Changed to use YAML models instead of DAO models for external configuration representation |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/ConfigurationDataUpdate.cs | New record types capturing created, updated, and removed entities for each configuration type |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/ConfigurationDataHelper.cs | Helper methods for computing entity differences and converting between YAML and DAO models |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/Validations/EntityValidator.cs | Generic validator for checking entity uniqueness across IExternallySyncedEntity collections |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/Validations/SubscriptionValidator.cs | Updated to validate collections and work with SubscriptionYaml instead of DAO models |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/Validations/ChannelValidator.cs | Updated to validate collections and work with ChannelYaml instead of DAO models |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/Validations/DefaultChannelValidator.cs | Updated to validate collections and work with DefaultChannelYaml instead of DAO models |
| src/Maestro/Maestro.DataProviders/ConfigurationIngestor/Validations/BranchMergePolicyValidator.cs | Updated to validate collections and work with BranchMergePoliciesYaml instead of DAO models |
Comments suppressed due to low confidence (6)
src/Maestro/Maestro.DataProviders/SqlBarClient.cs:641
- This assignment assigns Enabled to itself.
existingSubscription.SourceRepository = existingSubscription.SourceRepository;
src/Maestro/Maestro.DataProviders/SqlBarClient.cs:642
- This assignment assigns SourceEnabled to itself.
existingSubscription.TargetRepository = existingSubscription.TargetRepository;
src/Maestro/Maestro.DataProviders/SqlBarClient.cs:643
- This assignment assigns SourceDirectory to itself.
existingSubscription.Enabled = existingSubscription.Enabled;
src/Maestro/Maestro.DataProviders/SqlBarClient.cs:644
- This assignment assigns TargetDirectory to itself.
existingSubscription.SourceEnabled = existingSubscription.SourceEnabled;
src/Maestro/Maestro.DataProviders/SqlBarClient.cs:646
- This assignment assigns PullRequestFailureNotificationTags to itself.
existingSubscription.TargetDirectory = existingSubscription.TargetDirectory;
src/Maestro/Maestro.DataProviders/SqlBarClient.cs:546
- The contents of this container are never initialized.
var newSubscriptionHashes = new HashSet<string>();
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestor/Validations/EntityValidator.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestor/ConfigurationIngestor.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
…urationDataHelper.cs Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
…dEntity.cs Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestor/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Outdated
Show resolved
Hide resolved
test/Maestro.DataProviders.Tests/ConfigurationIngestionTests.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
- Make some internal things public - Fix id update bug with default channels - Add AssetFilter persistence for subscriptions - Change EF queries to make sure all fetches are meterialized immediately
| @@ -0,0 +1,178 @@ | |||
| // Licensed to the .NET Foundation under one or more agreements. | |||
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 this go to the helpers folder?
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 Helper might not be the best name for this class. It does quite a lot of the core logic
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.
To be fair, all the methods here are internal and static, so it's kind of a helper in that sense (there's zero side effects in that class).
It's hard to find another name, but maybe if i separate the converters into one class and the entity diff computations into another, we can have a converters class and a .. ingestion diff.. computer.. class
| if (existingChannel is null) | ||
| { | ||
| //todo find the right exception type | ||
| throw new InvalidOperationException( |
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.
darc exception?
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.
think we often use those when it's an internal logic exception
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataUpdate.cs
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.DotNet.Darc/DarcLib/Models/Yaml/SubscriptionYaml.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.DotNet.Darc/DarcLib/Models/Yaml/DefaultChannelYaml.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/Validations/EntityValidator.cs
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Show resolved
Hide resolved
...oConfiguration/src/Microsoft.DotNet.MaestroConfiguration.Client/Models/DefaultChannelYaml.cs
Outdated
Show resolved
Hide resolved
| /// </summary> | ||
| private static string SubscriptionComparisonKey(Data.Models.Subscription subscription) | ||
| { | ||
| if (subscription.SourceEnabled) |
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.
Do we need this if? Can't we just have || in the hash?
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.
The relevant fields are a bit different for source-enabled and standard subscriptions. How do you propose to do it?
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.
How do they differ? Only by source directory, no?
- We can keep all the relevant fields and if source enabled is not equal then subscriptions are also not equal?
- I think there's a bug - target repository should most likely be in the bottom hash too.
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.
What about the channel id? I added it for dependency flows, but not for codeflows. Should the strings here not have the channel id in both cases?
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.
Oh, I see, you've clumped together the fact that there were similar subscriptions before and the verification of different codeflows leading to the same branch+folder.
I think that's fine like this, it was just a little obscured - maybe we could have a comment about source enabled ones and when and why they are the same if they target the same dir of the same branch?
| /// Requires a unique identifier to match existing entities with ingested ones. | ||
| /// </summary> | ||
| /// <typeparam name="TId">The type of the unique identifier for the entity. Must be a non-nullable type.</typeparam> | ||
| public interface IExternallySyncedEntity<TId> where TId : notnull |
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 this be internal?
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 is implemented by the ingested entity POCO's that are returned by the ingestor, so has to be public
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 return the Ingestion POCOs and not the values from inside of them? Aren't those only here for internal comparison?
| #nullable enable | ||
| namespace Maestro.DataProviders.ConfigurationIngestion.Helpers; | ||
|
|
||
| public class IngestedChannel : IExternallySyncedEntity<string> |
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 internal?
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.
These are used by the validation because we also check entity uniqueness and such. The validations should be public according to our plan
| #nullable enable | ||
| namespace Maestro.DataProviders.ConfigurationIngestion; | ||
|
|
||
| public class ConfigurationIngestor( |
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 this be internal?
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 will be consumed by the CI pipeline at the config repo, so needs to be public
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.
The interface yes, but the implementation can stay internal?
You will only get it through DI?
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Show resolved
Hide resolved
... to subscriptions string, make configuration ingestor internal
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationDataHelper.cs
Outdated
Show resolved
Hide resolved
src/Maestro/Maestro.DataProviders/ConfigurationIngestion/ConfigurationIngestor.cs
Outdated
Show resolved
Hide resolved
|
quick question: since the data we send to the Ingestor will be just parsed from the repo without any checks, do we have a check if the for example subscriptions are distinct, in the yaml data? |
Check out EntityValidator.cs - |
nice, thanks! |
#5494