[codex] Resolve build warnings (#7458)

* Resolve build warnings

* Address Greptile review feedback

* Remove dead metadata null guard

* Preserve tenant-agnostic workflow activities
This commit is contained in:
Sipke Schoorstra 2026-05-17 14:58:10 +02:00 committed by GitHub
parent ec43976e30
commit 27ae1fae64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 66 additions and 33 deletions

View file

@ -6,7 +6,9 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Common.ShellFeatures;
[ShellFeature("DefaultFormatters")]
[ShellFeature(
"DefaultFormatters",
Description = "Registers default serializers and type converters")]
public class DefaultFormattersFeature : IShellFeature
{
public void ConfigureServices(IServiceCollection services)
@ -14,4 +16,4 @@ public class DefaultFormattersFeature : IShellFeature
TypeDescriptor.AddAttributes(typeof(Type), new TypeConverterAttribute(typeof(TypeTypeConverter)));
services.AddSingleton<IFormatter, JsonFormatter>();
}
}
}

View file

@ -9,7 +9,9 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Common.ShellFeatures;
[ShellFeature("Multitenancy")]
[ShellFeature(
"Multitenancy",
Description = "Provides tenant resolution, tenant scopes, and tenant lifecycle services")]
public class MultitenancyFeature : IShellFeature
{
private readonly Func<IServiceProvider, ITenantsProvider> _tenantsProviderFactory = sp => sp.GetRequiredService<DefaultTenantsProvider>();
@ -42,4 +44,4 @@ public class MultitenancyFeature : IShellFeature
.AddTransient<IDrainHandler, ActivateShellTenants>()
;
}
}
}

View file

@ -7,7 +7,9 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Common.ShellFeatures;
[UsedImplicitly]
[ShellFeature("StringCompression")]
[ShellFeature(
"StringCompression",
Description = "Registers string compression codecs")]
public class StringCompressionFeature : IShellFeature
{
public void ConfigureServices(IServiceCollection services)
@ -18,4 +20,4 @@ public class StringCompressionFeature : IShellFeature
.AddSingleton<ICompressionCodec, GZip>()
.AddSingleton<ICompressionCodec, Zstd>();
}
}
}

View file

@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Elsa.Dsl.ElsaScript.Ast;
using Elsa.Dsl.ElsaScript.Contracts;
using Elsa.Dsl.ElsaScript.Helpers;
@ -114,7 +115,7 @@ public class ElsaScriptCompiler(IActivityRegistryLookupService activityRegistryL
metadata.TryGetValue(key, out var value) ? ConvertValue<T>(value, default) : default;
private T GetMetadataValueOrDefault<T>(Dictionary<string, object> metadata, string key, T defaultValue) =>
metadata.TryGetValue(key, out var value) ? ConvertValue(value, defaultValue) : defaultValue;
metadata.TryGetValue(key, out var value) ? ConvertValue(value, defaultValue) ?? defaultValue : defaultValue;
private static T? ConvertValue<T>(object value, T? defaultValue)
{
@ -477,6 +478,7 @@ public class ElsaScriptCompiler(IActivityRegistryLookupService activityRegistryL
throw new NotSupportedException($"Expression type {exprNode.GetType().Name} is not supported as Expression");
}
[UnconditionalSuppressMessage("Trimming", "IL2060:Call to MakeGenericMethod can not be statically analyzed", Justification = "ElsaScript activity input types are discovered from runtime activity descriptors and must be bound dynamically.")]
private object CompileExpression(ExpressionNode exprNode, Type targetType)
{
// Check if targetType is already Input<T>
@ -598,4 +600,4 @@ public class ElsaScriptCompiler(IActivityRegistryLookupService activityRegistryL
private static string MapLanguageName(string dslLanguage) =>
LanguageMappings.TryGetValue(dslLanguage, out var mapped) ? mapped : dslLanguage;
}
}

View file

@ -454,7 +454,7 @@ public class ElsaScriptParser : IElsaScriptParser
var workflowWithoutMetadata = workflowKeyword
.And(identifier)
.Then(x => (WorkflowId: x.Item2.ToString(), Metadata: (IReadOnlyList<(string Name, object Value)>?)null));
.Then(x => (WorkflowId: x.Item2.ToString(), Metadata: (IReadOnlyList<(string Name, object Value)>)[]));
var workflowHeader = workflowWithMetadata.Or(workflowWithoutMetadata);
@ -466,12 +466,9 @@ public class ElsaScriptParser : IElsaScriptParser
var bodyElements = x.Item2;
var metadataDict = new Dictionary<string, object>();
if (header.Metadata != null)
foreach (var entry in header.Metadata)
{
foreach (var entry in header.Metadata)
{
metadataDict[entry.Name] = entry.Value;
}
metadataDict[entry.Name] = entry.Value;
}
// Separate use statements from regular statements in body

View file

@ -30,10 +30,10 @@ internal class ActivityOutputFunctionsDefinitionProvider(IActivityRegistryLookup
definitions.AddRange(from output in activityDescriptor.Outputs.Where(x => x.Name.IsValidVariableName())
select output.Name.Pascalize()
into outputPascalName
let activityNamePascalName = activity.Name.Pascalize()
let activityNamePascalName = activity.Name!.Pascalize()
select CreateFunctionDefinition(builder => builder.Name($"get{outputPascalName}From{activityNamePascalName}").ReturnType("any")));
}
return definitions;
}
}
}

