using Microsoft.Extensions.DependencyInjection; namespace Bit.Seeder.Pipeline; /// /// Resolves steps from DI by recipe key and executes them in order. /// internal sealed class RecipeExecutor { private readonly string _recipeName; private readonly IServiceProvider _serviceProvider; private readonly BulkCommitter _committer; internal RecipeExecutor(string recipeName, IServiceProvider serviceProvider, BulkCommitter committer) { _recipeName = recipeName; _serviceProvider = serviceProvider; _committer = committer; } /// /// Executes the recipe by resolving keyed steps, running them in order, and committing results. /// /// /// Clears the EntityRegistry at the start to ensure a clean slate for each run. /// internal ExecutionResult Execute() { var steps = _serviceProvider.GetKeyedServices(_recipeName) .OrderBy(s => s is OrderedStep os ? os.Order : int.MaxValue) .ToList(); var context = new SeederContext(_serviceProvider); context.Registry.Clear(); foreach (var step in steps) { step.Execute(context); } // Capture counts BEFORE committing (commit clears the lists) var result = new ExecutionResult( context.RequireOrgId(), context.Owner?.Email, context.Users.Count, context.Groups.Count, context.Collections.Count, context.Ciphers.Count); _committer.Commit(context); return result; } }