< Summary

Information
Class: Elsa.Workflows.Builders.WorkflowBuilder
Assembly: Elsa.Workflows.Core
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs
Line coverage
72%
Covered lines: 88
Uncovered lines: 34
Coverable lines: 122
Total lines: 309
Line coverage: 72.1%
Branch coverage
69%
Covered branches: 18
Total branches: 26
Branch coverage: 69.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Id()100%11100%
get_DefinitionId()100%11100%
get_TenantId()100%11100%
get_Version()100%11100%
get_Name()100%11100%
get_Description()100%11100%
get_IsReadonly()100%11100%
get_IsSystem()100%11100%
get_Root()100%11100%
get_Variables()100%11100%
get_Inputs()100%11100%
get_Outputs()100%11100%
get_Outcomes()100%11100%
get_Result()100%11100%
get_CustomProperties()100%11100%
get_WorkflowOptions()100%11100%
WithDefinitionId(...)100%11100%
WithId(...)100%210%
WithTenantId(...)100%11100%
WithVariable()100%11100%
WithVariable(...)100%210%
WithVariable(...)100%11100%
WithVariable(...)100%210%
WithVariable(...)100%11100%
WithVariable(...)100%210%
WithVariables(...)0%620%
WithInput(...)100%11100%
WithInput(...)100%22100%
WithInput(...)0%620%
WithInput(...)100%11100%
WithInput(...)100%210%
WithOutput(...)100%11100%
WithOutput(...)50%2287.5%
WithOutput(...)0%620%
WithOutput(...)100%11100%
WithOutput(...)100%11100%
WithCustomProperty(...)100%210%
WithActivationStrategyType()100%210%
AsReadonly()100%210%
AsSystemWorkflow()100%11100%
BuildWorkflowAsync()93.75%1616100%
BuildWorkflowAsync()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs

