Add WrapperGenerator: a standalone cmdlet generator that reproduces published MS Graph cmdlet names - #3682
Open
Joywambui-maina wants to merge 2 commits into
Open
Add WrapperGenerator: a standalone cmdlet generator that reproduces published MS Graph cmdlet names#3682Joywambui-maina wants to merge 2 commits into
Joywambui-maina wants to merge 2 commits into
Conversation
…h cmdlet-name parity checks and unit tests
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new standalone .NET CLI generator (tools/WrapperGenerator) intended to reproduce the published Microsoft.Graph PowerShell cmdlet names deterministically by deriving nouns from URL paths (with per-word singularization), alongside tests and tooling to validate parity against MgCommandMetadata.json. It also updates CI tooling to install a newer .NET SDK required to build the new net10.0 projects.
Changes:
- Introduces
tools/WrapperGenerator(OpenAPI reader + naming + emission) to generate wrapper cmdlet C# sources and a lock file. - Adds a dedicated test project covering naming/singularization/schema-property extraction and generation regressions.
- Adds a parity gate script (
tools/Compare-WrapperCmdletNames.ps1) and updates pipeline tooling to install the needed .NET SDK.
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/WrapperGenerator/WrapperGenerator.csproj | New net10.0 CLI project and package dependencies for OpenAPI reading/logging. |
| tools/WrapperGenerator/Program.cs | CLI entry point: arg parsing, spec loading, include-path filtering, run + lockfile write. |
| tools/WrapperGenerator/PowerShellWrapperGenerationService.cs | Orchestrates operation selection, GET pairing, and writing emitted .g.cs files. |
| tools/WrapperGenerator/CmdletNaming.cs | Implements verb/noun resolution and Kiota builder-expression construction. |
| tools/WrapperGenerator/Singularizer.cs | Path-segment per-word singularization rules to match published cmdlet nouns. |
| tools/WrapperGenerator/NamingOverrides.cs | Data-driven overrides/suppressions to mirror published SDK AutoRest directives. |
| tools/WrapperGenerator/IncludePathFilter.cs | Filters OpenAPI paths/operations based on --include-path patterns. |
| tools/WrapperGenerator/CmdletEmitter.cs | Emits cmdlet C# templates (GET/list, dispatcher, new/update/remove, shared auth helpers). |
| tools/WrapperGenerator/SchemaProperties.cs | Extracts shallow primitive body properties for New/Update parameter flattening. |
| tools/WrapperGenerator/OperationInfo.cs | Operation metadata record used during naming/emission decisions. |
| tools/WrapperGenerator/EmitContext.cs | Carries emitter namespace settings (client namespace + cmdlet namespace). |
| tools/WrapperGenerator/GeneratorConfig.cs | Records generator run configuration (client namespace, output path). |
| tools/WrapperGenerator/GeneratorExtensions.cs | Shared string casing helpers + OpenAPI $ref ID extraction. |
| tools/WrapperGenerator/README.md | Documents naming algorithm, output shapes, build/run/test steps, and known gaps. |
| tools/WrapperGenerator.Tests/WrapperGenerator.Tests.csproj | New net10.0 test project referencing WrapperGenerator. |
| tools/WrapperGenerator.Tests/NamingTests.cs | Golden naming/singularization/builder-expression tests against published cmdlet expectations. |
| tools/WrapperGenerator.Tests/SchemaPropertiesTests.cs | Tests property extraction and passwordProfile detection behavior. |
| tools/WrapperGenerator.Tests/GenerationServiceRegressionTests.cs | Regression tests ensuring generator skips unsupported shapes without throwing. |
| tools/WrapperGenerator.Tests/EmitterTests.cs | Tests emitter escaping of spec-derived string literals (quotes). |
| tools/Compare-WrapperCmdletNames.ps1 | New parity gate: reconstructs Method+URI from generated source and joins to oracle inventory. |
| .azure-pipelines/common-templates/install-tools.yml | Installs an additional .NET SDK to support building net10.0 tooling. |
| .gitignore | Ignores sweep_results.json. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| null, | ||
| MyInvocation.BoundParameters, internalCmdletName); | ||
| } | ||
| {{CatchBlock(TargetId(itemNaming))}} |
Comment on lines
+156
to
+157
| $cmdletAttrPattern = '\[Cmdlet\(Verbs\w+\.(\w+),\s*"([^"]+)"' | ||
| $callChainPattern = 'client\.([A-Za-z0-9_.\[\]]+)\.(Get|Post|Patch|Put|Delete)Async\(' |
Comment on lines
+185
to
+187
| $verb = $attrMatch.Groups[1].Value | ||
| $generatedNoun = $attrMatch.Groups[2].Value | ||
| $publishedNoun = $generatedNoun -replace '_(List|Get)$', '' |
Comment on lines
+99
to
+106
| foreach ($token in ($BuilderExpression -split '\.')) { | ||
| if ($token -notmatch '^([A-Za-z0-9]+)(\[([A-Za-z0-9]+)\])?$') { | ||
| return $null | ||
| } | ||
| $prop = $Matches[1] | ||
| $segments += ($prop.Substring(0, 1).ToLowerInvariant() + $prop.Substring(1)) | ||
| if ($Matches[3]) { $segments += '{param}' } | ||
| } |
|
|
||
| ## The one subtle part: list + item GET become one cmdlet | ||
|
|
||
| Graph has two GETs for a resource — the collection (`GET …/messages`) and a single item (`GET …/messages/{message-id}`) — but the published SDK exposes **one** cmdlet, `Get-MgUserMessage`,that does both: no `-MessageId` lists them, a `-MessageId` fetches one. |
Author
|
@microsoft-github-policy-service agree company="Microsoft" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes Proposed
tools/WrapperGenerator, a standalone .NET CLI that generates C# cmdletclasses (e.g.
Get-MgUserMessage) from Graph's OpenAPI descriptionoperationIds, for deterministic naming
List/Getparameter sets forwarding to internal cmdlets
names from
MgCommandMetadata.jsontools/Compare-WrapperCmdletNames.ps1for parity validation against the command metadata inventory.azure-pipelines/common-templates/install-tools.ymlto install the.NET 10 SDK so CI can build the
net10.0generator projectsWhy
Customer scripts depend on the exact cmdlet names the SDK ships —
Get-MgUserMessage, notGet-MgUsersMessages. When nouns are derived from operationIds, generated names leak whatever plurality the spec author chose, and collisions have occurred. Path-based deterministic naming with singularization rules keeps name parity stable.Validation
dotnet teston net10.0).(
MgCommandMetadata.json) usingtools/Compare-WrapperCmdletNames.ps1: every generated cmdlet whose API call exists in the published SDK matches the published name exactly (e.g. BackupRestore 183/186, Bookings 129/131). The handful of non-matches are endpoints with no published cmdlet to compare against — not naming mismatches.wiring is documented as future work.