Skip to content

Conversation

@adamzip
Copy link
Contributor

@adamzip adamzip commented Dec 10, 2025

Copilot AI review requested due to automatic review settings December 10, 2025 15:27
@adamzip adamzip force-pushed the configuration-ingestion-implementation branch from 5835a33 to 898d740 Compare December 10, 2025 15:29
@adamzip adamzip force-pushed the configuration-ingestion-implementation branch from 898d740 to 2407049 Compare December 10, 2025 15:32
Copy link
Contributor

Copilot AI left a 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 SqlBarClient and ConfigurationIngestor to 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

        existingSubscription.TargetRepository = existingSubscription.TargetRepository;

src/Maestro/Maestro.DataProviders/SqlBarClient.cs:643

        existingSubscription.Enabled = existingSubscription.Enabled;

src/Maestro/Maestro.DataProviders/SqlBarClient.cs:644

        existingSubscription.SourceEnabled = existingSubscription.SourceEnabled;

src/Maestro/Maestro.DataProviders/SqlBarClient.cs:646

        existingSubscription.TargetDirectory = existingSubscription.TargetDirectory;

src/Maestro/Maestro.DataProviders/SqlBarClient.cs:546

  • The contents of this container are never initialized.
        var newSubscriptionHashes = new HashSet<string>();

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

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?

Copy link
Member

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

Copy link
Contributor Author

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

Choose a reason for hiding this comment

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

darc exception?

Copy link
Member

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

/// </summary>
private static string SubscriptionComparisonKey(Data.Models.Subscription subscription)
{
if (subscription.SourceEnabled)
Copy link
Member

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?

Copy link
Contributor Author

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?

Copy link
Member

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?

  1. We can keep all the relevant fields and if source enabled is not equal then subscriptions are also not equal?
  2. I think there's a bug - target repository should most likely be in the bottom hash too.

Copy link
Contributor Author

@adamzip adamzip Dec 15, 2025

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?

Copy link
Member

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

Choose a reason for hiding this comment

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

Should this be internal?

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 is implemented by the ingested entity POCO's that are returned by the ingestor, so has to be public

Copy link
Member

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>
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 internal?

Copy link
Contributor Author

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

Choose a reason for hiding this comment

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

Should this be internal?

Copy link
Contributor Author

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

Copy link
Member

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?

premun
premun previously approved these changes Dec 16, 2025
@premun premun dismissed their stale review December 16, 2025 13:54

Ah, I guess we still have stuff public

@dkurepa
Copy link
Member

dkurepa commented Dec 16, 2025

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?

@adamzip
Copy link
Contributor Author

adamzip commented Dec 16, 2025

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 - ValidateEntityUniqueness

@dkurepa
Copy link
Member

dkurepa commented Dec 16, 2025

Check out EntityValidator.cs - ValidateEntityUniqueness

nice, thanks!

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.

3 participants