Skip to content

Commit cebbf5e

Browse files
author
vp
committed
feat(pipeline): add source-generated pipeline attributes and tests
- Introduced PipelineAttribute, PipelineStepAttribute, PipelineHookAttribute, and PipelineBehaviorAttribute for defining pipelines and their components. - Implemented GeneratedContextPipeline and GeneratedNoContextPipeline with respective steps, hooks, and behaviors. - Added unit tests for pipeline execution and generator diagnostics, ensuring proper functionality and error reporting for invalid configurations.
1 parent 13a33d0 commit cebbf5e

12 files changed

Lines changed: 1598 additions & 100 deletions

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# Changelog
22

3-
This changelog is maintained from version tags in the `main` branch. It covers the full tagged release history on `main`.
3+
This changelog includes unreleased changes on `main` and the full tagged release history from the `main` branch.
4+
5+
## [10.0.104] - 2026-03-31
6+
7+
- Added a new Pipeline feature in `Common.Utilities` with fluent definition and registration APIs, runtime behaviors, hooks, execution tracking, inline step support, and source-generated attributes to reduce registration boilerplate.
48

59
## [10.0.103] - 2026-03-19
610

7-
- Added the new `Application.DataPorter` framework for multi-format import and export.
11+
- Added the new `Application.DataPorter` feature for multi-format import and export.
812
- Introduced profile-based and attribute-based configuration, validation, streaming, compression, templates, typed row interception, progress reporting, and extensible custom formats.
913
- Added fluent import, export, and template option builders for a more discoverable API.
1014

docs/features-pipelines.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,3 +800,123 @@ The Pipelines feature integrates especially well with:
800800

801801
Together, these features support explicit flow control, rich validation, and consistent outcome
802802
handling without introducing a heavyweight orchestration framework.
803+
804+
## Appendix A: Pipeline Code Generation
805+
806+
The Pipelines feature also offers an optional source-generation layer for packaged pipelines. It is
807+
meant to remove repetitive authoring boilerplate, while still using the same runtime, the same
808+
registration model, and the same execution semantics described above.
809+
810+
### What It Adds
811+
812+
Code generation is focused on packaged pipeline definitions:
813+
814+
- declare a `partial` pipeline class with `[Pipeline]`
815+
- declare step methods with `[PipelineStep(order)]`
816+
- add class-level hooks with `[PipelineHook(typeof(...))]`
817+
- add class-level behaviors with `[PipelineBehavior(typeof(...))]`
818+
819+
The generator then emits the normal packaged pipeline definition plumbing for you. Generated
820+
pipelines still register like manual packaged pipelines:
821+
822+
```csharp
823+
services.AddPipelines()
824+
.WithPipeline<OrderImportPipeline>();
825+
```
826+
827+
and resolve the same way:
828+
829+
```csharp
830+
var pipeline = pipelineFactory.Create<OrderImportPipeline, OrderImportContext>();
831+
```
832+
833+
### Example
834+
835+
```csharp
836+
[Pipeline(typeof(OrderImportContext))]
837+
[PipelineHook(typeof(PipelineAuditHook))]
838+
[PipelineBehavior(typeof(PipelineTracingBehavior))]
839+
[PipelineBehavior(typeof(PipelineTimingBehavior))]
840+
public partial class OrderImportPipeline : PipelineDefinition<OrderImportContext>
841+
{
842+
[PipelineStep(10)]
843+
public Result Validate(OrderImportContext context, Result result)
844+
{
845+
return result.WithMessage("validated");
846+
}
847+
848+
[PipelineStep(20)]
849+
public async Task<Result> LoadAsync(
850+
OrderImportContext context,
851+
Result result,
852+
IOrderImportRepository repository,
853+
CancellationToken cancellationToken)
854+
{
855+
var orders = await repository.LoadAsync(context.SourceFileName, cancellationToken);
856+
context.ImportedOrderCount = orders.Count;
857+
return result.WithMessage($"loaded {orders.Count} orders");
858+
}
859+
860+
[PipelineStep(30, Name = "persist-generated")]
861+
public PipelineControl Persist(
862+
OrderImportContext context,
863+
Result result,
864+
IOrderRepository repository)
865+
{
866+
repository.SaveImportedOrders(context.TenantId);
867+
return PipelineControl.Continue(result.WithMessage("persisted"));
868+
}
869+
870+
partial void OnConfigureGenerated(IPipelineDefinitionBuilder<OrderImportContext> builder)
871+
{
872+
builder.AddStep(ctx => ctx.Pipeline.Items.Set("extended", true), name: "manual-extension");
873+
}
874+
}
875+
```
876+
877+
### Supported Step Signatures
878+
879+
Generated step methods may use these runtime inputs:
880+
881+
- `TContext`
882+
- `Result`
883+
- `CancellationToken`
884+
885+
Any additional method parameters are treated as DI services and resolved through the normal
886+
container.
887+
888+
Supported return types are:
889+
890+
- `void`
891+
- `Task`
892+
- `Result`
893+
- `Task<Result>`
894+
- `PipelineControl`
895+
- `Task<PipelineControl>`
896+
897+
The runtime behavior matches manual steps:
898+
899+
- `void` and `Task` keep the current carried `Result` and continue
900+
- `Result` and `Task<Result>` replace the carried `Result` and continue
901+
- `PipelineControl` and `Task<PipelineControl>` provide full flow control, including `Retry(...)`,
902+
`Break(...)`, and `Terminate(...)`
903+
904+
### Naming and Diagnostics
905+
906+
Generated pipelines follow the same naming conventions as manual pipelines:
907+
908+
- pipeline names default from the class name, for example `OrderImportPipeline` -> `order-import`
909+
- step names default from the method name, for example `LoadAsync` -> `load`
910+
- explicit names can still be provided through `PipelineStepAttribute.Name`
911+
912+
The generator also emits compile-time diagnostics for invalid authoring, including:
913+
914+
- pipeline class is not `partial`
915+
- pipeline does not inherit `PipelineDefinition` or `PipelineDefinition<TContext>`
916+
- unsupported step method signatures
917+
- `async void` step methods
918+
- duplicate generated step orders
919+
- duplicate generated step names
920+
- incompatible hook or behavior types
921+
922+
The source generation acts as a thin authoring convenience layer instead of a second hidden pipeline model.

src/Common.Utilities.CodeGen/Common.Utilities.CodeGen.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<IncludeBuildOutput>false</IncludeBuildOutput>
1111
<BuildOutputTargetFolder>analyzers</BuildOutputTargetFolder>
1212
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
13-
<NoWarn>NU5128</NoWarn>
13+
<NoWarn>NU5128;RS2008</NoWarn>
1414
</PropertyGroup>
1515

1616
<ItemGroup>
@@ -34,4 +34,4 @@
3434
<ItemGroup>
3535
<Folder Include="Pipelines\" />
3636
</ItemGroup>
37-
</Project>
37+
</Project>

0 commit comments

Comments
 (0)