View file

@ -13,7 +13,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Resilience.ShellFeatures;
[ShellFeature]
[ShellFeature(Description = "Provides workflow resilience strategies and retry attempt tracking")]
public class ResilienceFeature : IFastEndpointsShellFeature
{
public void ConfigureServices(IServiceCollection services)
@ -44,4 +44,4 @@ public class ResilienceFeature : IFastEndpointsShellFeature
.AddSingleton<ITransientExceptionStrategy, DefaultTransientExceptionStrategy>()
.AddSingleton<ITransientExceptionDetector, TransientExceptionDetector>();
}
}
}

View file

@ -472,7 +472,7 @@ public static class ExpressionExecutionContextExtensions
{
var activity = activityWithOutput.Activity;
var activityDescriptor = activityWithOutput.ActivityDescriptor;
var activityIdentifier = useActivityName ? activity.Name : activity.Id;
var activityIdentifier = useActivityName ? activity.Name! : activity.Id;
var activityIdPascalName = activityIdentifier.Pascalize();
foreach (var output in activityDescriptor.Outputs)
@ -568,4 +568,4 @@ public static class ExpressionExecutionContextExtensions
enumerable
])!;
}
}
}

View file

@ -6,7 +6,9 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.ShellFeatures;
[ShellFeature("CommitStrategies")]
[ShellFeature(
"CommitStrategies",
Description = "Registers workflow commit strategies")]
public class CommitStrategiesFeature : IShellFeature
{
public void ConfigureServices(IServiceCollection services)
@ -14,4 +16,4 @@ public class CommitStrategiesFeature : IShellFeature
services.AddSingleton<ICommitStrategyRegistry, DefaultCommitStrategyRegistry>();
services.AddStartupTask<PopulateCommitStrategyRegistry>();
}
}
}

View file

@ -30,7 +30,9 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.ShellFeatures;
[ShellFeature(DependsOn =
[ShellFeature(
Description = "Provides core workflow execution, activity execution, and workflow serialization services",
DependsOn =
[
"SystemClock",
"Expressions",
@ -177,4 +179,4 @@ public class WorkflowsFeature : IShellFeature
// Overridable services
services.AddScoped<ICommitStateHandler, NoopCommitStateHandler>();
}
}
}

View file

@ -9,8 +9,23 @@ namespace Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
/// <summary>
/// Provides activity descriptors based on <see cref="WorkflowDefinition"/>s stored in the database.
/// </summary>
public class WorkflowDefinitionActivityProvider(IWorkflowDefinitionStore store, WorkflowDefinitionActivityDescriptorFactory workflowDefinitionActivityDescriptorFactory, ITenantAccessor tenantAccessor) : IActivityProvider
public class WorkflowDefinitionActivityProvider : IActivityProvider
{
private readonly IWorkflowDefinitionStore _store;
private readonly WorkflowDefinitionActivityDescriptorFactory _workflowDefinitionActivityDescriptorFactory;
private readonly ITenantAccessor? _tenantAccessor;
public WorkflowDefinitionActivityProvider(IWorkflowDefinitionStore store, WorkflowDefinitionActivityDescriptorFactory workflowDefinitionActivityDescriptorFactory)
{
_store = store;
_workflowDefinitionActivityDescriptorFactory = workflowDefinitionActivityDescriptorFactory;
}
public WorkflowDefinitionActivityProvider(IWorkflowDefinitionStore store, WorkflowDefinitionActivityDescriptorFactory workflowDefinitionActivityDescriptorFactory, ITenantAccessor tenantAccessor) : this(store, workflowDefinitionActivityDescriptorFactory)
{
_tenantAccessor = tenantAccessor;
}
/// <inheritdoc />
public async ValueTask<IEnumerable<ActivityDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default)
{
@ -20,7 +35,14 @@ public class WorkflowDefinitionActivityProvider(IWorkflowDefinitionStore store,
VersionOptions = VersionOptions.All
};
var definitions = (await store.FindManyAsync(filter, cancellationToken)).ToList();
var definitions = (await _store.FindManyAsync(filter, cancellationToken)).ToList();
if (_tenantAccessor != null)
{
var currentTenantId = _tenantAccessor.TenantId;
definitions = definitions.Where(x => x.TenantId == Tenant.AgnosticTenantId || x.TenantId.NormalizeTenantId() == currentTenantId).ToList();
}
return CreateDescriptors(definitions).ToList();
}
@ -34,6 +56,6 @@ public class WorkflowDefinitionActivityProvider(IWorkflowDefinitionStore store,
var latestPublishedVersion = allDefinitions
.Where(x => x.DefinitionId == definition.DefinitionId && x.IsPublished)
.MaxBy(x => x.Version);
return workflowDefinitionActivityDescriptorFactory.CreateDescriptor(definition, latestPublishedVersion);
return _workflowDefinitionActivityDescriptorFactory.CreateDescriptor(definition, latestPublishedVersion);
}
}
}

