원클릭으로
mpg-migration
// Handles Azure SDK for .NET management-plane migrations from AutoRest/Swagger to TypeSpec; use for MPG, mgmt migration, or Azure.ResourceManager.* migration requests.
// Handles Azure SDK for .NET management-plane migrations from AutoRest/Swagger to TypeSpec; use for MPG, mgmt migration, or Azure.ResourceManager.* migration requests.
Roll dice using a random number generator. Use when asked to roll a die (d6, d20, etc.), roll dice, or generate a random dice roll.
Roll dice using a random number generator.
Generate the code from typespec for C#. Parameter: C# SDK repository root location <cs_root>.
Generate a test given sample. Parameters: <cs_root> C# SDK repository root; <package_name> Package name: one of Azure.AI.Projects, Azure.AI.Projects.Agents or Azure.AI.Extensions.OpenAI; <sample_name> the sample to use as a starting point for the test.
Build the matrix of all the samples throughout different frameworks.
Translate the Azure SDK sample from python to C# and generate markdownn file for the sample. Parameters: <cs_root> C# SDK repository root; <python_root> python SDK repository root; <package_name> Package name: one of Azure.AI.Projects, Azure.AI.Projects.Agents or Azure.AI.Extensions.OpenAI; <sample_name> The name of sample file in Python SDK repository.
| name | mpg-migration |
| description | Handles Azure SDK for .NET management-plane migrations from AutoRest/Swagger to TypeSpec; use for MPG, mgmt migration, or Azure.ResourceManager.* migration requests. |
Migrate an Azure SDK for .NET management library from AutoRest/Swagger to TypeSpec.
Use this skill only for management-plane packages named like Azure.ResourceManager.*.
Typical triggers:
sdk/<service>/Azure.ResourceManager.<Service>/azure-rest-api-specs repo path if it is not present at ../azure-rest-api-specssdk/<service>/Azure.ResourceManager.<Service>/../azure-rest-api-specs with TypeSpec for this service. Ask user for path if not found.<service>-mpg-migration in both repos, branched off mainsrc/Generated/ or metadata.json by hand.ApiCompatBaseline.txt entries or disable ApiCompat/package validation.@@clientName, @@alternateType, @@markAsPageable.Proceed autonomously through the normal generate/build/fix loop. Ask the user only when:
client.tspmain.src/Custom/, src/Customization/, src/Customized/, hand-written partials, backward-compat shims) so stale customizations do not hide real migration problems. When resuming, preserve minimal compatibility shims that were intentionally reintroduced during earlier migration work.tsp-location.yaml: set emitterPackageJsonPath: eng/azure-typespec-http-client-csharp-mgmt-emitter-package.json.SaveInputs=true so tspCodeModel.json is preserved for the next step: pwsh eng/packages/http-client-csharp-mgmt/eng/scripts/RegenSdkLocal.ps1 -Services "<Service>" -LocalSpecRepoPath <path> -SaveInputs (or dotnet build /t:GenerateCode /p:SaveInputs=true in src/).<ApiCompatVersion> in the .csproj.
$scripts = "eng/packages/http-client-csharp-mgmt/eng/scripts"
pwsh $scripts/Get-PreviousGaResourceHierarchy.ps1 -ProjectPath sdk/<svc>/Azure.ResourceManager.<Svc>/src -OutFile ga-hierarchy.json
pwsh $scripts/Get-ResourceHierarchyFromTspCodeModel.ps1 -TspCodeModelPath sdk/<svc>/Azure.ResourceManager.<Svc>/src -GeneratedDir sdk/<svc>/Azure.ResourceManager.<Svc>/src/Generated -OutFile new-hierarchy.json
pwsh $scripts/Compare-ResourceHierarchy.ps1 -GAJson ga-hierarchy.json -NewJson new-hierarchy.json
Verification semantics — every GA resource must exist in the new SDK with the same ResourceType, parent set, scope, and singleton flag. Class-name renames are reported but not blocking.
0 → hierarchy matches; continue.1 → structural drift (missing resource / parent / scope / singleton flip). Block and fix spec-side first (typespec-azure decorators such as @parentResource, @singleton, @@hierarchyBuilding, scope-defining templates) before entering the Phase 2 build-fix loop, otherwise downstream ApiCompat work will compound.2 → class-name renames only, structural hierarchy is intact. Non-blocking; record the renames in the migration status and address them during Phase 2 alongside other surface-level fixes.Fix errors spec-side (decorators in client.tsp with "csharp" scope) or SDK-side (custom code in src/Customization/). Always verify zero swagger diff after spec changes.
After each fix: regenerate if spec changed → rebuild → check remaining errors → repeat until clean. Apply this same classify-first loop to both compile/build errors and breaking-change remediation from ApiCompat/API diff review.
Before fixing an issue, categorize it first so the mitigation goes to the right layer and we do not paper over the real cause.
| Category | Typical symptoms | Preferred fix |
|---|---|---|
| Spec-shape issue | Wrong names, types, visibility, paging shape, inheritance, or operation grouping | Fix in client.tsp using decorators first |
| SDK compatibility gap | ApiCompat failures such as missing types/members, signature changes, or lost convenience entry points | Add targeted compatibility shims in SDK custom code |
| Customization drift | Old handwritten code conflicts with the new generated surface or masks the real migration issue | Remove it first; only reintroduce a minimal shim if Phase 3 proves it is still needed |
| Generated-code drift | Verify Generated Code or local regen changes files after a clean build | Regenerate, export API, and commit the produced output |
| Generator bug | Emitted code is structurally wrong and cannot be safely corrected with decorators or normal customizations | Stop, minimize the repro, and file a generator issue |
During the loop, keep a running list of remaining issues grouped by category. This makes it clear which items are real migration breaks, which are compatibility shims, and which must be fixed in the generator.
For SDK-side custom code, prefer MCP tools for deterministic edits:
add_using_directive / remove_using_directiveregex_replacementnullable_annotation_fixrename_codegen_typeadd_codegen_suppressUse them in a loop: build/classify → batch MCP fixes → regenerate if CodeGen* attributes changed → hand-write only the remaining compatibility logic. Use this same loop again in Phase 3 when mitigating breaking changes; do not treat ApiCompat work as a separate ad hoc cleanup step.
Treat deleted custom code as suspect by default. Re-add only the smallest compatibility layer required to preserve the shipped API or behavior after the generated surface has stabilized.
| Problem | Decorator |
|---|---|
| Wrong property type | @@alternateType(Model.prop, targetType, "csharp") |
| Wrong name | @@clientName(target, "NewName", "csharp") |
| Model should be input and output | @@usage(Model, Usage.input, "csharp") (decorator appends; only specify the missing flag) |
| Needs pageable return type | @@markAsPageable(Interface.op, "csharp") |
| Flatten properties envelope | @@flattenProperty(Model.properties, "csharp") |
| Change base type | @@hierarchyBuilding(Model, TargetBase, "csharp") |
| Wrong operation parameter type | @@alternateType(Interface.op::parameters.param, targetType, "csharp") |
| Operation name collision | @@clientLocation(Interface.op, "GroupName", "csharp") |
Every file needs a justification comment.
For Arm<Package>ModelFactory overloads added only for backward compatibility, prefer delegating to a generated public model-factory overload. The compatibility overload should translate renamed parameters or enum/value types, then call the generated overload rather than constructing generated models, internal Properties bags, or internal constructors directly.
This preserves the purpose of model factories: callers can provide arbitrary values for both read-write and read-only properties. Avoid adding SDK customizations or constructors for internal members just to support a custom factory overload; first look for a public generated factory overload or public model surface that can receive the same values.
| Problem | Fix |
|---|---|
| Flattened properties lost (polymorphic type) | Shim properties delegating to Properties bag |
| Protected constructor missing (discriminated base) | protected ctor in partial class |
Property lost due to @@alternateType model swap | Add property in partial class |
pwsh eng/scripts/Export-API.ps1 <service>origin/main API file.ApiCompatBaseline.txt.After the API diff is clean for missing/changed members, review every new public API introduced by the migration before treating it as acceptable. New APIs require explicit classification:
| Category | How to identify it | Required action |
|---|---|---|
| Real service/API-version addition | Operation/model/property exists only in the newer TypeSpec input/API version and has no equivalent in the previous GA swagger/API surface | Keep it. Note in the migration status/PR discussion that it comes from an API-version bump or newly onboarded operation. |
| Rename of an existing API | New method/type/property has the same operation id, route, resource type, or model semantics as an API that existed in the previous GA SDK | Prefer spec-side @@clientName/decorators so the generated name stays compatible. If decorators cannot express it, suppress the generated renamed member and add the smallest SDK-side compatibility implementation using the GA name. Do not keep both names unless there is a deliberate approved reason. |
| Generator convenience/drift | New convenience overload, operation grouping, or pageable shape appears only because the TypeSpec generator names or groups the same REST operation differently | Treat as a potential rename/compat issue. Investigate against previous GA API listings and operation ids before keeping it. |
For every new member, compare against:
origin/main API file or restored ApiCompat assembly).If a new API is actually a rename of an existing method, fix the rename instead of documenting it as additive. This is especially important for operation methods: method names should remain verb-style and compatible with the GA SDK unless the old name was wrong and reviewers explicitly accept the new name.
Review changes against the mpg-migration-pr-review skill rules locally — check customization quality rules, decorator preference rules, and the Phase 3 new API triage. Fix issues before proceeding.
Before opening the SDK PR:
CHANGELOG.md has a short migration note.ci.mgmt.yml exists if the package does not already have one.pre-commit-checks skill on the SDK package.Azure/azure-rest-api-specs.tsp-location.yaml to point to fork commit.Azure/azure-sdk-for-net.Use concise PR titles:
Add csharp customizations for <Service> migration[Mgmt] <PackageName>: Migrate to TypeSpecclient.tsp or SDK custom code and link the issue.When pausing, update the draft SDK PR description with the current state. If no draft PR exists yet, create one at that point and use its description as the tracker going forward:
## Phase 2 — Fix Build Errors
Blocked: [#58138](https://github.com/Azure/azure-sdk-for-net/issues/58138) — CollectionResultOfT name collision
Remaining breaks: ApplicationPatch base type change, model factory signatures
Keep it minimal — just current phase, blockers, and unfinished work. On resume, read the PR description first.
dotnet build is cleantsp-location.yaml points to the final spec commit used by the PR