#LineLine coverage
 1using Elsa.Extensions;
 2using Elsa.Workflows.Activities;
 3using Elsa.Workflows.Memory;
 4using Elsa.Workflows.Models;
 5
 6namespace Elsa.Workflows.Builders;
 7
 8/// <inheritdoc />
 37589public class WorkflowBuilder(IActivityVisitor activityVisitor, IIdentityGraphService identityGraphService, IActivityRegi
 10    : IWorkflowBuilder
 11{
 12    /// <inheritdoc />
 376613    public string? Id { get; set; }
 14
 15    /// <inheritdoc />
 1233416    public string? DefinitionId { get; set; }
 17
 18    /// <inheritdoc />
 391419    public string? TenantId { get; set; }
 20
 21    /// <inheritdoc />
 752022    public int Version { get; set; } = 1;
 23
 24    /// <inheritdoc />
 399025    public string? Name { get; set; }
 26
 27    /// <inheritdoc />
 375828    public string? Description { get; set; }
 29
 30    /// <inheritdoc />
 375831    public bool IsReadonly { get; set; }
 32
 33    /// <inheritdoc />
 381434    public bool IsSystem { get; set; }
 35
 36    /// <inheritdoc />
 751637    public IActivity? Root { get; set; }
 38
 39    /// <inheritdoc />
 874840    public ICollection<Variable> Variables { get; set; } = new List<Variable>();
 41
 42    /// <inheritdoc />
 791343    public ICollection<InputDefinition> Inputs { get; set; } = new List<InputDefinition>();
 44
 45    /// <inheritdoc />
 762946    public ICollection<OutputDefinition> Outputs { get; set; } = new List<OutputDefinition>();
 47
 48    /// <inheritdoc />
 751649    public ICollection<string> Outcomes { get; set; } = new List<string>();
 50
 51    /// <inheritdoc />
 1503252    public Variable? Result { get; set; } = new();
 53
 54    /// <inheritdoc />
 751655    public IDictionary<string, object> CustomProperties { get; set; } = new Dictionary<string, object>();
 56
 57    /// <inheritdoc />
 780158    public WorkflowOptions WorkflowOptions { get; } = new();
 59
 60    /// <inheritdoc />
 61    public IWorkflowBuilder WithDefinitionId(string definitionId)
 62    {
 351863        DefinitionId = definitionId;
 351864        return this;
 65    }
 66
 67    public IWorkflowBuilder WithId(string id)
 68    {
 069        Id = id;
 070        return this;
 71    }
 72
 73    /// <inheritdoc />
 74    public IWorkflowBuilder WithTenantId(string tenantId)
 75    {
 7876        TenantId = tenantId;
 7877        return this;
 78    }
 79
 80    /// <inheritdoc />
 81    [Obsolete("Use the overload that takes a name instead. This overload will be removed in a future version.")]
 82    public Variable<T> WithVariable<T>()
 83    {
 78484        var variable = new Variable<T>(null!, default!);
 78485        Variables.Add(variable);
 78486        variable.WithWorkflowStorage();
 78487        variable.Id = null!; // This ensures that a deterministic ID is assigned by the builder.
 78488        return variable;
 89    }
 90
 91    /// <inheritdoc />
 92    public Variable<T> WithVariable<T>(string name)
 93    {
 094        var variable = new Variable<T>(name, default!);
 095        Variables.Add(variable);
 096        return variable;
 97    }
 98
 99    /// <inheritdoc />
 100    public Variable<T> WithVariable<T>(string name, T value)
 101    {
 392102        var variable = new Variable<T>(name, value);
 392103        Variables.Add(variable);
 392104        return variable;
 105    }
 106
 107    /// <inheritdoc />
 108    [Obsolete("Use the overload that takes a name instead. This overload will be removed in a future version.")]
 109    public Variable<T> WithVariable<T>(T value)
 110    {
 0111        var variable = WithVariable<T>();
 0112        variable.Value = value;
 0113        return variable;
 114    }
 115
 116    /// <inheritdoc />
 117    public IWorkflowBuilder WithVariable<T>(Variable<T> variable)
 118    {
 56119        Variables.Add(variable);
 56120        return this;
 121    }
 122
 123    /// <inheritdoc />
 124    public IWorkflowBuilder WithVariable(Variable variable)
 125    {
 0126        Variables.Add(variable);
 0127        return this;
 128    }
 129
 130    /// <inheritdoc />
 131    public IWorkflowBuilder WithVariables(params Variable[] variables)
 132    {
 0133        foreach (var variable in variables)
 0134            Variables.Add(variable);
 0135        return this;
 136    }
 137
 138    /// <inheritdoc />
 139    public InputDefinition WithInput<T>(string name, string? description = default)
 140    {
 397141        return WithInput(name, typeof(T), description);
 142    }
 143
 144    /// <inheritdoc />
 145    public InputDefinition WithInput(string name, Type type, string? description = default)
 146    {
 397147        return WithInput(inputDefinition =>
 397148        {
 397149            inputDefinition.Name = name;
 397150            inputDefinition.Type = type;
 397151
 397152            if (description != null)
 56153                inputDefinition.Description = description;
 794154        });
 155    }
 156
 157    /// <inheritdoc />
 158    public InputDefinition WithInput(string name, Type type, Action<InputDefinition>? setup = default)
 159    {
 0160        return WithInput(inputDefinition =>
 0161        {
 0162            inputDefinition.Name = name;
 0163            inputDefinition.Type = type;
 0164            setup?.Invoke(inputDefinition);
 0165        });
 166    }
 167
 168    /// <inheritdoc />
 169    public InputDefinition WithInput(Action<InputDefinition> setup)
 170    {
 397171        var inputDefinition = new InputDefinition();
 397172        setup(inputDefinition);
 397173        Inputs.Add(inputDefinition);
 397174        return inputDefinition;
 175    }
 176
 177    /// <inheritdoc />
 178    public IWorkflowBuilder WithInput(InputDefinition inputDefinition)
 179    {
 0180        Inputs.Add(inputDefinition);
 0181        return this;
 182    }
 183
 184    public OutputDefinition WithOutput<T>(string name, string? description = default)
 185    {
 113186        return WithOutput(name, typeof(T), description);
 187    }
 188
 189    public OutputDefinition WithOutput(string name, Type type, string? description = default)
 190    {
 113191        return WithOutput(outputDefinition =>
 113192        {
 113193            outputDefinition.Name = name;
 113194            outputDefinition.Type = type;
 113195
 113196            if (description != null)
 0197                outputDefinition.Description = description;
 226198        });
 199    }
 200
 201    public OutputDefinition WithOutput(string name, Type type, Action<OutputDefinition>? setup = default)
 202    {
 0203        return WithOutput(outputDefinition =>
 0204        {
 0205            outputDefinition.Name = name;
 0206            outputDefinition.Type = type;
 0207            setup?.Invoke(outputDefinition);
 0208        });
 209    }
 210
 211    public OutputDefinition WithOutput(Action<OutputDefinition> setup)
 212    {
 113213        var outputDefinition = new OutputDefinition();
 113214        setup(outputDefinition);
 113215        return WithOutput(outputDefinition);
 216    }
 217
 218    public OutputDefinition WithOutput(OutputDefinition outputDefinition)
 219    {
 113220        Outputs.Add(outputDefinition);
 113221        return outputDefinition;
 222    }
 223
 224    /// <inheritdoc />
 225    public IWorkflowBuilder WithCustomProperty(string name, object value)
 226    {
 0227        CustomProperties[name] = value;
 0228        return this;
 229    }
 230
 231    /// <inheritdoc />
 232    public IWorkflowBuilder WithActivationStrategyType<T>() where T : IWorkflowActivationStrategy
 233    {
 0234        WorkflowOptions.ActivationStrategyType = typeof(T);
 0235        return this;
 236    }
 237
 238    /// <summary>
 239    /// Marks the workflow as readonly.
 240    /// </summary>
 241    public IWorkflowBuilder AsReadonly()
 242    {
 0243        IsReadonly = true;
 0244        return this;
 245    }
 246
 247    /// <summary>
 248    ///   Marks the workflow as a system workflow.
 249    ///   System workflows are not visible in the UI by default and are not meant to be modified by users.
 250    /// </summary>
 251    public IWorkflowBuilder AsSystemWorkflow()
 252    {
 56253        IsSystem = true;
 56254        return this;
 255    }
 256
 257    /// <inheritdoc />
 258    public async Task<Workflow> BuildWorkflowAsync(CancellationToken cancellationToken = default)
 259    {
 3758260        var definitionId = string.IsNullOrEmpty(DefinitionId) ? string.Empty : DefinitionId;
 3758261        var id = string.IsNullOrEmpty(Id) ? string.Empty : Id;
 3758262        var tenantId = string.IsNullOrEmpty(TenantId) ? null : TenantId;
 3758263        var root = Root ?? new Sequence();
 3758264        var identity = new WorkflowIdentity(definitionId, Version, id, tenantId);
 3758265        var publication = WorkflowPublication.LatestAndPublished;
 3758266        var name = string.IsNullOrEmpty(Name) ? definitionId : Name;
 3758267        var workflowMetadata = new WorkflowMetadata(name, Description);
 3758268        var workflow = new Workflow(identity, publication, workflowMetadata, WorkflowOptions, root, Variables, Inputs, O
 269
 270        // If a Result variable is defined, install it into the workflow, so we can capture the output into it.
 3758271        if (Result != null)
 272        {
 3758273            workflow.ResultVariable = Result;
 3758274            workflow.Result = new Output<object>(Result);
 275        }
 276
 3758277        var graph = await activityVisitor.VisitAsync(workflow, cancellationToken);
 3758278        var nodes = graph.Flatten().ToList();
 279
 280        // Register all activity types first. The identity graph service will need to know about all activity types.
 19219281        var distinctActivityTypes = nodes.Select(x => x.Activity.GetType()).Distinct().ToList();
 3758282        await activityRegistry.RegisterAsync(distinctActivityTypes, cancellationToken);
 283
 284        // Assign identities to all activities.
 3758285        await identityGraphService.AssignIdentitiesAsync(nodes);
 286
 287        // Give unnamed variables in each variable container a predictable name.
 26277288        var variableContainers = nodes.Where(x => x.Activity is IVariableContainer).Select(x => (IVariableContainer)x.Ac
 289
 21632290        foreach (var container in variableContainers)
 291        {
 7058292            var index = 0;
 8292293            var unnamedVariables = container.Variables.Where(x => string.IsNullOrWhiteSpace(x.Name)).ToList();
 294
 15796295            foreach (var unnamedVariable in unnamedVariables)
 840296                unnamedVariable.Name = $"Variable_{index++}";
 297        }
 298
 3758299        return workflow;
 3758300    }
 301
 302    /// <inheritdoc />
 303    public async Task<Workflow> BuildWorkflowAsync(IWorkflow workflowDefinition, CancellationToken cancellationToken = d
 304    {
 1346305        DefinitionId = workflowDefinition.GetType().Name;
 1346306        await workflowDefinition.BuildAsync(this, cancellationToken);
 1346307        return await BuildWorkflowAsync(cancellationToken);
 1346308    }
 309}