< Summary

Information
Class: Elsa.Workflows.Management.Services.WorkflowDefinitionPublisher
Assembly: Elsa.Workflows.Management
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionPublisher.cs
Line coverage
64%
Covered lines: 98
Uncovered lines: 55
Coverable lines: 153
Total lines: 251
Line coverage: 64%
Branch coverage
52%
Covered branches: 25
Total branches: 48
Branch coverage: 52%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
New(...)0%620%
NewAsync(...)100%22100%
PublishAsync()50%2255.55%
PublishAsync()83.33%6696.29%
RetractAsync()0%620%
RetractAsync()0%620%
RevertVersionAsync()0%2040%
GetDraftAsync()75%8895.65%
SaveDraftAsync()57.14%141490%
Initialize(...)50%9657.14%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionPublisher.cs

#LineLine coverage
 1using Elsa.Common;
 2using Elsa.Common.Entities;
 3using Elsa.Common.Models;
 4using Elsa.Mediator.Contracts;
 5using Elsa.Workflows.Activities;
 6using Elsa.Workflows.Management.Entities;
 7using Elsa.Workflows.Management.Filters;
 8using Elsa.Workflows.Management.Materializers;
 9using Elsa.Workflows.Management.Models;
 10using Elsa.Workflows.Management.Notifications;
 11using Elsa.Workflows.Models;
 12
 13namespace Elsa.Workflows.Management.Services;
 14
 15/// <inheritdoc />
 32016public class WorkflowDefinitionPublisher(
 32017    IWorkflowDefinitionService workflowDefinitionService,
 32018    IWorkflowDefinitionStore workflowDefinitionStore,
 32019    IWorkflowValidator workflowValidator,
 32020    IIdentityGenerator identityGenerator,
 32021    IActivitySerializer activitySerializer,
 32022    IMediator mediator,
 32023    ISystemClock systemClock)
 24    : IWorkflowDefinitionPublisher
 25{
 26    /// <inheritdoc />
 27    public WorkflowDefinition New(IActivity? root = null)
 28    {
 029        root ??= new Sequence();
 030        var id = identityGenerator.GenerateId();
 031        var definitionId = identityGenerator.GenerateId();
 32        const int version = 1;
 33
 034        return new()
 035        {
 036            Id = id,
 037            DefinitionId = definitionId,
 038            Version = version,
 039            IsLatest = true,
 040            IsPublished = false,
 041            CreatedAt = systemClock.UtcNow,
 042            StringData = activitySerializer.Serialize(root),
 043            MaterializerName = JsonWorkflowMaterializer.MaterializerName
 044        };
 45    }
 46
 47    public Task<WorkflowDefinition> NewAsync(IActivity? root = null, CancellationToken cancellationToken = default)
 48    {
 449        root ??= new Sequence();
 450        var id = identityGenerator.GenerateId();
 451        var definitionId = identityGenerator.GenerateId();
 52        const int version = 1;
 53
 454        var workflowDefinition = new WorkflowDefinition
 455        {
 456            Id = id,
 457            DefinitionId = definitionId,
 458            Version = version,
 459            IsLatest = true,
 460            IsPublished = false,
 461            CreatedAt = systemClock.UtcNow,
 462            StringData = activitySerializer.Serialize(root),
 463            MaterializerName = JsonWorkflowMaterializer.MaterializerName
 464        };
 65
 466        return Task.FromResult(workflowDefinition);
 67    }
 68
 69    /// <inheritdoc />
 70    public async Task<PublishWorkflowDefinitionResult> PublishAsync(string definitionId, CancellationToken cancellationT
 71    {
 172        var filter = WorkflowDefinitionHandle.ByDefinitionId(definitionId, VersionOptions.Latest).ToFilter();
 173        var definition = await workflowDefinitionStore.FindAsync(filter, cancellationToken);
 74
 175        if (definition == null)
 076            return new(false, new List<WorkflowValidationError>
 077            {
 078                new("Workflow definition not found.")
 079            }, new([]));
 80
 181        return await PublishAsync(definition, cancellationToken);
 182    }
 83
 84    /// <inheritdoc />
 85    public async Task<PublishWorkflowDefinitionResult> PublishAsync(WorkflowDefinition definition, CancellationToken can
 86    {
 587        var workflowGraph = await workflowDefinitionService.MaterializeWorkflowAsync(definition, cancellationToken);
 588        var validationErrors = (await workflowValidator.ValidateAsync(workflowGraph.Workflow, cancellationToken)).ToList
 89
 590        if (validationErrors.Any())
 091            return new(false, validationErrors, new([]));
 92
 593        await mediator.SendAsync(new WorkflowDefinitionPublishing(definition), cancellationToken);
 594        var definitionId = definition.DefinitionId;
 95
 96        // Reset current latest and published definitions.
 597        var publishedWorkflows = await workflowDefinitionStore.FindManyAsync(new()
 598        {
 599            DefinitionId = definitionId,
 5100            VersionOptions = VersionOptions.LatestOrPublished
 5101        }, cancellationToken);
 102
 18103        foreach (var publishedAndOrLatestWorkflow in publishedWorkflows)
 104        {
 4105            var isPublished = publishedAndOrLatestWorkflow.IsPublished;
 4106            publishedAndOrLatestWorkflow.IsPublished = false;
 4107            publishedAndOrLatestWorkflow.IsLatest = false;
 4108            await workflowDefinitionStore.SaveAsync(publishedAndOrLatestWorkflow, cancellationToken);
 109
 4110            if (isPublished)
 3111                await mediator.SendAsync(new WorkflowDefinitionVersionRetracted(publishedAndOrLatestWorkflow), cancellat
 4112        }
 113
 114        // Save the newly published definition.
 5115        definition.IsPublished = true;
 5116        definition.IsLatest = true;
 5117        definition = Initialize(definition);
 5118        await workflowDefinitionStore.SaveAsync(definition, cancellationToken);
 119
 5120        var affectedWorkflows = new AffectedWorkflows(new List<WorkflowDefinition>());
 5121        await mediator.SendAsync(new WorkflowDefinitionPublished(definition, affectedWorkflows), cancellationToken);
 5122        return new(true, validationErrors, affectedWorkflows);
 5123    }
 124
 125    /// <inheritdoc />
 126    public async Task<WorkflowDefinition?> RetractAsync(string definitionId, CancellationToken cancellationToken = defau
 127    {
 0128        var filter = WorkflowDefinitionHandle.ByDefinitionId(definitionId, VersionOptions.Published).ToFilter();
 0129        var definition = await workflowDefinitionStore.FindAsync(filter, cancellationToken);
 130
 0131        if (definition == null)
 0132            return null;
 133
 0134        return await RetractAsync(definition, cancellationToken);
 0135    }
 136
 137    /// <inheritdoc />
 138    public async Task<WorkflowDefinition> RetractAsync(WorkflowDefinition definition, CancellationToken cancellationToke
 139    {
 0140        if (!definition.IsPublished)
 0141            throw new InvalidOperationException("Cannot retract an unpublished workflow definition.");
 142
 0143        definition.IsPublished = false;
 144
 0145        await mediator.SendAsync(new WorkflowDefinitionRetracting(definition), cancellationToken);
 0146        await workflowDefinitionStore.SaveAsync(definition, cancellationToken);
 0147        await mediator.SendAsync(new WorkflowDefinitionRetracted(definition), cancellationToken);
 0148        return definition;
 0149    }
 150
 151    public async Task<WorkflowDefinition> RevertVersionAsync(string definitionId, int version, CancellationToken cancell
 152    {
 0153        var filter = new WorkflowDefinitionFilter
 0154        {
 0155            DefinitionId = definitionId,
 0156            VersionOptions = VersionOptions.Latest
 0157        };
 0158        var latestVersion = await workflowDefinitionStore.FindAsync(filter, cancellationToken);
 159
 0160        if (latestVersion != null)
 161        {
 0162            latestVersion.IsLatest = false;
 0163            await workflowDefinitionStore.SaveAsync(latestVersion, cancellationToken);
 164        }
 165
 0166        var draft = await GetDraftAsync(definitionId, VersionOptions.SpecificVersion(version), cancellationToken);
 0167        draft!.Id = identityGenerator.GenerateId();
 0168        draft.Version = (latestVersion?.Version ?? 0) + 1;
 0169        draft.IsLatest = true;
 170
 0171        await workflowDefinitionStore.SaveAsync(draft, cancellationToken);
 0172        return draft;
 0173    }
 174
 175    /// <inheritdoc />
 176    public async Task<WorkflowDefinition?> GetDraftAsync(string definitionId, VersionOptions versionOptions, Cancellatio
 177    {
 6178        var filter = new WorkflowDefinitionFilter
 6179        {
 6180            DefinitionId = definitionId,
 6181            VersionOptions = versionOptions
 6182        };
 6183        var order = new WorkflowDefinitionOrder<int>(x => x.Version, OrderDirection.Descending);
 6184        var lastVersion = await workflowDefinitionStore.FindLastVersionAsync(new()
 6185        {
 6186            DefinitionId = definitionId
 6187        }, cancellationToken);
 6188        var definition = await workflowDefinitionStore.FindAsync(filter, order, cancellationToken) ?? lastVersion;
 189
 6190        if (definition == null!)
 4191            return null;
 192
 2193        if (!definition.IsPublished)
 0194            return definition;
 195
 2196        var draft = definition.ShallowClone();
 197
 2198        draft.Version = lastVersion?.Version + 1 ?? 1;
 2199        draft.CreatedAt = systemClock.UtcNow;
 2200        draft.Id = identityGenerator.GenerateId();
 2201        draft.IsLatest = true;
 2202        draft.IsPublished = false;
 203
 2204        return draft;
 6205    }
 206
 207    /// <inheritdoc />
 208    public async Task<WorkflowDefinition> SaveDraftAsync(WorkflowDefinition definition, CancellationToken cancellationTo
 209    {
 2210        var draft = definition;
 2211        var definitionId = definition.DefinitionId;
 2212        var filter = new WorkflowDefinitionFilter
 2213        {
 2214            DefinitionId = definitionId
 2215        };
 2216        var lastVersion = await workflowDefinitionStore.FindLastVersionAsync(filter, cancellationToken);
 217
 2218        draft.Version = draft.Id == lastVersion?.Id ? lastVersion.Version : lastVersion?.Version + 1 ?? 1;
 2219        draft.IsLatest = true;
 2220        draft = Initialize(draft);
 221
 2222        await mediator.SendAsync(new WorkflowDefinitionDraftSaving(draft), cancellationToken);
 2223        await workflowDefinitionStore.SaveAsync(draft, cancellationToken);
 2224        await mediator.SendAsync(new WorkflowDefinitionDraftSaved(draft), cancellationToken);
 225
 2226        if (lastVersion is null)
 2227            await mediator.SendAsync(new WorkflowDefinitionCreated(definition), cancellationToken);
 228
 2229        if (lastVersion is { IsPublished: true, IsLatest: true })
 230        {
 0231            lastVersion.IsLatest = false;
 0232            await workflowDefinitionStore.SaveAsync(lastVersion, cancellationToken);
 233        }
 234
 2235        return draft;
 2236    }
 237
 238    private WorkflowDefinition Initialize(WorkflowDefinition definition)
 239    {
 7240        if (definition.Id == null!)
 0241            definition.Id = identityGenerator.GenerateId();
 242
 7243        if (definition.DefinitionId == null!)
 0244            definition.DefinitionId = identityGenerator.GenerateId();
 245
 7246        if (definition.Version == 0)
 0247            definition.Version = 1;
 248
 7249        return definition;
 250    }
 251}