mpg-migration

star 6.0k

Handles Azure SDK for .NET management-plane migrations from AutoRest/Swagger to TypeSpec; use for MPG, mgmt migration, or Azure.ResourceManager.* migration requests.

Azure By Azure schedule Updated 6/12/2026

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.

MPG Migration Workflow

Use for Azure SDK for .NET management-plane migrations from AutoRest/Swagger to TypeSpec for packages named Azure.ResourceManager.*.

Inputs

  • SDK package path: sdk/<service>/Azure.ResourceManager.<Service>/
  • Local azure-rest-api-specs path if not at ../azure-rest-api-specs
  • Branches in both repos, normally <service>-mpg-migration from main

Non-Negotiables

  • Never hand-edit src/Generated/ or metadata.json.
  • Never add ApiCompat baselines or disable ApiCompat/package validation, except targeted WirePathAttribute removal entries in the centralized baseline file.
  • Prefer client.tsp decorators with "csharp" scope before SDK custom code.
  • Root-cause every ApiCompat/API diff before adding custom code.
  • SDK custom code is only for backward compatibility or cases decorators cannot express.
  • Do not overwrite dirty user work in either repo.

Ask the user only when the spec repo path is missing, a fix requires files beyond client.tsp, or a generator bug has no safe workaround.

Setup

  1. If resuming, read the draft SDK PR description first and continue from its phase/blockers.
  2. Check git status in SDK and spec repos, then sync both to latest main without disturbing unrelated dirty files.
  3. Fresh migration only: inventory and remove old SDK custom code (src/Custom/, src/Customization/, src/Customized/, hand-written partials, old shims) before first generation. Re-add only proven-needed compatibility shims later.
  4. Remove AutoRest config: delete <IncludeAutorestDependency>true</IncludeAutorestDependency> and remove/replace src/autorest.md.
  5. Set tsp-location.yaml to emitterPackageJsonPath: eng/azure-typespec-http-client-csharp-mgmt-emitter-package.json.
  6. Generate with saved inputs so tspCodeModel.json is preserved for hierarchy checks. -Services must be the exact package folder name, not service directory:
    pwsh eng/packages/http-client-csharp-mgmt/eng/scripts/RegenSdkLocal.ps1 -Services "Azure.ResourceManager.<Service>" -LocalSpecRepoPath <path> -SaveInputs
    
    Alternative from the package src/ directory: dotnet build /t:GenerateCode /p:SaveInputs=true.
  7. Build after first generation. Errors are expected; classify them in the build-fix loop.

Resource Hierarchy Gate

Before the build-fix loop, compare the generated hierarchy with the previous GA SDK. The previous GA DLL is restored automatically by ApiCompat from <ApiCompatVersion>. Write JSON outputs to temp/package-local scratch and do not commit them.

$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
  • Exit 0: every GA resource exists in the new SDK with the same ResourceType, parent set, scope, and singleton flag; continue.
  • Exit 1: structural drift. Fix TypeSpec resource shape first (@parentResource, @singleton, scopes/templates). Do not enter ApiCompat mitigation yet.
  • Exit 2: class-name renames only. Continue, but record and handle during naming/API compatibility work.

For C# base-model/base-type compatibility, do not use @@hierarchyBuilding; use SDK custom code after the generated surface is stable.

Build-Fix Loop

Repeat: build → classify → fix → regenerate if needed → rebuild.

Always verify zero Swagger diff after spec changes. Keep a running status list grouped by issue category so real migration breaks, compatibility shims, and generator bugs stay distinct.

Classify each issue before fixing:

Category Preferred action
Spec shape: names, types, paging, visibility, grouping Fix in client.tsp with scoped decorators
SDK compatibility gap: missing/changed shipped API Add minimal SDK shim only after root cause is known
Customization drift Remove stale custom code; re-add only proven shims
Generated-code drift Regenerate/export API; do not hand-edit generated files
Generator bug Stop, minimize repro, file/link issue

Common decorator fixes:

Problem Decorator
Wrong property type @@alternateType(Model.prop, targetType, "csharp")
Wrong operation parameter type @@alternateType(Interface.op::parameters.param, targetType, "csharp")
Wrong name @@clientName(target, "NewName", "csharp")
Model should be input and output @@usage(Model, Usage.input, "csharp"); decorator appends, so specify only the missing flag
Needs pageable return type @@markAsPageable(Interface.op, "csharp")
Flatten properties envelope @@flattenProperty(Model.properties, "csharp")
Operation name collision @@clientLocation(Interface.op, "GroupName", "csharp")

SDK custom code goes in the package's existing customization folder (src/Custom/, src/Customization/, or src/Customized/). Use MCP tools for deterministic edits when available, then hand-write only remaining shim logic. Useful MCP edits include add_using_directive, remove_using_directive, regex_replacement, nullable_annotation_fix, rename_codegen_type, and add_codegen_suppress. Regenerate when CodeGen* attributes change.

Every customization file or significant custom member needs a root-cause comment explaining what generated differently and why SDK-side customization is required. Avoid vague comments like "for backward compatibility". Obsolete custom members do not need a separate justification comment when the [Obsolete] message already clearly explains the reason and replacement.

Model factory compatibility overloads should translate renamed parameters or enum/value types, then delegate to generated public model-factory overloads. Do not construct generated models through internal constructors, internal Properties bags, or private Core helpers just to preserve an old factory signature. First look for a public generated factory overload or public model surface that can receive the same values.

SDK-side fix patterns when decorators cannot help:

Problem Fix
Base model/base type changed Add a custom partial model declaring the intended base model; use [CodeGenType] only when the custom type name differs from the generated/TypeSpec name, then regenerate. Do not use @@hierarchyBuilding.
Flattened properties lost on a polymorphic type Shim properties delegating to the Properties bag
Protected constructor missing on a discriminated base Add a protected constructor in the partial class
Property lost due to @@alternateType model swap Add the property in a partial class

Breaking Changes And New APIs

  1. Export API: pwsh eng/scripts/Export-API.ps1 <service>.
  2. Diff against the previous stable API surface from ApiCompatVersion / latest stable package tag. Use origin/main only if it matches that baseline.
  3. Fix each break using the same classify-first loop, then regenerate/export API/re-diff until clean. Never suppress with an ApiCompat baseline except for WirePathAttribute removal diffs.

For every new public API, classify it before keeping it:

Category Action
Real service/API-version addition Keep and note source API version in PR status
Rename of existing shipped API Prefer @@clientName; otherwise suppress/add minimal shim. Do not keep both names without approval
Generator convenience/drift Investigate operation id, route, resource type, and prior API before keeping

Compare each new member against the previous GA public API listing or restored ApiCompat assembly, operation id and request path in generated XML docs/source, resource type/parent hierarchy, and the TypeSpec or Swagger API version where the operation/model first appears. If a new API is actually a rename of an existing API, fix the rename instead of documenting it as additive.

Generator Bugs

If generated code is structurally wrong after stale customizations are removed, stop and report a generator bug. Create a minimum TypeSpec repro, document any approved workaround in client.tsp or SDK custom code with an issue link, and pause migration if no safe workaround exists.

Finalize

  1. Review locally with mpg-migration-pr-review rules.
  2. Ensure CHANGELOG.md has a short migration note and ci.mgmt.yml exists if needed.
  3. Format TypeSpec before opening the spec PR.
  4. Push spec changes to a fork and open draft spec PR titled Add csharp customizations for <Service> migration.
  5. Update tsp-location.yaml to point to the fork spec commit, then push SDK changes to a fork and open draft SDK PR titled [Mgmt] <PackageName>: Migrate to TypeSpec.
  6. Keep the SDK PR description as the status tracker: current phase, blockers, remaining breaks. If pausing before a draft PR exists, create one and use its description as the tracker.
  7. Before final SDK review, point tsp-location.yaml to the final spec commit, regenerate once without LocalSpecRepoPath, run pre-commit-checks, and verify build.

Done When

  • Build is clean.
  • ApiCompat is clean without baselines, except approved WirePathAttribute removal entries.
  • New APIs are triaged.
  • Required PR/status/review steps are complete.
  • tsp-location.yaml points to the final spec commit.
Install via CLI
npx skills add https://github.com/Azure/azure-sdk-for-net --skill mpg-migration
Repository Details
star Stars 6,013
call_split Forks 5,160
navigation Branch main
article Path SKILL.md
More from Creator