feat: Add type-safe GetModule extension generator (Issue #2006)#2027
feat: Add type-safe GetModule extension generator (Issue #2006)#2027
Conversation
This adds a new incremental source generator that creates type-safe extension methods for retrieving module results: - For each class inheriting from Module<T>, generates: - GetXxxModule(this IModuleContext context) - returns ModuleResult<T> - GetXxxModuleIfRegistered(this IModuleContext context) - returns ModuleResult<T>? - Added ModuleClassInfo record type for holding module information - Added ModuleExtensionsGenerator implementing IIncrementalGenerator - Updated ModularPipelines.csproj to include source generator as analyzer - Updated ModularPipelines.Build.csproj for testing - Source generator included in NuGet package for consumers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SummaryAdds a source generator that creates type-safe GetModule extension methods for all registered modules to eliminate runtime type errors. Critical Issues1. Silent handling of duplicate module class names 2. NuGet package path construction unreliable Suggestions
VerdictREQUEST CHANGES - Duplicate module handling and NuGet packaging need fixes. |
… conflicts The CommandOptionsGenerator now generates BuildCommandLine() instead of Build() to avoid conflicts with options classes that have properties named Build (like AptGetOptions with --build flag). Also added partial keyword to all options classes for source generation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SummaryThis PR adds a source generator that creates type-safe extension methods (e.g., Critical Issues1. Generated method naming conflict (src/ModularPipelines.SourceGenerator/ModuleExtensionsGenerator.cs:180) The generated method names like According to issue #2006, the naming convention should be:
Current implementation generates:
Recommendation: Update line 180 to strip "Module" suffix when present. 2. NuGet packaging path issue (src/ModularPipelines/ModularPipelines.csproj:65) The target Recommendation: Use MSBuild properties to reference the built assembly, or ensure the configuration matches. Consider using the standard approach with Suggestions1. Namespace organization (src/ModularPipelines.SourceGenerator/ModuleExtensionsGenerator.cs:156) The generated extensions are placed in 2. Missing generator version The generator version is hardcoded to "1.0.0". Consider using assembly version or making it configurable. Verdict |
Per code review feedback, BuildModule now generates GetBuild() instead of GetBuildModule() for cleaner, more intuitive API: - BuildModule → GetBuild() / GetBuildIfRegistered() - DeployModule → GetDeploy() / GetDeployIfRegistered() Classes without "Module" suffix remain unchanged. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per user feedback, renamed methods to make it clearer that we're returning a ModuleResult<T>, not the module itself: - BuildModule → GetBuildModuleResult() / GetBuildModuleResultIfRegistered() - DeployModule → GetDeployModuleResult() / GetDeployModuleResultIfRegistered() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SummaryThis PR adds a source generator to create type-safe extension methods for module result retrieval. Critical Issues1. Breaking Change: Build() to BuildCommandLine() RenameLocation: src/ModularPipelines.SourceGenerator/BuildMethodGenerator.cs:36 The rename from Build() to BuildCommandLine() is a breaking API change that will break all existing code using generated options classes. Every consumer using generated options classes (Git, Docker, DotNet, etc.) will break on upgrade. Recommendation: Either keep Build() as the method name, OR clearly document as a breaking change with migration guidance. 2. Hardcoded Build Path in NuGet Package TargetLocation: src/ModularPipelines/ModularPipelines.csproj:65 The hardcoded relative path assumes specific directory structure, won't work correctly if projects are built independently, and build order dependency is not enforced. Recommendation: Use @(ReferencePath) or add explicit dependency to ensure correct build order. Suggestions3. XML Documentation EscapingLocation: ModuleExtensionsGenerator.cs:173,182 4. Method Naming Edge CaseLocation: ModuleExtensionsGenerator.cs:212-218 5. Duplicate Module Name HandlingLocation: ModuleExtensionsGenerator.cs:168 VerdictREQUEST CHANGES - Critical issues found: Breaking API change and NuGet packaging target issues |
SummaryAdds a source generator that creates type-safe extension methods for accessing module results, replacing the verbose two-parameter GetModule pattern with generated single-parameter methods like GetBuildModuleResult(). Critical Issues1. Breaking Change: Method Rename Without Context (BLOCKING) The PR renames Build() to BuildCommandLine() in the source generator without explanation in BuildMethodGenerator.cs:49. All Options classes changed from record to partial record. Issue: While my analysis confirms this is likely NOT a breaking change for consumers (the Build() method appears to be internal infrastructure only called by ICommandLineBuilder), the PR description makes no mention of this change. This is significant because it:
Required Action: Either explain in PR description why this rename is needed and confirm it's non-breaking, split this into a separate PR since it's unrelated to module extensions, or provide migration guidance if this IS breaking. 2. NuGet Package Distribution Issue (CRITICAL) ModularPipelines.csproj:60-66 uses hardcoded path for source generator packaging. Problems: hardcodes Configuration but doesn't ensure generator is built before packaging, uses fragile relative path, no guarantee DLL exists when package target runs, doesn't follow existing pattern used for ModularPipelines.Analyzers.Package. Better Approach: Create ModularPipelines.SourceGenerator.Package.csproj following the established pattern in src/ModularPipelines.Analyzers/ModularPipelines.Analyzers.Package/ModularPipelines.Analyzers.Package.csproj:16-33. 3. Build Integration Missing (CRITICAL) ModularPipelines.Build.csproj:26 added source generator reference but no verification that generated extensions actually work in the build pipeline. Missing from test plan. Suggestions
VerdictMust address:
|
Explains why the generated method is named BuildCommandLine() instead of Build() - to avoid conflicts with options classes that have properties named "Build" (e.g., AptGetOptions has a Build property for --build flag). In C#, a property and parameterless method cannot share the same name. This is internal infrastructure called by ICommandLineBuilder, so users don't call it directly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents that the "Module" edge case (class named exactly "Module") is already handled by the length check. Adds explicit example showing this edge case produces "Module" not an empty string. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addressed Review Feedback1. Build() to BuildCommandLine() Rename (ADDRESSED)Added documentation to
2. StripModuleSuffix Edge Case (ADDRESSED)Added documentation clarifying that the edge case for a class named exactly "Module" is already handled:
3. NuGet PackagingThe current approach works because:
The alternative pattern (separate 4. Duplicate Module NamesIf two modules in different namespaces have the same class name, the generator uses |
SummaryThis PR adds a Critical IssuesNone found ✅ Suggestions1. Verify No Breaking ChangesThe rename from
2. StripModuleSuffix Edge Case DocumentationIn
3. Missing XML Documentation in ModuleClassInfo.csThe new 4. NuGet Package Build Path ConcernsIn Verdict✅ APPROVE - No critical issues, but please verify the BuildCommandLine() method is actually invoked somewhere (Suggestion #1). |
SummaryThis PR adds a ModuleExtensionsGenerator for type-safe module access, fixes a naming conflict in generated options classes, and updates multiple options classes to support source generation. Critical Issues1. Silent Duplicate Module HandlingFile: src/ModularPipelines.SourceGenerator/ModuleExtensionsGenerator.cs:167-169 The generator groups modules by class name but only uses the first one, silently dropping duplicates. If multiple modules have the same class name in different namespaces, only the first generates an extension method. Impact: Users cannot access all their modules via generated extensions, with no warning or error. Fix: Detect duplicates and emit a diagnostic error/warning, include namespace in method name, or generate methods in the module namespace. 2. Unreliable NuGet Package ConfigurationFile: src/ModularPipelines/ModularPipelines.csproj:63-65 The packaging configuration hardcodes a bin path that may not exist when packaging. This does not establish a proper build dependency and can fail in multi-project or clean builds. Fix: Use proper MSBuild references to the built output. 3. PR Scope - Multiple Unrelated ChangesThis PR bundles two separate features: (1) New ModuleExtensionsGenerator and (2) Build to BuildCommandLine rename to fix AptGetOptions property conflict. Impact: Makes review harder, mixes breaking changes with new features. Recommendation: Consider splitting into two PRs. Suggestions4. Missing Breaking Change DocumentationThe Build to BuildCommandLine rename is a public API breaking change not mentioned in the PR description. 5. Module Discovery PerformanceConsider moving the IsAbstract check earlier in the pipeline to avoid unnecessary work. VerdictREQUEST CHANGES - Critical issues must be fixed before merging |
SummaryThis PR adds a ModuleExtensionsGenerator source generator to create type-safe extension methods for module access and renames the generated Build() method to BuildCommandLine() to avoid property name conflicts. Critical IssuesNone found Previous Review StatusAddressed:
Remaining concerns:
Suggestions
VerdictAPPROVE - No critical issues. The PR successfully implements type-safe module extensions per issue 2006. Previous review concerns have been documented. The remaining items are clarifications and minor improvements that do not block merge. |
Summary
ModuleExtensionsGeneratorsource generator that creates type-safeGetModule<T>andGetModuleIfRegistered<T>extension methodsChanges
ModuleExtensionsGenerator.csinModularPipelines.SourceGeneratorModuleClassInfo.csrecord for tracking module informationTest Plan
Closes #2006
🤖 Generated with Claude Code