View file

@ -17,7 +17,7 @@ public class MultitenancyTests(App app) : AppComponentTest(app)
public void DefaultTenant_ShouldUseEmptyStringAsId()
{
// Assert
Assert.Equal(string.Empty, Tenant.DefaultTenantId);
Assert.Empty(Tenant.DefaultTenantId);
Assert.Equal(Tenant.DefaultTenantId, Tenant.Default.Id);
}

View file

@ -88,7 +88,7 @@ public class ReloadWorkflowTests : AppComponentTest
// Set up the initial workflow version.
_testWorkflowProvider.MaterializedWorkflows = [workflowV1];
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
var activityTypeName = workflowV1.Workflow.Name.Pascalize();
var activityTypeName = workflowV1.Workflow.Name!.Pascalize();
var activityV1 = _activityRegistry.Find(activityTypeName);
Assert.Equal(1, activityV1!.Version);
@ -151,4 +151,4 @@ public class ReloadWorkflowTests : AppComponentTest
workflow.Name = definitionId;
return new(workflow, _testWorkflowProvider.Name, TestWorkflowMaterializer.MaterializerName);
}
}
}

View file

@ -17,7 +17,9 @@ public class ExceptionExtensionsTests
[InlineData(typeof(ThreadAbortException))]
public void FatalExceptions(Type exceptionType)
{
#pragma warning disable SYSLIB0050 // FormatterServices is needed to instantiate fatal exception types without throwing them.
var ex = (Exception)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(exceptionType);
#pragma warning restore SYSLIB0050
Assert.True(ex.IsFatal());
}

View file

@ -514,10 +514,10 @@ public class CachingWorkflowDefinitionServiceTests
.Returns(async callInfo => await callInfo.Arg<Func<ICacheEntry, Task<WorkflowGraphFindResult>>>()(Substitute.For<ICacheEntry>()));
_cache.FindOrCreateAsync<WorkflowDefinition>(Arg.Any<object>(), Arg.Any<Func<ICacheEntry, Task<WorkflowDefinition>>>())
.Returns(async callInfo => await callInfo.Arg<Func<ICacheEntry, Task<WorkflowDefinition>>>()(Substitute.For<ICacheEntry>()));
.Returns(async callInfo => (WorkflowDefinition?)await callInfo.Arg<Func<ICacheEntry, Task<WorkflowDefinition>>>()(Substitute.For<ICacheEntry>()));
_cache.FindOrCreateAsync<WorkflowGraph>(Arg.Any<object>(), Arg.Any<Func<ICacheEntry, Task<WorkflowGraph>>>())
.Returns(async callInfo => await callInfo.Arg<Func<ICacheEntry, Task<WorkflowGraph>>>()(Substitute.For<ICacheEntry>()));
.Returns(async callInfo => (WorkflowGraph?)await callInfo.Arg<Func<ICacheEntry, Task<WorkflowGraph>>>()(Substitute.For<ICacheEntry>()));
}
/// <summary>