< 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
73%
Covered lines: 88
Uncovered lines: 31
Coverable lines: 119
Total lines: 301
Line coverage: 73.9%
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%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 />
 10329public class WorkflowBuilder(IActivityVisitor activityVisitor, IIdentityGraphService identityGraphService, IActivityRegi
 10    : IWorkflowBuilder
 11{
 12    /// <inheritdoc />
 104013    public string? Id { get; set; }
 14
 15    /// <inheritdoc />
 357016    public string? DefinitionId { get; set; }
 17
 18    /// <inheritdoc />
 109619    public string? TenantId { get; set; }
 20
 21    /// <inheritdoc />
 206822    public int Version { get; set; } = 1;
 23
 24    /// <inheritdoc />
 110425    public string? Name { get; set; }
 26
 27    /// <inheritdoc />
 103228    public string? Description { get; set; }
 29
 30    /// <inheritdoc />
 103231    public bool IsReadonly { get; set; }
 32
 33    /// <inheritdoc />
 104834    public bool IsSystem { get; set; }
 35
 36    /// <inheritdoc />
 206437    public IActivity? Root { get; set; }
 38
 39    /// <inheritdoc />
 227440    public ICollection<Variable> Variables { get; set; } = new List<Variable>();
 41
 42    /// <inheritdoc />
 218943    public ICollection<InputDefinition> Inputs { get; set; } = new List<InputDefinition>();
 44
 45    /// <inheritdoc />
 209846    public ICollection<OutputDefinition> Outputs { get; set; } = new List<OutputDefinition>();
 47
 48    /// <inheritdoc />
 206449    public ICollection<string> Outcomes { get; set; } = new List<string>();
 50
 51    /// <inheritdoc />
 412852    public Variable? Result { get; set; } = new();
 53
 54    /// <inheritdoc />
 206455    public IDictionary<string, object> CustomProperties { get; set; } = new Dictionary<string, object>();
 56
 57    /// <inheritdoc />
 215558    public WorkflowOptions WorkflowOptions { get; } = new();
 59
 60    /// <inheritdoc />
 61    public IWorkflowBuilder WithDefinitionId(string definitionId)
 62    {
 91063        DefinitionId = definitionId;
 91064        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    {
 3276        TenantId = tenantId;
 3277        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    {
 6784        var variable = new Variable<T>(null!, default!);
 6785        Variables.Add(variable);
 6786        variable.WithWorkflowStorage();
 6787        variable.Id = null!; // This ensures that a deterministic ID is assigned by the builder.
 6788        return variable;
 89    }
 90
 91    /// <inheritdoc />
 92    public Variable<T> WithVariable<T>(string name, T value)
 93    {
 12694        var variable = new Variable<T>(name, value);
 12695        Variables.Add(variable);
 12696        return variable;
 97    }
 98
 99    /// <inheritdoc />
 100    [Obsolete("Use the overload that takes a name instead. This overload will be removed in a future version.")]
 101    public Variable<T> WithVariable<T>(T value)
 102    {
 0103        var variable = WithVariable<T>();
 0104        variable.Value = value;
 0105        return variable;
 106    }
 107
 108    /// <inheritdoc />
 109    public IWorkflowBuilder WithVariable<T>(Variable<T> variable)
 110    {
 17111        Variables.Add(variable);
 17112        return this;
 113    }
 114
 115    /// <inheritdoc />
 116    public IWorkflowBuilder WithVariable(Variable variable)
 117    {
 0118        Variables.Add(variable);
 0119        return this;
 120    }
 121
 122    /// <inheritdoc />
 123    public IWorkflowBuilder WithVariables(params Variable[] variables)
 124    {
 0125        foreach (var variable in variables)
 0126            Variables.Add(variable);
 0127        return this;
 128    }
 129
 130    /// <inheritdoc />
 131    public InputDefinition WithInput<T>(string name, string? description = default)
 132    {
 125133        return WithInput(name, typeof(T), description);
 134    }
 135
 136    /// <inheritdoc />
 137    public InputDefinition WithInput(string name, Type type, string? description = default)
 138    {
 125139        return WithInput(inputDefinition =>
 125140        {
 125141            inputDefinition.Name = name;
 125142            inputDefinition.Type = type;
 125143
 125144            if (description != null)
 16145                inputDefinition.Description = description;
 250146        });
 147    }
 148
 149    /// <inheritdoc />
 150    public InputDefinition WithInput(string name, Type type, Action<InputDefinition>? setup = default)
 151    {
 0152        return WithInput(inputDefinition =>
 0153        {
 0154            inputDefinition.Name = name;
 0155            inputDefinition.Type = type;
 0156            setup?.Invoke(inputDefinition);
 0157        });
 158    }
 159
 160    /// <inheritdoc />
 161    public InputDefinition WithInput(Action<InputDefinition> setup)
 162    {
 125163        var inputDefinition = new InputDefinition();
 125164        setup(inputDefinition);
 125165        Inputs.Add(inputDefinition);
 125166        return inputDefinition;
 167    }
 168
 169    /// <inheritdoc />
 170    public IWorkflowBuilder WithInput(InputDefinition inputDefinition)
 171    {
 0172        Inputs.Add(inputDefinition);
 0173        return this;
 174    }
 175
 176    public OutputDefinition WithOutput<T>(string name, string? description = default)
 177    {
 34178        return WithOutput(name, typeof(T), description);
 179    }
 180
 181    public OutputDefinition WithOutput(string name, Type type, string? description = default)
 182    {
 34183        return WithOutput(outputDefinition =>
 34184        {
 34185            outputDefinition.Name = name;
 34186            outputDefinition.Type = type;
 34187
 34188            if (description != null)
 0189                outputDefinition.Description = description;
 68190        });
 191    }
 192
 193    public OutputDefinition WithOutput(string name, Type type, Action<OutputDefinition>? setup = default)
 194    {
 0195        return WithOutput(outputDefinition =>
 0196        {
 0197            outputDefinition.Name = name;
 0198            outputDefinition.Type = type;
 0199            setup?.Invoke(outputDefinition);
 0200        });
 201    }
 202
 203    public OutputDefinition WithOutput(Action<OutputDefinition> setup)
 204    {
 34205        var outputDefinition = new OutputDefinition();
 34206        setup(outputDefinition);
 34207        return WithOutput(outputDefinition);
 208    }
 209
 210    public OutputDefinition WithOutput(OutputDefinition outputDefinition)
 211    {
 34212        Outputs.Add(outputDefinition);
 34213        return outputDefinition;
 214    }
 215
 216    /// <inheritdoc />
 217    public IWorkflowBuilder WithCustomProperty(string name, object value)
 218    {
 0219        CustomProperties[name] = value;
 0220        return this;
 221    }
 222
 223    /// <inheritdoc />
 224    public IWorkflowBuilder WithActivationStrategyType<T>() where T : IWorkflowActivationStrategy
 225    {
 0226        WorkflowOptions.ActivationStrategyType = typeof(T);
 0227        return this;
 228    }
 229
 230    /// <summary>
 231    /// Marks the workflow as readonly.
 232    /// </summary>
 233    public IWorkflowBuilder AsReadonly()
 234    {
 0235        IsReadonly = true;
 0236        return this;
 237    }
 238
 239    /// <summary>
 240    ///   Marks the workflow as a system workflow.
 241    ///   System workflows are not visible in the UI by default and are not meant to be modified by users.
 242    /// </summary>
 243    public IWorkflowBuilder AsSystemWorkflow()
 244    {
 16245        IsSystem = true;
 16246        return this;
 247    }
 248
 249    /// <inheritdoc />
 250    public async Task<Workflow> BuildWorkflowAsync(CancellationToken cancellationToken = default)
 251    {
 1032252        var definitionId = string.IsNullOrEmpty(DefinitionId) ? string.Empty : DefinitionId;
 1032253        var id = string.IsNullOrEmpty(Id) ? string.Empty : Id;
 1032254        var tenantId = string.IsNullOrEmpty(TenantId) ? null : TenantId;
 1032255        var root = Root ?? new Sequence();
 1032256        var identity = new WorkflowIdentity(definitionId, Version, id, tenantId);
 1032257        var publication = WorkflowPublication.LatestAndPublished;
 1032258        var name = string.IsNullOrEmpty(Name) ? definitionId : Name;
 1032259        var workflowMetadata = new WorkflowMetadata(name, Description);
 1032260        var workflow = new Workflow(identity, publication, workflowMetadata, WorkflowOptions, root, Variables, Inputs, O
 261
 262        // If a Result variable is defined, install it into the workflow, so we can capture the output into it.
 1032263        if (Result != null)
 264        {
 1032265            workflow.ResultVariable = Result;
 1032266            workflow.Result = new Output<object>(Result);
 267        }
 268
 1032269        var graph = await activityVisitor.VisitAsync(workflow, cancellationToken);
 1032270        var nodes = graph.Flatten().ToList();
 271
 272        // Register all activity types first. The identity graph service will need to know about all activity types.
 5167273        var distinctActivityTypes = nodes.Select(x => x.Activity.GetType()).Distinct().ToList();
 1032274        await activityRegistry.RegisterAsync(distinctActivityTypes, cancellationToken);
 275
 276        // Assign identities to all activities.
 1032277        await identityGraphService.AssignIdentitiesAsync(nodes);
 278
 279        // Give unnamed variables in each variable container a predictable name.
 7088280        var variableContainers = nodes.Where(x => x.Activity is IVariableContainer).Select(x => (IVariableContainer)x.Ac
 281
 5906282        foreach (var container in variableContainers)
 283        {
 1921284            var index = 0;
 2133285            var unnamedVariables = container.Variables.Where(x => string.IsNullOrWhiteSpace(x.Name)).ToList();
 286
 4010287            foreach (var unnamedVariable in unnamedVariables)
 84288                unnamedVariable.Name = $"Variable_{index++}";
 289        }
 290
 1032291        return workflow;
 1032292    }
 293
 294    /// <inheritdoc />
 295    public async Task<Workflow> BuildWorkflowAsync(IWorkflow workflowDefinition, CancellationToken cancellationToken = d
 296    {
 558297        DefinitionId = workflowDefinition.GetType().Name;
 558298        await workflowDefinition.BuildAsync(this, cancellationToken);
 558299        return await BuildWorkflowAsync(cancellationToken);
 558300    }
 301}