feat: add gateway aggregation pattern#317
Conversation
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Test Results 1 files 1 suites 2m 27s ⏱️ Results for commit d707963. |
🔍 PR Validation ResultsVersion: `` ✅ Validation Steps
📊 ArtifactsDry-run artifacts have been uploaded and will be available for 7 days. This comment was automatically generated by the PR validation workflow. |
Code Coverage |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #317 +/- ##
==========================================
+ Coverage 90.14% 95.92% +5.77%
==========================================
Files 444 448 +4
Lines 36964 37254 +290
Branches 5248 5290 +42
==========================================
+ Hits 33322 35736 +2414
+ Misses 1609 1518 -91
+ Partials 2033 0 -2033
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds Gateway Aggregation as a first-class PatternKit pattern, including a fluent runtime API, a Roslyn incremental generator for factory creation, and an end-to-end “Customer Dashboard” demo integrated with DI and ASP.NET Core routing. This lands the pattern into the production readiness catalogs and documentation sets (patterns, generators, examples).
Changes:
- Introduces
GatewayAggregation<TRequest,TResponse>runtime API with per-part results, composition, and explicit failure reporting. - Adds
GenerateGatewayAggregationsource generator + attribute surface + generator diagnostics + generator tests. - Adds a DI + ASP.NET Core minimal API example and wires it into catalogs, coverage docs, and TOCs.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/PatternKit.Tests/Cloud/GatewayAggregation/GatewayAggregationTests.cs | Runtime API behavioral coverage (success, failures, validation). |
| test/PatternKit.Generators.Tests/GatewayAggregationGeneratorTests.cs | Verifies generated factory output and diagnostic IDs for invalid declarations. |
| test/PatternKit.Generators.Tests/AbstractionsAttributeCoverageTests.cs | Ensures new generator attributes expose defaults/config and are tracked in attribute coverage. |
| test/PatternKit.Examples.Tests/ProductionReadiness/PatternKitPatternCatalogTests.cs | Updates catalog expectations to include the new pattern and family counts. |
| test/PatternKit.Examples.Tests/GatewayAggregationDemo/CustomerDashboardGatewayAggregationDemoTests.cs | Validates fluent/generated demo paths and DI importability. |
| src/PatternKit.Generators/GatewayAggregation/GatewayAggregationGenerator.cs | New incremental generator that emits a gateway factory from fetches + composer. |
| src/PatternKit.Generators/AnalyzerReleases.Unshipped.md | Registers new generator diagnostic IDs (PKGA001–PKGA004). |
| src/PatternKit.Generators.Abstractions/Cloud/GatewayAggregationAttributes.cs | Adds generator attribute API: host, fetch, composer attributes. |
| src/PatternKit.Examples/ProductionReadiness/PatternKitPatternCatalog.cs | Registers Gateway Aggregation pattern coverage descriptor and links docs/tests/examples. |
| src/PatternKit.Examples/ProductionReadiness/PatternKitExampleCatalog.cs | Adds “Customer Dashboard Gateway Aggregation” example descriptor. |
| src/PatternKit.Examples/GatewayAggregationDemo/CustomerDashboardGatewayAggregationDemo.cs | New demo: downstream clients, fluent + generated construction, DI + endpoint mapping. |
| src/PatternKit.Examples/DependencyInjection/PatternKitExampleServiceCollectionExtensions.cs | Adds AddCustomerDashboardGatewayAggregationExample and includes it in AddPatternKitExamples. |
| src/PatternKit.Core/Cloud/GatewayAggregation/GatewayAggregation.cs | Adds the core gateway aggregation runtime types and fluent builder. |
| docs/patterns/toc.yml | Adds Gateway Aggregation to pattern TOC under Cloud Architecture. |
| docs/patterns/cloud/gateway-aggregation.md | Adds the pattern doc + quick runtime snippet + guidance. |
| docs/guides/pattern-coverage.md | Extends coverage matrix with the new runtime + generator entries. |
| docs/generators/toc.yml | Adds Gateway Aggregation generator doc to TOC. |
| docs/generators/index.md | Adds generator index entry + quick reference snippet. |
| docs/generators/gateway-aggregation.md | Adds generator guide + example + diagnostic list. |
| docs/examples/toc.yml | Adds the customer dashboard gateway aggregation example to examples TOC. |
| docs/examples/index.md | Adds example summary entry to examples landing page. |
| docs/examples/customer-dashboard-gateway-aggregation.md | Adds example doc with DI usage snippet and endpoint mapping note. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private static FetchMember[] FetchMembers(INamedTypeSymbol type) | ||
| => type.GetMembers().OfType<IMethodSymbol>() | ||
| .Select(method => new | ||
| { | ||
| Method = method, | ||
| Attribute = method.GetAttributes().FirstOrDefault(attr => attr.AttributeClass?.ToDisplayString() == FetchAttributeName) | ||
| }) | ||
| .Where(static item => item.Attribute is not null) | ||
| .Select(static item => new FetchMember((string)item.Attribute!.ConstructorArguments[0].Value!, item.Method)) | ||
| .ToArray(); |
| var fetches = FetchMembers(type); | ||
| var composers = MembersWith(type, ComposerAttributeName); | ||
| if (fetches.Length == 0 || composers.Length != 1) | ||
| { | ||
| context.ReportDiagnostic(Diagnostic.Create(MissingMembers, node.Identifier.GetLocation(), type.Name)); | ||
| return; | ||
| } | ||
|
|
||
| var duplicate = fetches.GroupBy(static item => item.Name, StringComparer.OrdinalIgnoreCase).FirstOrDefault(static group => group.Count() > 1); | ||
| if (duplicate is not null) | ||
| { | ||
| context.ReportDiagnostic(Diagnostic.Create(DuplicateFetch, node.Identifier.GetLocation(), duplicate.Key)); | ||
| return; | ||
| } |
| sb.Append("abstract "); | ||
| else if (type.IsSealed && type.TypeKind == TypeKind.Class) | ||
| sb.Append("sealed "); | ||
| sb.Append("partial ").Append(type.TypeKind == TypeKind.Struct ? "struct" : "class").Append(' ').Append(type.Name).AppendLine(); |
| var ns = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToDisplayString(); | ||
| var requestTypeName = requestType.ToDisplayString(TypeFormat); | ||
| var responseTypeName = responseType.ToDisplayString(TypeFormat); | ||
| var sb = new StringBuilder(); | ||
| sb.AppendLine("// <auto-generated/>"); | ||
| sb.AppendLine("#nullable enable"); | ||
| sb.AppendLine(); | ||
| if (ns is not null) | ||
| { | ||
| sb.Append("namespace ").Append(ns).AppendLine(";"); | ||
| sb.AppendLine(); | ||
| } | ||
|
|
||
| sb.Append(GetAccessibility(type.DeclaredAccessibility)).Append(' '); | ||
| if (type.IsStatic) | ||
| sb.Append("static "); | ||
| else if (type.IsAbstract && type.TypeKind == TypeKind.Class) | ||
| sb.Append("abstract "); | ||
| else if (type.IsSealed && type.TypeKind == TypeKind.Class) | ||
| sb.Append("sealed "); | ||
| sb.Append("partial ").Append(type.TypeKind == TypeKind.Struct ? "struct" : "class").Append(' ').Append(type.Name).AppendLine(); | ||
| sb.AppendLine("{"); |
Closes #309
Summary
Local validation
GatewayAggregationGeneratorTests|FullyQualifiedNameAbstractionsAttributeCoverageTestsNote: local full examples build still hits the existing CS9057 compiler/analyzer mismatch; hosted CI validates examples/docs.