
Azure Upgrade
- 343k installs
- 1.3k repo stars
- Updated July 26, 2026
- microsoft/azure-skills
azure-upgrade is a Microsoft agent skill that assesses and automates Azure workload migrations between hosting plans, SKUs, and legacy SDK dependencies for developers modernizing Functions, App Service, Redis, or Java Az
About
Assess and upgrade Azure workloads between plans, tiers, or SKUs. Handles Consumption to Flex Consumption, plan changes, Container Apps migration, and Azure SDK Java modernization. Generates assessments before upgrades and follows scenarios sequentially.
- Assess and upgrade: Consumption to Flex, plan changes, SKU updates
- Cross-service migrations: App Service to Container Apps
- Azure SDK Java modernization: com.microsoft.azure to com.azure
Azure Upgrade by the numbers
- 343,300 all-time installs (skills.sh)
- +20,311 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #12 of 1,041 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
What azure-upgrade says it does
Assess and upgrade Azure workloads between plans, tiers, or SKUs
All automation scripts must be idempotent and resumable
npx skills add https://github.com/microsoft/azure-skills --skill azure-upgradeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 343k |
|---|---|
| repo stars | ★ 1.3k |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 26, 2026 |
| Repository | microsoft/azure-skills ↗ |
How do you upgrade Azure Functions hosting plans automatically?
Upgrade Azure workloads between hosting plans, SKUs, and services with assessment.
Who is it for?
Developers migrating live Azure Functions, App Service, Redis, or legacy Java Azure SDK workloads to newer plans, SKUs, or com.azure packages.
Skip if: Greenfield Azure deployments with no existing plan, SKU, or legacy SDK dependencies to assess and upgrade.
When should I use this skill?
An Azure workload needs migration from Consumption to Flex Consumption, App Service to Container Apps, ACR to AMR, or com.microsoft.azure to com.azure SDKs.
What you get
Migration assessment report, upgraded Azure hosting configuration, and modernized SDK dependency imports
- migration assessment
- upgraded hosting configuration
- modernized SDK imports
By the numbers
- 4 upgrade scenarios
- Supports ACRE to AMR migration
- MCP tools for best practices
Files
Azure Upgrade
This skill handles assessment and automated upgrades of existing Azure workloads from one Azure service, hosting plan, or SKU to another — all within Azure. This includes plan/tier upgrades (e.g. Consumption → Flex Consumption), cross-service migrations (e.g. App Service → Container Apps), and SKU changes. It also covers Azure SDK for Java source-code modernization (e.g. legacy Javacom.microsoft.azure.*→ moderncom.azure.*). This is NOT for cross-cloud migration — useazure-cloud-migratefor that.
Triggers
| User Intent | Example Prompts |
|---|---|
| Upgrade Azure Functions plan | "Upgrade my function app from Consumption to Flex Consumption" |
| Change hosting tier | "Move my function app to a better plan" |
| Assess upgrade readiness | "Is my function app ready for Flex Consumption?" |
| Automate plan migration | "Automate the steps to upgrade my Functions plan" |
| Modernize legacy Azure Java SDK | "Migrate legacy Azure SDKs for Java", "Upgrade legacy Azure Java SDK", "Migrate my Java project from com.microsoft.azure to com.azure" |
| Migrate Azure Cache for Redis (ACR/OSS) to Azure Managed Redis (AMR) | "Migrate my Redis cache to AMR", "ACR to AMR", "OSS to AMR", "Upgrade my Premium P2 cache to Managed Redis", "Pick an AMR SKU", "Convert my Redis IaC template to AMR" |
| Migrate Azure Cache for Redis Enterprise (ACRE) to Azure Managed Redis (AMR) | "Migrate my Enterprise_E10 cache to AMR", "ACRE to AMR", "Update my ACRE IaC template for AMR", "Migrate EnterpriseFlash to AMR", "Migrate my geo-replicated Enterprise Redis" |
Rules
1. Follow phases sequentially — do not skip 2. Generate an assessment before any upgrade operations 3. Load the scenario reference and follow its rules 4. Use mcp_azure_mcp_get_azure_bestpractices and mcp_azure_mcp_documentation MCP tools 5. Destructive actions require ask_user — global-rules 6. Always confirm the target plan/SKU with the user before proceeding 7. Never delete or stop the original app without explicit user confirmation 8. All automation scripts must be idempotent and resumable
Upgrade Scenarios
| Source | Target | Reference |
|---|---|---|
| Azure Functions Consumption Plan | Azure Functions Flex Consumption Plan | consumption-to-flex.md |
Legacy Azure Java SDK (com.microsoft.azure.*) | Modern Azure Java SDK (com.azure.*) | languages/java/README.md |
| Azure Cache for Redis (ACR/OSS) Basic/Standard/Premium | Azure Managed Redis (AMR) | services/redis/redis-to-amr.md |
| Azure Cache for Redis Enterprise (ACRE) / Enterprise Flash | Azure Managed Redis (AMR) | services/redis/redis-to-amr.md |
SDK upgrade scenarios (e.g. Java legacy → modern) run a source-code modernization flow that is distinct from Azure service/plan/SKU upgrades: follow the scenario reference, not the Steps below.
No matching scenario? Usemcp_azure_mcp_documentationandmcp_azure_mcp_get_azure_bestpracticestools to research the upgrade path.
MCP Tools
| Tool | Purpose |
|---|---|
mcp_azure_mcp_get_azure_bestpractices | Get Azure best practices for the target service |
mcp_azure_mcp_documentation | Look up Azure documentation for upgrade scenarios |
mcp_azure_mcp_appservice | Query App Service and Functions plan details |
mcp_azure_mcp_applicationinsights | Verify monitoring configuration |
Steps
1. Identify — Determine the source and target Azure plans/SKUs. Ask user to confirm. 2. Assess — Analyze existing app for upgrade readiness → load scenario reference (e.g., consumption-to-flex.md) 3. Pre-migrate — Collect settings, identities, configs from the existing app 4. Upgrade — Execute the automated upgrade steps (create new resources, migrate settings, deploy code) 5. Validate — Hit the function app default URL to confirm the app is reachable, then verify endpoints and monitoring 6. Ask User — "Upgrade complete. Would you like to verify performance, clean up the old app, or update your IaC?" 7. Hand off to azure-validate for deep validation or azure-deploy for CI/CD setup
Track progress in upgrade-status.md inside the workspace root.
References
- Global Rules
- Workflow Details
- Functions
- Consumption to Flex Consumption
- Assessment
- Automation Scripts
- Redis
- Redis (ACR or ACRE) to AMR Migration — routes to dedicated amr-migration-skill (ACR/OSS) or acre-to-amr-migration-skill (Enterprise)
- Java SDK Migration Templates
- Plan Template
- Progress Template
- Summary Template
Next
After upgrade is validated, hand off to:
azure-validate— for thorough post-upgrade validationazure-deploy— if the user wants to set up CI/CD for the new app
Global Rules
These rules apply to ALL phases of the azure-upgrade skill.
Destructive Action Policy
⛔ NEVER perform destructive actions without explicit user confirmation via ask_user:
- Deleting apps, services, or resource groups
- Stopping or disabling the original app/service
- Overwriting app settings or configuration in the new app
- Removing the original hosting plan or service tier
- Modifying DNS or custom domain bindings
User Confirmation Required
Always use ask_user before:
- Selecting target Azure subscription
- Selecting target Azure region/location
- Creating new Azure resources
- Stopping or deleting the original app/service
- Modifying custom domains or network restrictions
- Any irreversible configuration change
Best Practices
- Always use
mcp_azure_mcp_get_azure_bestpracticestool before generating upgrade commands - Prefer managed identity over connection strings — upgrades are a good time to improve security
- Always target the latest supported runtime version — check Azure docs for the newest GA version
- Keep the original app/service running until the upgraded one is fully validated
- Use the same resource group for the new resource to maintain access to existing dependencies
- Follow Azure naming conventions for all new resources
Identity-First Authentication (Zero API Keys)
Enterprise subscriptions commonly enforce policies that block local auth. Always design for identity-based access from the start.
- Prefer managed identity connections over connection strings/keys
- Use
DefaultAzureCredentialin code — works locally and in Azure - When using User Assigned Managed Identity, always pass
managedIdentityClientIdexplicitly - See service-specific identity configuration in the scenario reference files
Rollback Policy
- Always document rollback steps before executing upgrade
- Keep the original app intact and running until upgrade is validated
- If upgrade fails, guide the user to restart the original app
- Never delete the original app automatically — always require
ask_user
BOM Migration — Gradle Programmatic Version Catalog (settings.gradle)
Some projects define version catalogs programmatically in settings.gradle / settings.gradle.kts instead of using a TOML file. OpenRewrite does not support this either (openrewrite/rewrite#4852). Handle manually.
Step 0 — Detect programmatic catalog usage
Look for a dependencyResolutionManagement block in settings.gradle or settings.gradle.kts:
// settings.gradle (Groovy DSL)
dependencyResolutionManagement {
versionCatalogs {
libs {
version("azureSdk", "1.41.4")
version("azureStorage", "8.6.6")
library("azure", "com.microsoft.azure", "azure").versionRef("azureSdk")
library("azure-storage", "com.microsoft.azure", "azure-storage").versionRef("azureStorage")
}
}
}// settings.gradle.kts (Kotlin DSL)
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
version("azureSdk", "1.41.4")
version("azureStorage", "8.6.6")
library("azure", "com.microsoft.azure", "azure").versionRef("azureSdk")
library("azure-storage", "com.microsoft.azure", "azure-storage").versionRef("azureStorage")
}
}
}The library() call can also use the two-arg module form (the same syntax applies to Kotlin DSL):
library("azure", "com.microsoft.azure:azure").versionRef("azureSdk")
library("azure-inline", "com.microsoft.azure:azure").version("1.41.4")If the project has this pattern and contains Azure dependency entries, use this section. The same libs.<alias> accessor syntax is used in build.gradle as with TOML catalogs.
Step 1 — Add or upgrade the BOM
Add a version and library entry for the BOM inside the versionCatalogs block:
// Groovy DSL
dependencyResolutionManagement {
versionCatalogs {
libs {
version("azureSdkBom", "{bom_version}")
library("azure-sdk-bom", "com.azure", "azure-sdk-bom").versionRef("azureSdkBom")
}
}
}// Kotlin DSL
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
version("azureSdkBom", "{bom_version}")
library("azure-sdk-bom", "com.azure", "azure-sdk-bom").versionRef("azureSdkBom")
}
}
}If a BOM entry already exists, update the version string.
Add the platform dependency (if not already present).
Groovy DSL (build.gradle):
dependencies {
implementation enforcedPlatform(libs.azure.sdk.bom)
}Kotlin DSL (build.gradle.kts):
dependencies {
implementation(enforcedPlatform(libs.azure.sdk.bom))
}Step 2 — Remove explicit versions from BOM-managed Azure libraries
For each modern Azure library (com.azure.*) managed by the BOM, change its catalog entry to remove the version. Use the withoutVersion() call:
The snippets below show Groovy DSL (settings.gradle); the same code applies to Kotlin DSL (settings.gradle.kts).
Before:
library("azure-identity", "com.azure", "azure-identity").versionRef("azureIdentity")After:
library("azure-identity", "com.azure", "azure-identity").withoutVersion()For the two-arg module form (the same syntax applies to Kotlin DSL):
// Before
library("azure-identity", "com.azure:azure-identity").versionRef("azureIdentity")
// After
library("azure-identity", "com.azure:azure-identity").withoutVersion()Then remove any orphaned version(...) calls that are no longer referenced.
Step 3 — Replace legacy Azure library entries with modern equivalents
For each legacy com.microsoft.azure.* library call: 1. Replace the group and artifact with the modern com.azure.* equivalent. 2. Change .versionRef(...) or .version(...) to .withoutVersion() if the new artifact is managed by the BOM. 3. Remove orphaned version(...) calls. 4. If you rename the alias (first argument), update all references in build.gradle / build.gradle.kts and any bundle(...) calls.
The snippets below show Groovy DSL (settings.gradle); the same code applies to Kotlin DSL (settings.gradle.kts).
Before:
version("azureSdk", "1.41.4")
version("azureStorage", "8.6.6")
library("azure", "com.microsoft.azure", "azure").versionRef("azureSdk")
library("azure-storage", "com.microsoft.azure", "azure-storage").versionRef("azureStorage")After:
library("azure-resourcemanager", "com.azure.resourcemanager", "azure-resourcemanager").withoutVersion()
library("azure-storage-blob", "com.azure", "azure-storage-blob").withoutVersion()Then update build.gradle (Groovy DSL):
// Before
implementation libs.azure
implementation libs.azure.storage
// After
implementation libs.azure.resourcemanager
implementation libs.azure.storage.blobOr build.gradle.kts (Kotlin DSL):
// Before
implementation(libs.azure)
implementation(libs.azure.storage)
// After
implementation(libs.azure.resourcemanager)
implementation(libs.azure.storage.blob)Step 4 — Handle bundles
If bundle(...) calls reference any renamed or removed aliases, update them:
Groovy DSL (settings.gradle):
// Before
bundle("azureLibs", ["azure", "azure-storage"])
// After
bundle("azureLibs", ["azure-resourcemanager", "azure-storage-blob", "azure-identity"])Kotlin DSL (settings.gradle.kts):
// Before
bundle("azureLibs", listOf("azure", "azure-storage"))
// After
bundle("azureLibs", listOf("azure-resourcemanager", "azure-storage-blob", "azure-identity"))Expected settings.gradle after migration
Groovy DSL (settings.gradle):
dependencyResolutionManagement {
versionCatalogs {
libs {
version("azureSdkBom", "{bom_version}")
library("azure-sdk-bom", "com.azure", "azure-sdk-bom").versionRef("azureSdkBom")
library("azure-identity", "com.azure", "azure-identity").withoutVersion()
library("azure-resourcemanager", "com.azure.resourcemanager", "azure-resourcemanager").withoutVersion()
}
}
}Kotlin DSL (settings.gradle.kts):
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
version("azureSdkBom", "{bom_version}")
library("azure-sdk-bom", "com.azure", "azure-sdk-bom").versionRef("azureSdkBom")
library("azure-identity", "com.azure", "azure-identity").withoutVersion()
library("azure-resourcemanager", "com.azure.resourcemanager", "azure-resourcemanager").withoutVersion()
}
}
}BOM Migration — Gradle TOML Version Catalog (libs.versions.toml)
OpenRewrite does not yet support TOML version catalogs (openrewrite/rewrite#4400). Handle manually.
Check for gradle/libs.versions.toml. If it exists and contains Azure entries, apply these steps. Always update build.gradle / build.gradle.kts references in tandem.
💡 Tip: TOML aliasazure-sdk-bombecomes accessorlibs.azure.sdk.bom(hyphens→dots). CamelCaseazureSdkBombecomeslibs.azureSdkBom. Match the project's existing convention.
Step 1 — Add or upgrade the BOM
In gradle/libs.versions.toml:
[versions]
azureSdkBom = "{bom_version}"
[libraries]
azure-sdk-bom = { group = "com.azure", name = "azure-sdk-bom", version.ref = "azureSdkBom" }In build.gradle (Groovy DSL):
implementation enforcedPlatform(libs.azure.sdk.bom)In build.gradle.kts (Kotlin DSL):
implementation(enforcedPlatform(libs.azure.sdk.bom))Step 2 — Remove explicit versions from BOM-managed libraries
For each com.azure.* library in [libraries] that the BOM manages, drop version.ref / version and remove orphaned [versions] entries.
# Before
[versions]
azureIdentity = "1.15.0"
[libraries]
azureIdentity = { group = "com.azure", name = "azure-identity", version.ref = "azureIdentity" }
# After
[libraries]
azureIdentity = { group = "com.azure", name = "azure-identity" }Step 3 — Replace legacy entries with modern equivalents
For each com.microsoft.azure.* library: replace group/name with the modern com.azure.* equivalent, drop version.ref/version if BOM-managed, remove orphaned [versions] entries, and update alias references in build.gradle and [bundles].
# Before
[versions]
azureSdk = "1.41.4"
azureStorage = "8.6.6"
[libraries]
azure = { group = "com.microsoft.azure", name = "azure", version.ref = "azureSdk" }
azureStorage = { group = "com.microsoft.azure", name = "azure-storage", version.ref = "azureStorage" }
# After (BOM-managed)
[libraries]
azureResourcemanager = { group = "com.azure.resourcemanager", name = "azure-resourcemanager" }
azureStorageBlob = { group = "com.azure", name = "azure-storage-blob" }Update build.gradle and [bundles] to use the new aliases.
TOML patterns to recognise
Libraries may use any of these forms — handle all of them:
lib = { group = "g", name = "a", version.ref = "v" }
lib = { module = "g:a", version.ref = "v" }
lib = { module = "g:a", version = "1.0" }
lib = { group = "g", name = "a", version = { strictly = "1.0" } }BOM Migration — Gradle Projects (No Version Catalogs)
Python availability: The script below requires Python 3.8+. Ifpython3 --version(orpython --version) fails, skip the script section and follow Manual Fallback (no Python) instead.
Automated (Python available)
Run the upgrade_bom.py script located at references/languages/java/scripts/upgrade_bom.py (relative to this skill). It auto-detects Gradle and performs:
1. Set/upgrade the BOM — adds enforcedPlatform("com.azure:azure-sdk-bom:...") if missing, or upgrades the version. 2. Remove redundant explicit versions — strips inline version strings from Azure dependencies managed by the BOM.
The following invocation works identically in bash and PowerShell:
# Path is relative to the skill directory (plugin/skills/azure-upgrade/)
python3 ./references/languages/java/scripts/upgrade_bom.py <project_dir> <bom_version>Options:
--gradle <cmd>— override the Gradle command (default: auto-detectsgradleworgradle).
Under the hood (OpenRewrite recipes):
- Add BOM:
AddPlatformDependency(docs) - Upgrade BOM:
UpgradeDependencyVersion(docs) - Remove redundant versions:
RemoveRedundantDependencyVersions(docs)
⚠️ Warning: The script does not support Gradle version catalogs — neither TOML files nor programmatic settings.gradle catalogs. If the project uses either, follow TOML catalog steps or programmatic catalog steps instead.Expected build.gradle after migration
Groovy DSL (build.gradle):
dependencies {
implementation enforcedPlatform("com.azure:azure-sdk-bom:{bom_version}")
implementation "com.azure:azure-identity"
implementation "com.azure.resourcemanager:azure-resourcemanager"
}Kotlin DSL (build.gradle.kts):
dependencies {
implementation(enforcedPlatform("com.azure:azure-sdk-bom:{bom_version}"))
implementation("com.azure:azure-identity")
implementation("com.azure.resourcemanager:azure-resourcemanager")
}Manual Fallback (no Python)
When Python is unavailable, edit build.gradle (or build.gradle.kts) directly. Apply the same two steps as the script.
Step 1 — Add or upgrade the BOM platform
Inside the dependencies { } block, add or update the enforcedPlatform line for azure-sdk-bom:
Groovy DSL:
dependencies {
implementation enforcedPlatform("com.azure:azure-sdk-bom:{bom_version}")
// ...other dependencies...
}Kotlin DSL:
dependencies {
implementation(enforcedPlatform("com.azure:azure-sdk-bom:{bom_version}"))
// ...other dependencies...
}- If the line exists: update only the version to
{bom_version}. - If the line is missing: insert it at the top of the
dependenciesblock. - Use the same configuration (
implementation,api,compileOnly, etc.) the project already uses for Azure deps. Repeat the platform line per configuration if needed. - Multi-project build: add the platform line in every subproject that declares Azure dependencies, or apply it once via a shared
subprojects { }/ convention plugin.
Step 2 — Remove redundant explicit versions
For every Azure dependency whose group starts with com.azure and is managed by the BOM (verify against https://repo1.maven.org/maven2/com/azure/azure-sdk-bom/{bom_version}/azure-sdk-bom-{bom_version}.pom), strip the version coordinate.
Groovy DSL — string notation:
// Before
implementation "com.azure:azure-identity:1.13.0"
// After
implementation "com.azure:azure-identity"Groovy DSL — map notation:
// Before
implementation group: "com.azure", name: "azure-identity", version: "1.13.0"
// After
implementation group: "com.azure", name: "azure-identity"Kotlin DSL:
// Before
implementation("com.azure:azure-identity:1.13.0")
// After
implementation("com.azure:azure-identity")Do not strip versions from artifacts that are not managed by the BOM.
Step 3 — Verify
Run the Gradle wrapper to inspect the resolved classpath. Use the form appropriate for your shell:
# bash / macOS / Linux
./gradlew dependencies --configuration runtimeClasspath# PowerShell on Windows
.\gradlew.bat dependencies --configuration runtimeClasspathThen confirm:
- The platform
com.azure:azure-sdk-bom:{bom_version}appears. - All BOM-managed Azure artifacts resolve to versions sourced from the BOM.
Then continue with the validation checklist in bom-validation.md.
BOM Migration — Maven Projects
Python availability: The script below requires Python 3.8+. Ifpython3 --version(orpython --version) fails, skip the script section and follow Manual Fallback (no Python) instead.
Automated (Python available)
Run the upgrade_bom.py script located at references/languages/java/scripts/upgrade_bom.py (relative to this skill). It auto-detects Maven and performs two steps:
1. Set/upgrade the BOM — adds azure-sdk-bom if missing, or upgrades the version if already present. 2. Remove redundant explicit versions — strips explicit <version> tags from individual Azure dependencies that are now managed by the BOM.
The following invocation works identically in bash and PowerShell:
# Path is relative to the skill directory (plugin/skills/azure-upgrade/)
python3 ./references/languages/java/scripts/upgrade_bom.py <project_dir> <bom_version>Options:
--mvn <cmd>— override the Maven command (default: auto-detectsmvnwormvn).
Under the hood (OpenRewrite recipes):
- Add BOM:
AddManagedDependency(docs) - Upgrade BOM:
UpgradeDependencyVersion(docs) - Remove redundant versions:
RemoveRedundantDependencyVersions(docs)
Expected pom.xml after migration
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-sdk-bom</artifactId>
<version>{bom_version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
<dependency>
<groupId>com.azure.resourcemanager</groupId>
<artifactId>azure-resourcemanager</artifactId>
</dependency>
</dependencies>Manual Fallback (no Python)
When Python is unavailable, edit pom.xml directly. Apply the same two steps as the script:
Step 1 — Add or upgrade azure-sdk-bom
Locate the <dependencyManagement><dependencies> block (create it inside <project> if absent). Add or update the BOM entry:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-sdk-bom</artifactId>
<version>{bom_version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- keep any other managed dependencies here -->
</dependencies>
</dependencyManagement>- If the entry exists: update only the
<version>value to{bom_version}. - If the entry is missing: insert the full
<dependency>block above. Preserve any other existing managed dependencies. - Multi-module project: add the BOM in the parent (aggregator)
pom.xmlonly. Child modules inherit it.
Step 2 — Remove redundant explicit versions
For every <dependency> whose <groupId> starts with com.azure (e.g. com.azure, com.azure.resourcemanager, com.azure.spring), check whether the BOM manages it (see the BOM POM at https://repo1.maven.org/maven2/com/azure/azure-sdk-bom/{bom_version}/azure-sdk-bom-{bom_version}.pom). If managed:
- Remove the
<version>element entirely. - Leave
<groupId>,<artifactId>,<scope>,<classifier>,<exclusions>, etc. unchanged.
Before:
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.13.0</version>
</dependency>After:
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>Do not strip versions from artifacts not managed by the BOM (verify each one against the BOM POM).
Step 3 — Verify
Run mvn -q -DskipTests dependency:tree (the same command works in both bash and PowerShell) and confirm:
com.azure:azure-sdk-bom:pom:{bom_version}:importappears in the managed dependencies.- All BOM-managed Azure artifacts resolve to versions from
{bom_version}.
Then continue with the validation checklist in bom-validation.md.
BOM Migration Guide
How to add or upgrade azure-sdk-bom and clean up redundant versions across all supported build configurations.
Prerequisite — Python availability check
The Maven and plain-Gradle flows are automated by scripts/upgrade_bom.py (Python 3.8+). Before picking a guide, verify Python is available:
The following check works in both bash and PowerShell 7+ (the || operator is supported in both):
python3 --version || python --versionFor Windows PowerShell 5.1, use:
python3 --version; if ($LASTEXITCODE -ne 0) { python --version }- Python available → use the script as documented in bom-maven.md / bom-gradle.md.
- Python NOT available → follow the Manual Fallback section in the same guide. Do not attempt to install Python; perform the edits by hand.
The TOML and programmatic-catalog guides (bom-gradle-toml.md, bom-gradle-settings.md) are manual-only and unaffected by Python availability.
Determine the latest BOM version
Resolve the target azure-sdk-bom version from the Azure SDK for Java source of truth before editing build files. This is mandatory: do not hardcode, guess, or reuse an illustrative version from another example. Versions below 1.3.0 are invalid for this migration flow.
The following invocation works identically in bash and PowerShell (no shell-specific syntax):
# Path is relative to the skill directory (plugin/skills/azure-upgrade/)
python3 ./references/languages/java/scripts/upgrade_bom.py --get-latest-version
# or: python ./references/languages/java/scripts/upgrade_bom.py --get-latest-versionIf Python is not available, fetch https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/boms/azure-sdk-bom/pom.xml directly and use the <version> value declared in that BOM pom.xml.
Do not continue until you have resolved that latest stable version explicitly.
Decision Tree
Is the project Maven?
├─ YES → Maven projects (bom-maven.md)
└─ NO (Gradle)
├─ Does gradle/libs.versions.toml exist with Azure entries?
│ └─ YES → TOML catalog steps (bom-gradle-toml.md)
├─ Does settings.gradle define a programmatic versionCatalogs block with Azure entries?
│ └─ YES → Programmatic catalog steps (bom-gradle-settings.md)
└─ Neither (plain build.gradle dependencies)
└─ Plain Gradle projects (bom-gradle.md)💡 Tip: To check which artifacts are managed by the BOM, fetch
https://repo1.maven.org/maven2/com/azure/azure-sdk-bom/{bom_version}/azure-sdk-bom-{bom_version}.pomand look for <dependency> entries.Build-System Guides
| Build system | Guide |
|---|---|
| Maven | bom-maven.md |
| Gradle (no version catalog) | bom-gradle.md |
| Gradle + TOML version catalog | bom-gradle-toml.md |
| Gradle + programmatic catalog | bom-gradle-settings.md |
Validation
See the Validation Checklist — covers all build systems including TOML and programmatic settings.gradle catalogs.
BOM Migration — Validation Checklist
After BOM migration, verify:
- [ ] Project compiles successfully.
- [ ] No legacy
com.microsoft.azure.*dependencies remain anywhere (pom.xml, build.gradle, TOML, settings.gradle). - [ ] BOM-managed Azure libraries have no explicit version (no
<version>tag, no version string, noversion.ref, no.versionRef()). - [ ] The BOM version is correct — check against https://repo1.maven.org/maven2/com/azure/azure-sdk-bom/
Additional checks for TOML version catalog projects
- [ ] No orphaned entries in
[versions](every version key must be referenced by at least one library or plugin). - [ ]
[bundles]aliases match current[libraries]aliases (no stale references). - [ ]
build.gradleuseslibs.<alias>references — no raw"group:artifact:version"strings for Azure libraries.
Additional checks for programmatic settings.gradle catalog projects
- [ ] No orphaned
version(...)calls (every version must be referenced by at least onelibraryorpluginentry). - [ ]
bundle(...)aliases match currentlibrary(...)aliases (no stale references). - [ ]
build.gradleuseslibs.<alias>references — no raw"group:artifact:version"strings for Azure libraries.
Azure SDK Migration Guidelines
Context
The application is identified using legacy Azure SDKs for Java (com.microsoft.azure.*). These libraries reached end of support in 2023. They are not recommended for use in production, should be migrated to the latest Azure SDKs with the latest security patches and new capabilities support.
Follow these steps:
- Inventory legacy dependencies: Use tools such as
mvn dependency:treeorgradlew dependenciesto find everycom.microsoft.azure.*SDK and map each one to its modern counterpart undercom.azure.*. Do not rely solely on the root reactor — also grep the entire repository for legacy coordinates so you catch build files that aren't reachable from the root project. Run from the repo root:
# Find every file referencing legacy groupIds/artifacts, including CI, samples, parent poms, buildSrc, version catalogs, Dockerfiles, and docs.
grep -RIn --exclude-dir={.git,target,build,node_modules,out} \
-E 'com\.microsoft\.azure(\.|:)|microsoft-azure-|azure-eventhubs-eph|azure-keyvault(:|["'\''])' .PowerShell equivalent (run from repo root):
Get-ChildItem -Path . -Recurse -File |
Where-Object { $_.FullName -notmatch '(\\|/)(\.git|target|build|node_modules|out)(\\|/)' } |
Select-String -Pattern 'com\.microsoft\.azure(\.|:)|microsoft-azure-|azure-eventhubs-eph|azure-keyvault(:|["''])'Commonly overlooked locations:.ci/**/pom.xml, ci/**, parent/BOM poms, buildSrc/, gradle/libs.versions.toml, settings.gradle(.kts), archetype-resources/, sample sub-modules, Dockerfiles, shell/PowerShell scripts, and README snippets. Every hit must end up on the migration file list.
- Adopt supported SDKs: Replace the legacy dependencies with their modern equivalents in your
pom.xmlorbuild.gradle, following the migration guide to align feature parity and new SDK names.
- Update application code: Refactor your code to the builder-based APIs, updated authentication flows (Azure Identity), and modern async or reactive patterns required by the latest SDKs. Add concise comments explaining non-obvious changes.
- Test thoroughly: Run unit, integration, and end-to-end tests to validate that the modern SDKs behave as expected, focusing on authentication, retry, and serialization differences.
Migration Guide
Assumption
- Project is Maven or Gradle.
- Java code is on JDK 8 or above.
Migrate dependencies
Use the latest stable azure-sdk-bom version from the Azure SDK for Java source of truth before editing any build file. Versions below 1.3.0 are invalid for this migration flow and must not be used.
Follow the detailed steps in BOM Migration Guide — it covers how to determine the latest BOM version, plus Maven, plain Gradle, TOML version catalogs (libs.versions.toml), and programmatic version catalogs (settings.gradle).
Migrate Java Code
- Make a list of source code/maven/gradle files that contains legacy SDK packages. Migrate each of them.
- Determine legacy SDK artifacts according to previous files, find suitable migration guides in Package-Specific Migration Guides and follow the guides whenever possible. Record which migration guide URL you used for each legacy package (e.g., in your plan or commit messages), so you can validate against them later.
- Do not change the Java `package ...;` declaration at the top of each source file, and do not rename or move the source file's directory path to match a new SDK package structure. Keep every
.javafile in its original directory; only updateimportstatements and type usages inside the file body. For example, if a file lives insrc/main/java/com/microsoft/azure/eventprocessorhosts/Consumer.javawithpackage com.microsoft.azure.eventprocessorhosts;, it must stay in that exact directory and keep that exact package declaration — even though the modern SDK usescom.azure.messaging.eventhubs. - Do not upgrade JDK version, if it is already JDK 8 or above.
- If there is test in the project, Java code there also need to be updated.
Package-Specific Source Code Guidelines (Add them to plan guidelines when generating plan)
Use these package-specific references:
- com.microsoft.azure.management.**
- com.microsoft.azure.eventprocessorhost
Validation
Make sure
- Migrated project pass compilation.
- All tests pass. Don't silently skip tests.
- No legacy SDK dependencies/references exist. This is a hard gate, not a self-assessment — you must prove it by running the commands below from the repo root and showing they return zero hits. Do not declare migration complete until all three return empty:
# 1. Legacy groupId / artifact references in ANY text file (pom.xml, *.gradle, *.gradle.kts, libs.versions.toml, Dockerfile, *.sh, *.md, etc.)
grep -RIn --exclude-dir={.git,target,build,node_modules,out} \
-E 'com\.microsoft\.azure(\.|:)|microsoft-azure-|azure-eventhubs-eph|azure-keyvault(:|["'\''])' .
# 2. Legacy imports still in Java sources
grep -RIn --include='*.java' -E '^\s*import\s+com\.microsoft\.azure\.' .
# 3. Every pom.xml and *.gradle(.kts) file in the repo (not just the root reactor) — eyeball each for legacy coordinates
find . -type d \( -name .git -o -name target -o -name build -o -name node_modules \) -prune -o \
-type f \( -name 'pom.xml' -o -name '*.gradle' -o -name '*.gradle.kts' -o -name 'libs.versions.toml' \) -printPowerShell equivalent (run from repo root):
# 1. Legacy groupId / artifact references in ANY text file
Get-ChildItem -Path . -Recurse -File |
Where-Object { $_.FullName -notmatch '(\\|/)(\.git|target|build|node_modules|out)(\\|/)' } |
Select-String -Pattern 'com\.microsoft\.azure(\.|:)|microsoft-azure-|azure-eventhubs-eph|azure-keyvault(:|["''])'
# 2. Legacy imports still in Java sources
Get-ChildItem -Path . -Recurse -File -Filter *.java |
Where-Object { $_.FullName -notmatch '(\\|/)(\.git|target|build|node_modules|out)(\\|/)' } |
Select-String -Pattern '^\s*import\s+com\.microsoft\.azure\.'
# 3. Every pom.xml and *.gradle(.kts) file in the repo — eyeball each for legacy coordinates
Get-ChildItem -Path . -Recurse -File -Include 'pom.xml','*.gradle','*.gradle.kts','libs.versions.toml' |
Where-Object { $_.FullName -notmatch '(\\|/)(\.git|target|build|node_modules)(\\|/)' } |
Select-Object -ExpandProperty FullNamePay special attention to files outside the root Maven/Gradle reactor— e.g. .ci/**/pom.xml, ci/**, buildSrc/, sample sub-modules, archetype resources — these are frequently missed because mvn dependency:tree on the root project never visits them.
- If azure-sdk-bom is used, ensure NO explicit version dependencies for Azure libraries that are in azure-sdk-bom.
E.g. Instead of implementation 'com.azure.resourcemanager:azure-resourcemanager:2.60.0', we should use implementation 'com.azure.resourcemanager:azure-resourcemanager'. For Azure libraries in azure-sdk-bom, check https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/boms/azure-sdk-bom/pom.xml. The BOM version used during migration must be the latest stable version available at migration time and must not be below 1.3.0. If the BOM version is below 1.3.0 or missing, or individual Azure packages still have explicit versions that should be managed by the BOM, follow the appropriate section in BOM Migration Guide to fix it.
- Version catalog projects: Follow the BOM Validation Checklist — it covers TOML, programmatic
settings.gradlecatalogs, and plain Gradle. - For each migration guide you recorded during migration:
1. Fetch and read the full content of the guide URL. 2. Identify the migrated source files that correspond to that guide's package. 3. Verify the migrated code follows the guide's recommended API replacements, class mappings, authentication patterns, and async/sync conventions. 4. Fix any deviations — do not just report them.
Package-Specific Migration Guides
- Migrate to `com.azure.resourcemanager.**` from `com.microsoft.azure.management.**`
- Migrate to com.azure:azure-messaging-servicebus from com.microsoft.azure:azure-servicebus
- Migrate to azure-messaging-eventhubs from azure-eventhubs and azure-eventhubs-eph
- Migrate to `azure-messaging-eventgrid` from `microsoft-azure-eventgrid`
- Storage Blob Service SDK Migration Guide from 8.x to 12.x
- Storage Blob Service SDK Migration Guide from 10.x/11.x to 12.x
- Storage Queue Service SDK Migration Guide from 8.x to 12.x
- Storage File Share Service SDK Migration Guide from 8.x to 12.x
- Migrate to azure-security-keyvault-secrets from azure-keyvault
- Migrate to azure-security-keyvault-keys from azure-keyvault
- Migrate to azure-security-keyvault-certificates from azure-keyvault
- Migrate to `Azure-Compute-Batch` from `Microsoft-Azure-Batch`
- Migrate to `azure-ai-documentintelligence` from `azure-ai-formrecognizer`
- Migrate to `azure-ai-formrecognizer 4.0.0-beta.1 - above` from `azure-ai-formrecognizer 3.1.x - lower`
- Migration Guide from Azure OpenAI Java SDK to OpenAI Java SDK
- Migrate to azure-monitor-query from azure-loganalytics and azure-applicationinsights-query
com.microsoft.azure.eventprocessorhost
Hard Rules (MUST follow)
- MUST replace any legacy
InMemoryCheckpointManager/InMemoryLeaseManagerand anyEventProcessorHostcheckpoint/lease usage withBlobCheckpointStorebacked by Azure Blob Storage. This is the only acceptable replacement. - MUST NOT create a class named
InMemoryCheckpointStore, copy/inlineSampleCheckpointStore, or implement any custom in-memoryCheckpointStore. The modern SDK intentionally omits an in-memory implementation due to production issues. - MUST NOT introduce any other custom
CheckpointStoreimplementation as part of this migration. If the legacy code stored checkpoints in memory, switch toBlobCheckpointStore— do not preserve the in-memory semantics. - If the user explicitly asks for an in-memory implementation, refuse and direct them to the upstream
SampleCheckpointStorereference instead of generating one.
⚠️ Important: The switch fromInMemoryCheckpointManager/InMemoryLeaseManagertoBlobCheckpointStoreis an expected and necessary behavioral change. It is inherent to the modern SDK design and must not block the migration from completing. Do not treat this behavioral difference as a migration defect or attempt to preserve in-memory semantics — proceed withBlobCheckpointStoreand complete the migration.
Code Samples
EventProcessorHost with InMemoryCheckpointManager / InMemoryLeaseManager
Replace usage of InMemoryCheckpointManager / InMemoryLeaseManager with BlobCheckpointStore. The modern EventProcessorClient does not ship an in-memory checkpoint store, and you must not create one.
Legacy code:
InMemoryCheckpointManager checkpointManager = new InMemoryCheckpointManager();
InMemoryLeaseManager leaseManager = new InMemoryLeaseManager();
EventProcessorHost host = new EventProcessorHost(
hostName, eventHubName, consumerGroupName,
eventHubConnectionString, checkpointManager, leaseManager);
host.registerEventProcessor(MyEventProcessor.class).get();Migrated code — replace with BlobCheckpointStore backed by Azure Blob Storage:
BlobContainerAsyncClient blobContainerClient = new BlobContainerClientBuilder()
.connectionString(storageConnectionString)
.containerName(storageContainerName)
.buildAsyncClient();
// BlobCheckpointStore is the only supported replacement for InMemoryCheckpointManager/InMemoryLeaseManager.
// Do NOT create an InMemoryCheckpointStore or copy SampleCheckpointStore — there is no in-memory store in the modern SDK.
EventProcessorClient eventProcessorClient = new EventProcessorClientBuilder()
.connectionString(eventHubConnectionString, eventHubName)
.consumerGroup(consumerGroupName)
.checkpointStore(new BlobCheckpointStore(blobContainerClient))
.processEvent(eventContext -> {
// Process event and checkpoint
eventContext.updateCheckpoint();
})
.processError(errorContext -> {
System.err.printf("Error in partition %s: %s%n",
errorContext.getPartitionContext().getPartitionId(),
errorContext.getThrowable().getMessage());
})
.buildEventProcessorClient();
eventProcessorClient.start();⚠️ Warning: Add dependencycom.azure:azure-messaging-eventhubs-checkpointstore-blobto the project when usingBlobCheckpointStore.
EventProcessorHost with Azure Storage checkpoint/lease
Legacy code using the built-in storage-backed checkpoint/lease:
EventProcessorHost host = EventProcessorHost.EventProcessorHostBuilder
.newBuilder(hostName, consumerGroupName)
.useAzureStorageCheckpointLeaseManager(storageConnectionString, storageContainerName, null)
.useEventHubConnectionString(eventHubConnectionString, eventHubName)
.build();
host.registerEventProcessor(MyEventProcessor.class).get();Migrated code:
BlobContainerAsyncClient blobContainerClient = new BlobContainerClientBuilder()
.connectionString(storageConnectionString)
.containerName(storageContainerName)
.buildAsyncClient();
EventProcessorClient eventProcessorClient = new EventProcessorClientBuilder()
.connectionString(eventHubConnectionString, eventHubName)
.consumerGroup(consumerGroupName)
.checkpointStore(new BlobCheckpointStore(blobContainerClient))
.processEvent(eventContext -> {
// Process event and checkpoint
eventContext.updateCheckpoint();
})
.processError(errorContext -> {
System.err.printf("Error in partition %s: %s%n",
errorContext.getPartitionContext().getPartitionId(),
errorContext.getThrowable().getMessage());
})
.buildEventProcessorClient();
eventProcessorClient.start();Required imports for migrated code
import com.azure.messaging.eventhubs.EventProcessorClient;
import com.azure.messaging.eventhubs.EventProcessorClientBuilder;
import com.azure.messaging.eventhubs.checkpointstore.blob.BlobCheckpointStore;
import com.azure.storage.blob.BlobContainerAsyncClient;
import com.azure.storage.blob.BlobContainerClientBuilder;Required dependencies
Add these dependencies when migrating from com.microsoft.azure:azure-eventhubs-eph:
| Legacy Artifact | Modern Artifact |
|---|---|
com.microsoft.azure:azure-eventhubs-eph | com.azure:azure-messaging-eventhubs |
| (included in above) | com.azure:azure-messaging-eventhubs-checkpointstore-blob |
com.microsoft.azure.management.**
Code Checklist
- Keep Azure resources, operations, and property values identical. The goal is functional equivalence, not feature expansion.
- Do not change the method sequence when creating or updating an Azure resource unless the new SDK requires it.
- Preserve the existing async pattern. For example, a delayed provisioning pattern that uses
Creatable<Resource>should not be replaced by a direct.create()call. Similarly, when provisioning a resource, do not swap.withNewDependencyResourcefor.withExistingDependencyResourceunless mandated by the new API surface. - Keep the text emitted by logging and stdout/stderr unchanged to avoid breaking downstream consumers of those streams.
- Do not replace
resource.region()withresource.regionName(); doing so changes the type fromRegiontoStringand can introduce subtle regressions.
Code Samples
Authentication with File
File-based authentication (e.g., Azure.configure().authenticate(credentialFile)) is discouraged under Azure's security-by-default posture: it relies on long-lived secrets stored on disk, which conflicts with the modern guidance to prefer managed identities, workload identity, or other credential types exposed by DefaultAzureCredential.
Detect: legacy file-based authentication patterns
Treat any of the following shapes in the legacy code as file-based authentication that must be replaced (not migrated). Triggers include AZURE_AUTH_LOCATION, .authenticate(File), ApplicationTokenCredentials.fromFile, or any code path that reads clientId / clientSecret / tenant from disk and feeds them into a credential builder.
// Shape A: direct File overload
Azure azure = Azure.authenticate(new File(System.getenv("AZURE_AUTH_LOCATION")))
.withDefaultSubscription();
// Shape B: configure() chain with a File
File credFile = new File(authFilePath);
Azure azure = Azure.configure()
.withLogLevel(LogLevel.BASIC)
.authenticate(credFile)
.withDefaultSubscription();
// Shape C: ApplicationTokenCredentials.fromFile(...)
ApplicationTokenCredentials creds =
ApplicationTokenCredentials.fromFile(new File(authFile));
Azure azure = Azure.authenticate(creds).withSubscription(subscriptionId);Do not emit a code sample that reproduces any of the above during the upgrade — including a "modernized" variant that parses the same file with Jackson and feeds it into ClientSecretCredentialBuilder. Instead, replace the authentication block in the migrated code with a DefaultAzureCredential (or another appropriate TokenCredential) and prepend a TODO comment that explains the change. For example:
// TODO: The original code authenticated using a credential file (AZURE_AUTH_LOCATION),
// which is discouraged because it relies on long-lived secrets on disk and conflicts
// with Azure's security-by-default guidance. It has been replaced with
// DefaultAzureCredential. This change alters the authentication mechanism, so the
// resulting code path requires extra testing (local dev, CI, and target runtime
// identities) before it is considered production-ready.
TokenCredential credential = new DefaultAzureCredentialBuilder().build();
AzureProfile profile = new AzureProfile(AzureEnvironment.AZURE);
AzureResourceManager azure = AzureResourceManager.configure()
.authenticate(credential, profile)
.withDefaultSubscription();Keep the TODO comment in the migrated source so reviewers and downstream maintainers are aware that the authentication mechanism changed and that the new code path has not been exercised by the original tests.
OKHttp Interceptors
Legacy OKHttp Interceptor implementation classes should be migrated to HttpPipelinePolicy implementation classes. This is a two-step migration — both steps are required:
Step 1: Convert each `Interceptor` subclass to an `HttpPipelinePolicy` subclass. Rename the class from XxxInterceptor to XxxPolicy and reimplement its logic against the HttpPipelinePolicy interface (i.e. process(HttpPipelineCallContext, HttpPipelineNextPolicy)) instead of the OKHttp Interceptor.intercept(Chain) API.
Step 2: Register every converted policy on the new manager builder via `.withPolicy(new XxxPolicy())`. Each withNetworkInterceptor(new XxxInterceptor()) call on the legacy RestClient.Builder must have a corresponding .withPolicy(new XxxPolicy()) call on AzureResourceManager.configure() (or the equivalent XxxManager.configure()). Preserve the original ordering of the interceptors when registering the policies.
Do not skip Step 2: converting the class without wiring it into the manager builder silently drops the behavior.
1. Legacy code:
RestClient.Builder builder = new RestClient.Builder()
...
.withNetworkInterceptor(new ResourceGroupTaggingInterceptor())
...;
Azure.Authenticated azureAuthed = Azure.authenticate(builder.build(), subscriptionId, credentials.domain());
Azure azure = azureAuthed.withSubscription(subscriptionId);2. Migrated code (note: ResourceGroupTaggingPolicy is the Step 1 conversion of ResourceGroupTaggingInterceptor, and it must be registered via .withPolicy(...) in Step 2):
AzureResourceManager azureResourceManager = AzureResourceManager.configure()
.withPolicy(new ResourceGroupTaggingPolicy())
.authenticate(credential, profile)
.withDefaultSubscription();ProviderRegistrationInterceptor
If legacy client(XXManager) initializes with ProviderRegistrationInterceptor, check whether this client is one of the premium ones:
- Azure
- AuthorizationManager
- CdnManager
- ComputeManager
- ContainerInstanceManager
- ContainerRegistryManager
- ContainerServiceManager
- CosmosDBManager
- DnsZoneManager
- EventHubManager
- KeyVaultManager
- MonitorManager
- MSIManager
- NetworkManager
- RedisManager
- ResourceManager
- SearchServiceManager
- ServiceBusManager
- SqlServerManager
- StorageManager
- TrafficManager
If not, add ProviderRegistrationPolicy when initializing the client. Otherwise, don't.
For each legacy client, add along with whether to initialize with ProviderRegistrationPolicy, to the generated plan guideline, and migrate accordingly.
1. Legacy client(not premium client):
BatchManager batchManager = BatchManager.configure()
.withLogLevel(LogLevel.BASIC)
.withInterceptor(new ProviderRegistrationInterceptor(credentials))
.authenticate(credentials, subscriptionId);should be migrated to:
BatchManager batchManager = BatchManager.configure()
.withPolicy(new ProviderRegistrationPolicy())
.withLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BASIC))
.authenticate(credential, profile);2. Legacy client(premium clients):
Azure azure = Azure.configure()
.withInterceptor(new ProviderRegistrationInterceptor(credentials))
.withLogLevel(LogLevel.BASIC)
.authenticate(credentials)
.withSubscription(subscriptionId);should be migrated to:
AzureResourceManager.configure()
.withLogLevel(HttpLogDetailLevel.BASIC)
.authenticate(credential, profile);BatchAccount
azure-resourcemanager-batch is no longer a premium/handwritten library. In BatchAccount, withNewStorageAccount should be replaced by .withAutoStorage(new AutoStorageBaseProperties().withStorageAccountId(storageAccount.id())), while the storageAccount needs to be created separately.
Legacy code:
BatchAccount batchAccount = azure.batchAccounts().define(batchAccountName)
.withRegion(region)
.withNewResourceGroup(rgName)
.defineNewApplication(applicationName)
.defineNewApplicationPackage(applicationPackageName)
.withAllowUpdates(true)
.withDisplayName(applicationDisplayName)
.attach()
.withNewStorageAccount(storageAccountName)
.create();Migrated:
StorageAccount storageAccount = storageManager.storageAccounts()
.define(storageAccountName)
.withRegion(REGION)
.withExistingResourceGroup(resourceGroup)
.create();
BatchAccount account = batchManager.batchAccounts()
.define(batchAccountName)
.withRegion(REGION)
.withExistingResourceGroup(resourceGroup)
.withAutoStorage(new AutoStorageBaseProperties().withStorageAccountId(storageAccount.id()))
.create();
// create application with batch account
application = batchManager.applications()
.define(applicationName)
.withExistingBatchAccount(resourceGroup, account.name())
.withDisplayName(applicationDisplayName)
.withAllowUpdates(true)
.create();
applicationPackage = batchManager.applicationPackages()
.define(applicationPackageName)
.withExistingApplication(resourceGroup, batchAccountName, applicationName)
.create();Java Legacy Azure SDK → Modern Azure SDK
Scenario scope: Upgrade a Maven/Gradle project's Azure SDK dependencies fromcom.microsoft.azure.*(legacy, end-of-support 2023) tocom.azure.*(modern) — source code, build files, tests.
>
This is a source-code modernization flow, not an Azure service/plan/SKU upgrade. Follow the workflow below instead of the top-level azure-upgrade Steps. Do NOT use this for .NET, Python, JavaScript, or Go Azure SDK upgrades.Upgrade all com.microsoft.azure.* to com.azure.* equivalents in one autonomous session.
You are an expert Azure SDK migration agent. Generate a unique run identifier at the start (format: azure-sdk-upgrade-YYYYMMDD-HHMMSS) and use it throughout all phases.
⚠️ Lazy loading: Do NOT pre-fetch the reference files listed below. Load each one only when its workflow step is reached or its trigger condition fires. Loading them upfront wastes context and causes premature decisions.
Workflow (load references on demand)
Full procedure: per-phase files under ./workflow/ (load each one when entering that phase). Global rules apply to every step: rules/execution-guidelines.md, rules/efficiency.md.
1. Precheck (workflow/phase-1-precheck.md) — Verify Maven/Gradle project, detect JDK/build tools. If git available, create branch java-upgrade/{RUN_ID}. → load ./templates/PLAN_TEMPLATE.md to create plan.md.
- Step-wise rules: rules/execution-guidelines.md (Output directory, Git, Wrapper preference).
2. Plan (workflow/phase-2-plan.md) — Inventory deps and populate plan.md. → load ./INSTRUCTION.md for package mappings.
- Step-wise rules: rules/upgrade-strategy.md (Incremental, Risk-first, Successor preference, Necessary/Meaningful steps).
3. Execute (workflow/phase-3-execute.md) — Migrate build config then source, build/test/fix, commit per step. → load ./templates/PROGRESS_TEMPLATE.md to create progress.md; load ./rules/ before running builds/tests.
- Step-wise rules: rules/review-code-changes.md, rules/upgrade-strategy.md (Automation tools, Temporary errors OK), rules/execution-guidelines.md (Template compliance, Git).
4. Validate (workflow/phase-4-summarize.md) — Apply validation checklist. → load ./templates/SUMMARY_TEMPLATE.md to create summary.md; load ./INSTRUCTION.md#validation.
- Step-wise rules: rules/upgrade-success-criteria.md.
Constraints
- 100% test pass · no premature termination · incremental changes · review each step
- Prefer wrappers (
mvnw/gradlew)
Examples
"upgrade legacy azure sdk" → precheck → plan → execute → validateEfficiency
- Targeted reads: Use
grepover full file reads; read sections, not entire files. - Quiet commands: Use
-q,--quietfor build/test when appropriate. - Progressive writes: Update
plan.mdandprogress.mdincrementally, not at end.
Execution Guidelines
- Wrapper preference: Use Maven Wrapper (
mvnw/mvnw.cmd) or Gradle Wrapper (gradlew/gradlew.bat) when present in the project root, unless user explicitly specifies otherwise. - Template compliance: Follow the HTML-comment instructions in the template reference files when creating and populating
.github/java-upgrade/{RUN_ID}/plan.md,progress.md,summary.md. You may remove the HTML comments after populating each section. - Output directory: All plan/progress/summary files are created under
.github/java-upgrade/{RUN_ID}/in the project being migrated. Create this directory at the start of the run. - Uninterrupted run: Complete each phase fully without pausing for user input.
- Git: If git is available, create a new branch
java-upgrade/{RUN_ID}before starting the migration. Commit changes per step on this branch. If git is not available, log a warning and proceed — files remain uncommitted in the working directory. UseN/Afor<current_branch>and<current_commit_id>placeholders.
Review Code Changes (MANDATORY for each step)
After completing changes in each step, review code changes per the rules in the Progress Template BEFORE verification. Key areas:
- Sufficiency: All required upgrade changes are present — no missing modifications that would leave the upgrade incomplete.
- Necessity: No critical unnecessary changes. Unnecessary changes that do not affect behavior may be retained; however, it is essential to ensure that functional behavior remains consistent and security controls are preserved.
Troubleshooting & Anti-Excuse Rules
Load this file when encountering build failures, test failures, or any temptation to stop mid-migration.
Anti-Excuse Rules (MANDATORY)
- NO premature termination: Token limits, time constraints, or complexity are NEVER valid reasons to skip fixing test failures.
- NO "close enough" acceptance: 95% is NOT 100%. Every failing test requires a fix attempt with documented root cause.
- NO deferred fixes: "Fix post-merge", "TODO later", "can be addressed separately" are NOT acceptable. Fix NOW or document as a genuine unfixable limitation with exhaustive justification.
- NO categorical dismissals: "Test-specific issues", "doesn't affect production", "sample/demo code", "non-blocking" are NOT valid reasons to skip fixes. ALL tests must pass.
- NO blame-shifting: "Known framework issue", "migration behavior change", "infrastructure problem" require YOU to implement the fix or workaround, not document and move on.
- Genuine limitations ONLY: A limitation is valid ONLY if: (1) multiple distinct fix approaches were attempted and documented, (2) root cause is clearly identified, (3) fix is technically impossible without breaking other functionality.
Critical: Do Not Stop Mid-Migration
You are expected to carry the migration to completion — either fully succeed or encounter an unrecoverable error. The following behaviors are strictly prohibited:
- Do NOT stop to summarize progress. Never output a message listing "what was done" and "what remains" as your final response.
- Do NOT treat partial migration as acceptable. Migrating some files but not others is not a valid stopping point. You must attempt every file and every dependency.
- Do NOT hand off work to the user. Never suggest the user "continue" or "complete the remaining items." You are responsible for finishing everything.
- If you hit an error on one file, move on to the next. A failure in one source file should not prevent you from migrating the rest. Come back to fix it after attempting all files.
- If a build fails after migration, debug and fix it. Do not stop at "build failed." Investigate the errors, fix them, and rebuild. Repeat until the build passes or you have exhausted all reasonable approaches.
The only acceptable stopping conditions are: 1. The migration is fully complete and the build passes. 2. You have attempted everything and an unrecoverable error prevents further progress (e.g., a fundamental API incompatibility with no workaround). In this case, clearly state the blocker.
Upgrade Strategy
- Incremental upgrades: Stepwise dependency upgrades to avoid large jumps breaking builds.
- Minimal changes: Only upgrade dependencies essential for compatibility with the modern Azure SDKs.
- Risk-first: Handle EOL/challenging deps early in isolated steps.
- Necessary/Meaningful steps only: Each step MUST change code/config. NO steps for pure analysis/validation. Merge small related changes. Test: "Does this step modify project files?"
- Automation tools: Use automation tools like OpenRewrite for efficiency; always verify output. For BOM upgrades, run the `scripts/upgrade_bom.py` script in the parent folder when Python 3.8+ is available; if Python is not available, follow the Manual Fallback sections in bom-maven.md / bom-gradle.md instead (see Migration Guidelines).
- Successor preference: Compatible successor > Adapter pattern > Code rewrite.
- Build tool compatibility: Check Maven/Gradle version compatibility with the project's JDK. Upgrade the build tool (including wrapper) if the current version does not support the JDK.
- Temporary errors OK: Steps may pass with known errors if resolved later or pre-existing.
Upgrade Success Criteria (ALL must be met)
- Goal: All legacy Azure SDK dependencies (
com.microsoft.azure.*) replaced with modern equivalents (com.azure.*). - Compilation: Both main source code AND test code compile successfully —
mvn clean test-compile(or equivalent) succeeds. - Test: 100% test pass rate —
mvn clean testsucceeds. Minimum acceptable: test pass rate ≥ baseline (pre-upgrade pass rate). Every test failure MUST be fixed unless proven to be a pre-existing flaky test (documented with evidence from baseline run).
If any criterion is not met, load `./troubleshooting.md` at that point — do NOT stop or defer.
#!/usr/bin/env python3
"""Upgrade or add azure-sdk-bom in a Maven or Gradle project using OpenRewrite.
Detects the build system automatically and applies the appropriate OpenRewrite
recipes. All operations use OpenRewrite — no manual XML/text manipulation.
Step 1 – Add or upgrade BOM:
- Maven (add): org.openrewrite.maven.AddManagedDependency
- Maven (upgrade): org.openrewrite.maven.UpgradeDependencyVersion
- Gradle (add): org.openrewrite.gradle.AddPlatformDependency
- Gradle (upgrade):org.openrewrite.gradle.UpgradeDependencyVersion
Step 2 – Remove redundant explicit versions:
- Maven: org.openrewrite.maven.RemoveRedundantDependencyVersions
- Gradle: org.openrewrite.gradle.RemoveRedundantDependencyVersions
Usage:
python3 upgrade_bom.py <project_dir> <bom_version> [options]
python3 upgrade_bom.py --get-latest-version
Arguments:
project_dir Path to the project root (must contain pom.xml or build.gradle).
bom_version Target azure-sdk-bom version to apply. Resolve the latest stable version first.
Options:
--mvn <cmd> Maven command override.
--gradle <cmd> Gradle command override.
"""
from __future__ import annotations
import argparse
import os
import re
import stat
import subprocess
import sys
import textwrap
import urllib.error
import urllib.request
import xml.etree.ElementTree as ET
GROUP_ID = "com.azure"
ARTIFACT_ID = "azure-sdk-bom"
BOM_POM_URL = "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/boms/azure-sdk-bom/pom.xml"
POM_NAMESPACE = {"m": "http://maven.apache.org/POM/4.0.0"}
# Maven constants
MVN_REWRITE_PLUGIN = "org.openrewrite.maven:rewrite-maven-plugin"
MVN_REWRITE_ARTIFACT_COORDS = "org.openrewrite:rewrite-maven"
MVN_UPGRADE_RECIPE = "org.openrewrite.maven.UpgradeDependencyVersion"
MVN_ADD_MANAGED_RECIPE = "org.openrewrite.maven.AddManagedDependency"
MVN_REMOVE_REDUNDANT_RECIPE = "org.openrewrite.maven.RemoveRedundantDependencyVersions"
# Gradle constants
GRADLE_UPGRADE_RECIPE = "org.openrewrite.gradle.UpgradeDependencyVersion"
GRADLE_ADD_PLATFORM_RECIPE = "org.openrewrite.gradle.AddPlatformDependency"
GRADLE_REMOVE_REDUNDANT_RECIPE = "org.openrewrite.gradle.RemoveRedundantDependencyVersions"
REWRITE_YML_NAME = "rewrite.yml"
GRADLE_PLUGIN_MARKER = "// --- openrewrite-upgrade-bom-plugin (auto-added, safe to remove) ---"
# ---------------------------------------------------------------------------
# Build-system detection
# ---------------------------------------------------------------------------
def _detect_build_system(project_dir: str) -> str:
"""Return 'maven' or 'gradle' depending on which build file is present."""
if os.path.isfile(os.path.join(project_dir, "pom.xml")):
return "maven"
for name in ("build.gradle", "build.gradle.kts"):
if os.path.isfile(os.path.join(project_dir, name)):
return "gradle"
return "unknown"
def _get_latest_bom_version() -> str:
try:
with urllib.request.urlopen(BOM_POM_URL) as response:
pom_xml = response.read()
except urllib.error.URLError as exc:
raise SystemExit(f"Failed to download {BOM_POM_URL}: {exc}") from exc
try:
root = ET.fromstring(pom_xml)
except ET.ParseError as exc:
raise SystemExit(f"Failed to parse BOM pom.xml: {exc}") from exc
version = root.findtext("m:version", namespaces=POM_NAMESPACE)
if not version:
raise SystemExit("Failed to find the azure-sdk-bom <version> in pom.xml")
return version.strip()
# ---------------------------------------------------------------------------
# Maven helpers
# ---------------------------------------------------------------------------
def _detect_maven(project_dir: str) -> str:
if sys.platform == "win32":
wrapper = os.path.join(project_dir, "mvnw.cmd")
# .cmd files on Windows are invoked by the shell; no executable bit needed.
if os.path.isfile(wrapper):
return wrapper
else:
wrapper = os.path.join(project_dir, "mvnw")
if os.path.isfile(wrapper):
if not os.access(wrapper, os.X_OK):
# Wrapper exists but isn't executable (common after fresh clones
# on filesystems that don't preserve the +x bit). Try to fix it.
try:
mode = os.stat(wrapper).st_mode
os.chmod(wrapper, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
print(f"[upgrade_bom] Added executable bit to {wrapper}.")
except OSError as exc:
print(
f"[upgrade_bom] WARNING: mvnw exists at {wrapper} but is not "
f"executable and chmod failed ({exc}); falling back to 'mvn'.",
file=sys.stderr,
)
return "mvn"
if os.access(wrapper, os.X_OK):
return wrapper
return "mvn"
def _has_maven_bom_entry(pom_path: str) -> bool:
try:
tree = ET.parse(pom_path)
except ET.ParseError:
return False
ns = {"m": "http://maven.apache.org/POM/4.0.0"}
for dep in tree.findall(".//m:dependencyManagement/m:dependencies/m:dependency", ns):
gid = dep.find("m:groupId", ns)
aid = dep.find("m:artifactId", ns)
if gid is not None and aid is not None:
if gid.text == GROUP_ID and aid.text == ARTIFACT_ID:
return True
for dep in tree.findall(".//dependencyManagement/dependencies/dependency"):
gid = dep.find("groupId")
aid = dep.find("artifactId")
if gid is not None and aid is not None:
if gid.text == GROUP_ID and aid.text == ARTIFACT_ID:
return True
return False
def _run_maven_recipe(mvn_cmd: str, project_dir: str, recipe: str, options: str) -> int:
"""Run an OpenRewrite recipe via the rewrite-maven-plugin."""
cmd = [
mvn_cmd, "-U",
f"{MVN_REWRITE_PLUGIN}:run",
f"-Drewrite.recipeArtifactCoordinates={MVN_REWRITE_ARTIFACT_COORDS}",
f"-Drewrite.activeRecipes={recipe}",
f"-Drewrite.options={options}",
]
print(f"[upgrade_bom] Running: {' '.join(cmd)}")
return subprocess.run(cmd, cwd=project_dir).returncode
def _handle_maven(project_dir: str, bom_version: str, mvn_cmd: str | None) -> int:
pom_path = os.path.join(project_dir, "pom.xml")
mvn = mvn_cmd or _detect_maven(project_dir)
# Step 1: Add or upgrade the BOM
if not _has_maven_bom_entry(pom_path):
print("[upgrade_bom] No existing azure-sdk-bom entry found — adding via AddManagedDependency.")
options = ",".join([
f"groupId={GROUP_ID}",
f"artifactId={ARTIFACT_ID}",
f"version={bom_version}",
"type=pom",
"scope=import",
])
rc = _run_maven_recipe(mvn, project_dir, MVN_ADD_MANAGED_RECIPE, options)
if rc != 0:
print(f"[upgrade_bom] ERROR: AddManagedDependency exited with code {rc}", file=sys.stderr)
return rc
print(f"[upgrade_bom] azure-sdk-bom {bom_version} added successfully.")
else:
print(f"[upgrade_bom] Existing azure-sdk-bom entry found — upgrading to {bom_version}.")
options = ",".join([
f"groupId={GROUP_ID}",
f"artifactId={ARTIFACT_ID}",
f"newVersion={bom_version}",
"overrideManagedVersion=true",
])
rc = _run_maven_recipe(mvn, project_dir, MVN_UPGRADE_RECIPE, options)
if rc != 0:
print(f"[upgrade_bom] ERROR: UpgradeDependencyVersion exited with code {rc}", file=sys.stderr)
return rc
print(f"[upgrade_bom] azure-sdk-bom upgraded to {bom_version} successfully.")
# Step 2: Remove explicit versions from Azure deps managed by the BOM
print("[upgrade_bom] Removing redundant explicit versions for Azure dependencies...")
options = f"groupPattern={GROUP_ID}*,onlyIfManagedVersionIs=GTE"
rc = _run_maven_recipe(mvn, project_dir, MVN_REMOVE_REDUNDANT_RECIPE, options)
if rc != 0:
print(f"[upgrade_bom] WARNING: RemoveRedundantDependencyVersions exited with code {rc}", file=sys.stderr)
else:
print("[upgrade_bom] Redundant explicit versions removed successfully.")
return rc
# ---------------------------------------------------------------------------
# Gradle helpers
# ---------------------------------------------------------------------------
def _detect_gradle(project_dir: str) -> str:
if sys.platform == "win32":
wrapper = os.path.join(project_dir, "gradlew.bat")
if os.path.isfile(wrapper):
return wrapper
else:
wrapper = os.path.join(project_dir, "gradlew")
if os.path.isfile(wrapper):
if not os.access(wrapper, os.X_OK):
try:
mode = os.stat(wrapper).st_mode
os.chmod(wrapper, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
print(f"[upgrade_bom] Added executable bit to {wrapper}.")
except OSError as exc:
print(
f"[upgrade_bom] WARNING: gradlew exists at {wrapper} but is not "
f"executable and chmod failed ({exc}); falling back to 'gradle'.",
file=sys.stderr,
)
return "gradle"
if os.access(wrapper, os.X_OK):
return wrapper
return "gradle"
def _find_gradle_build_file(project_dir: str) -> str | None:
for name in ("build.gradle", "build.gradle.kts"):
path = os.path.join(project_dir, name)
if os.path.isfile(path):
return path
return None
def _is_kotlin_dsl(build_file: str) -> bool:
return build_file.endswith(".kts")
def _has_gradle_bom_entry(build_file: str) -> bool:
"""Check whether build.gradle already references azure-sdk-bom."""
try:
with open(build_file, "r", encoding="utf-8") as f:
content = f.read()
except OSError:
return False
return f"{GROUP_ID}:{ARTIFACT_ID}" in content
def _create_rewrite_yml(project_dir: str, bom_version: str, has_bom: bool) -> str:
"""Create a temporary rewrite.yml with the appropriate OpenRewrite recipes.
When has_bom is True, uses UpgradeDependencyVersion to upgrade the existing BOM.
When has_bom is False, uses AddPlatformDependency to add a new enforcedPlatform BOM.
Always includes RemoveRedundantDependencyVersions as a final step.
"""
yml_path = os.path.join(project_dir, REWRITE_YML_NAME)
recipes: list[str] = []
if has_bom:
recipes.append(textwrap.dedent(f"""\
- org.openrewrite.gradle.UpgradeDependencyVersion:
groupId: {GROUP_ID}
artifactId: {ARTIFACT_ID}
newVersion: {bom_version}"""))
else:
recipes.append(textwrap.dedent(f"""\
- org.openrewrite.gradle.AddPlatformDependency:
groupId: {GROUP_ID}
artifactId: {ARTIFACT_ID}
version: {bom_version}
configuration: implementation
enforced: true"""))
recipes.append(textwrap.dedent(f"""\
- org.openrewrite.gradle.RemoveRedundantDependencyVersions:
groupPattern: {GROUP_ID}*
onlyIfManagedVersionIs: GTE"""))
yml_content = textwrap.dedent("""\
---
type: specs.openrewrite.org/v1beta/recipe
name: com.azure.UpgradeBom
displayName: Upgrade azure-sdk-bom and remove redundant versions
recipeList:
""") + "\n".join(recipes) + "\n"
with open(yml_path, "w", encoding="utf-8") as f:
f.write(yml_content)
print(f"[upgrade_bom] Created {yml_path}")
return yml_path
def _inject_gradle_rewrite_plugin(build_file: str) -> bool:
"""Temporarily add the OpenRewrite plugin to build.gradle if not present.
Returns True if the plugin block was injected (and should be cleaned up).
"""
with open(build_file, "r", encoding="utf-8") as f:
content = f.read()
if "org.openrewrite.rewrite" in content:
return False
kotlin = _is_kotlin_dsl(build_file)
if kotlin:
plugin_line = ' id("org.openrewrite.rewrite") version "latest.release"'
else:
plugin_line = ' id "org.openrewrite.rewrite" version "latest.release"'
rewrite_block_kt = textwrap.dedent("""\
rewrite {
activeRecipe("com.azure.UpgradeBom")
}
repositories {
mavenCentral()
}
""")
rewrite_block_groovy = rewrite_block_kt # same syntax for both DSLs here
plugins_pattern = re.compile(r"(plugins\s*\{)", re.MULTILINE)
match = plugins_pattern.search(content)
if match:
insert_pos = match.end()
# content[insert_pos:] already starts with the newline that follows
# `plugins {`, so don't add another one before the marker.
content = (
content[:insert_pos]
+ "\n"
+ GRADLE_PLUGIN_MARKER
+ "\n"
+ plugin_line
+ content[insert_pos:]
)
else:
# No plugins block — prepend one
content = (
"plugins {\n"
+ GRADLE_PLUGIN_MARKER
+ "\n"
+ plugin_line
+ "\n}\n\n"
+ content
)
content += GRADLE_PLUGIN_MARKER + "\n"
content += rewrite_block_kt if kotlin else rewrite_block_groovy
with open(build_file, "w", encoding="utf-8") as f:
f.write(content)
print(f"[upgrade_bom] Injected OpenRewrite plugin into {build_file}")
return True
def _remove_gradle_rewrite_plugin(build_file: str) -> None:
"""Remove the temporarily injected OpenRewrite plugin and config blocks."""
with open(build_file, "r", encoding="utf-8") as f:
lines = f.readlines()
cleaned: list[str] = []
marker_count = 0
i = 0
while i < len(lines):
line = lines[i]
if GRADLE_PLUGIN_MARKER in line:
marker_count += 1
if marker_count == 1:
# First marker (inside plugins {}): skip the marker line and
# the following injected plugin id line.
i += 2
continue
else:
# Second marker (at end of file): skip the marker and every
# remaining line — they're the injected rewrite {} and
# repositories {} blocks.
break
cleaned.append(line)
i += 1
with open(build_file, "w", encoding="utf-8") as f:
f.writelines(cleaned)
print(f"[upgrade_bom] Cleaned up OpenRewrite plugin from {build_file}")
def _run_gradle_openrewrite(gradle_cmd: str, project_dir: str) -> int:
cmd = [gradle_cmd, "rewriteRun"]
print(f"[upgrade_bom] Running: {' '.join(cmd)}")
return subprocess.run(cmd, cwd=project_dir).returncode
def _handle_gradle(project_dir: str, bom_version: str, gradle_cmd: str | None) -> int:
build_file = _find_gradle_build_file(project_dir)
if build_file is None:
print("[upgrade_bom] ERROR: no build.gradle or build.gradle.kts found", file=sys.stderr)
return 1
gradle = gradle_cmd or _detect_gradle(project_dir)
has_bom = _has_gradle_bom_entry(build_file)
if has_bom:
print(f"[upgrade_bom] Existing azure-sdk-bom entry found — upgrading to {bom_version}.")
else:
print("[upgrade_bom] No existing azure-sdk-bom entry found — adding via AddPlatformDependency.")
yml_path = None
injected = False
try:
# Set up OpenRewrite: create rewrite.yml + inject plugin temporarily
yml_path = _create_rewrite_yml(project_dir, bom_version, has_bom=has_bom)
injected = _inject_gradle_rewrite_plugin(build_file)
rc = _run_gradle_openrewrite(gradle, project_dir)
finally:
if yml_path and os.path.isfile(yml_path):
os.remove(yml_path)
print(f"[upgrade_bom] Removed {yml_path}")
if injected:
_remove_gradle_rewrite_plugin(build_file)
if rc != 0:
print(f"[upgrade_bom] ERROR: OpenRewrite exited with code {rc}", file=sys.stderr)
else:
print(f"[upgrade_bom] BOM set to {bom_version} and redundant versions removed successfully.")
return rc
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
description="Upgrade azure-sdk-bom version in a Maven or Gradle project using OpenRewrite."
)
parser.add_argument("project_dir", nargs="?", help="Path to the project root.")
parser.add_argument(
"bom_version",
nargs="?",
help="Target azure-sdk-bom version to apply. Resolve the latest stable version first.",
)
parser.add_argument("--mvn", default=None, help="Maven command override.")
parser.add_argument("--gradle", default=None, help="Gradle command override.")
parser.add_argument(
"--get-latest-version",
action="store_true",
help="Print the latest azure-sdk-bom version from the Azure SDK for Java BOM pom.xml.",
)
args = parser.parse_args(argv)
if args.get_latest_version:
if args.project_dir or args.bom_version:
parser.error("--get-latest-version does not accept project_dir or bom_version.")
print(_get_latest_bom_version())
return 0
if not args.project_dir or not args.bom_version:
parser.error("project_dir and bom_version are required unless --get-latest-version is used.")
project_dir = os.path.abspath(args.project_dir)
build_system = _detect_build_system(project_dir)
if build_system == "maven":
print("[upgrade_bom] Detected Maven project.")
return _handle_maven(project_dir, args.bom_version, args.mvn)
elif build_system == "gradle":
print("[upgrade_bom] Detected Gradle project.")
return _handle_gradle(project_dir, args.bom_version, args.gradle)
else:
print(
f"[upgrade_bom] ERROR: No pom.xml or build.gradle found in {project_dir}",
file=sys.stderr,
)
return 1
if __name__ == "__main__":
sys.exit(main())
<!-- This is the upgrade plan template for Azure SDK migration. RUN_ID should be replaced with the actual run identifier.
PLANNING RULES
!!! DON'T REMOVE THIS COMMENT BLOCK BEFORE FINAL PLAN IS GENERATED AS IT CONTAINS IMPORTANT INSTRUCTIONS.
Strategy
- Incremental upgrades: Stepwise dependency upgrades to avoid large jumps breaking builds
- Minimal changes: Only upgrade dependencies essential for compatibility
- Risk-first: Handle EOL/challenging deps early in isolated steps
- Necessary/Meaningful steps only: Each step MUST change code/config. NO steps for pure analysis/validation. Merge small related changes.
Mandatory Steps
- Step 1 (MANDATORY): Setup Baseline - Run compile/test with current JDK, document results.
- Steps 2-N: Upgrade steps - dependency order, high-risk early, isolated breaking changes
- Final step (MANDATORY): Final Validation - verify all goals met, all TODOs resolved, 100% tests pass
Verification Expectations
- Steps 1-N (Setup/Upgrade): Focus on COMPILATION SUCCESS. Tests may fail during intermediate steps.
- Final Validation: COMPILATION SUCCESS + 100% TEST PASS
Efficiency (IMPORTANT)
- Targeted reads: Use
grepover full file reads; read specific sections, not entire files. Template files are large - only read the sections you need. - Quiet commands: Use
-q,--quietfor build/test commands when appropriate - Progressive writes: Update plan.md incrementally, not at end
-->
Upgrade Plan: <PROJECT_NAME> (<RUN_ID>)
- Generated: <datetime> <!-- replace with actual date and time when generating -->
- HEAD Branch: <current_branch> <!-- replace with actual head branch when generating -->
- HEAD Commit ID: <current_commit_id> <!-- replace with actual head commit id when generating -->
Available Tools
<!-- List ONLY the JDKs and build tools that are required/used during the upgrade (not all discovered ones). Use the environment detection results from Precheck to check availability. Mark build tools that need upgrading for JDK compatibility as "<TO_BE_UPGRADED>". If a wrapper (mvnw/gradlew) is present, also check the wrapper-defined version in .mvn/wrapper/maven-wrapper.properties or gradle/wrapper/gradle-wrapper.properties.
NOTE: This section is finalized during Upgrade Path Design (after step sequence is known), not during Environment Analysis.
SAMPLE: JDKs
- JDK 1.8.0: /path/to/jdk-8 (current project JDK, used by step 1)
Build Tools
- Maven 3.9.6: /path/to/maven
- Maven Wrapper: 3.8.1 → <TO_BE_UPGRADED> to 3.9.6+ (current version incompatible with project requirements)
-->
Guidelines
<!-- User-specified guidelines or constraints in bullet points for this upgrade. Extract these from the user's prompt if provided, or leave empty if none specified. These guidelines take precedence over default upgrade strategies. -->
Note: You can add any specific guidelines or constraints for the upgrade process here if needed, bullet points are preferred. <!-- this note is for users, NEVER remove it -->
Upgrade Goals
<!-- The primary goal is to replace all legacy Azure SDK dependencies (com.microsoft.azure.) with their modern equivalents (com.azure.). List any additional user-specified goals below.
SAMPLE:
- Replace all
com.microsoft.azure.*dependencies withcom.azure.*equivalents - Migrate source code to use modern Azure SDK APIs (builder pattern, Azure Identity)
-->
Technology Stack
<!-- Table of core dependencies and their compatibility with upgrade goals. IMPORTANT: Analyze ALL modules in multi-module projects, not just the root module. Only include: direct dependencies + those critical for upgrade compatibility.
Columns:
- Technology/Dependency: Name of the dependency
- Current: Version currently in use
- Modern Equivalent: The com.azure.* replacement (or N/A if not an Azure SDK dep)
- Migration Notes: Notes on migration approach
IMPORTANT: Include build tools (Maven/Gradle), wrappers, and key build plugins in this table.
SAMPLE:
| Technology/Dependency | Current | Modern Equivalent | Migration Notes |
|---|---|---|---|
| com.microsoft.azure:azure-mgmt-resources | 1.41.4 | com.azure.resourcemanager:azure-resourcemanager | Use azure-sdk-bom for version management |
| com.microsoft.azure:azure-mgmt-storage | 1.41.4 | com.azure.resourcemanager:azure-resourcemanager | Included in azure-resourcemanager |
| com.microsoft.azure:azure-client-authentication | 1.7.14 | com.azure:azure-identity | Use ClientSecretCredential or DefaultAzureCredential |
| Maven (wrapper) | 3.6.3 | - | Check compatibility with project JDK |
-->
| Technology/Dependency | Current | Modern Equivalent | Migration Notes |
|---|
Derived Upgrades
<!-- Required upgrades inferred from the Azure SDK migration. Each derived upgrade must have a justification explaining WHY it's required. Common derivations:
- Legacy auth (azure-client-authentication) → azure-identity
- Legacy management (azure-mgmt-) → azure-resourcemanager or specific azure-resourcemanager- modules
- Legacy data plane SDKs → modern com.azure equivalents
- Add azure-sdk-bom for version management
SAMPLE:
- Add azure-sdk-bom for centralized version management of com.azure.* dependencies
- Replace azure-client-authentication with azure-identity (modern authentication library)
- Add jackson-databind if file-based authentication is used and Jackson is not already present
-->
Upgrade Steps
<!-- Step-by-step upgrade plan. Each step should follow this format:
- Step N: <Descriptive Title>
- Rationale: Why this step is needed and why at this position
- Changes to Make: ≤5 bullet points (concise)
- Verification: Command, JDK, Expected Result
VERIFICATION EXPECTATIONS:
- Steps 1-N (Setup and Upgrade steps): Focus on COMPILATION SUCCESS. Tests may fail during intermediate steps.
- Final step: COMPILATION SUCCESS + TEST PASS through iterative fix loop.
MANDATORY FIRST STEP: The first step MUST always be Setup Baseline.
MANDATORY SETUP BASELINE STEP SAMPLE:
- Step 1: Setup Baseline
- Rationale: Establish pre-upgrade compile and test results to measure upgrade success against.
- Changes to Make:
- [ ] Run baseline compilation with current JDK
- [ ] Run baseline tests with current JDK
- Verification:
- Command:
mvn clean compile test-compile -q && mvn clean test -q - JDK: <current project JDK path>
- Expected: Document SUCCESS/FAILURE, test pass rate (forms acceptance criteria)
---
SAMPLE STEP (dependency migration):
- Step N: Migrate Azure Management Dependencies
- Rationale: Replace legacy com.microsoft.azure management dependencies with modern com.azure.resourcemanager equivalents.
- Changes to Make:
- [ ] Add azure-sdk-bom to dependencyManagement
- [ ] Replace com.microsoft.azure:azure-mgmt-* with com.azure.resourcemanager:azure-resourcemanager
- [ ] Remove com.microsoft.azure:azure-client-authentication, add com.azure:azure-identity
- [ ] Fix compilation errors from API changes
- Verification:
- Command:
mvn clean test-compile -q - JDK: <JDK path>
- Expected: Compilation SUCCESS (tests may fail - will be fixed in Final Validation)
---
MANDATORY FINAL STEP (must always be the last step):
- Step N: Final Validation
- Rationale: Verify all upgrade goals met, project compiles successfully, all tests pass.
- Changes to Make:
- [ ] Verify no legacy com.microsoft.azure.* dependencies remain
- [ ] Resolve ALL TODOs and temporary workarounds from previous steps
- [ ] Clean rebuild with current JDK
- [ ] Fix any remaining compilation errors
- [ ] Run full test suite and fix ALL test failures (iterative fix loop until 100% pass)
- Verification:
- Command:
mvn clean test -q - JDK: <JDK path>
- Expected: Compilation SUCCESS + 100% tests pass
-->
Key Challenges
<!-- Document high-risk areas that require special attention during upgrade. Each challenge should have a mitigation strategy. Be concise. Common challenges for Azure SDK migration:
- Authentication pattern changes (file-based auth, service principal)
- API surface changes (fluent builder patterns differ between legacy and modern)
- Async/reactive pattern differences
- Package structure changes (com.microsoft.azure.management. → com.azure.resourcemanager.)
SAMPLE:
- Authentication Migration
- Challenge: Legacy code uses file-based authentication via Azure.authenticate(credentialFile). Modern SDK requires explicit credential construction.
- Strategy: Read credential file with Jackson ObjectMapper, construct ClientSecretCredential, use AzureProfile for subscription context.
- Fluent API Changes
- Challenge: Method names and builder patterns differ between legacy and modern Azure Resource Manager.
- Strategy: Follow the migration guide at https://aka.ms/java-track2-migration-guide for method-level mappings.
-->
<!-- This is the upgrade progress tracker for Azure SDK migration. Each step from plan.md should be tracked here with status, changes, verification results, and TODOs.
EXECUTION RULES
!!! DON'T REMOVE THIS COMMENT BLOCK BEFORE UPGRADE IS COMPLETE AS IT CONTAINS IMPORTANT INSTRUCTIONS.
Success Criteria
- Goal: All legacy Azure SDK dependencies (com.microsoft.azure.) replaced with modern equivalents (com.azure.)
- Compilation: Both main source code AND test code compile =
mvn clean test-compilesucceeds - Test: 100% test pass rate =
mvn clean testsucceeds (or ≥ baseline with documented pre-existing flaky tests)
Strategy
- Uninterrupted run: Complete execution without pausing for user input
- NO premature termination: Token limits, time constraints, or complexity are NEVER valid reasons to skip fixing.
- Automation tools: Use OpenRewrite etc. for efficiency; always verify output
Verification Expectations
- Steps 1-N (Setup/Upgrade): Focus on COMPILATION SUCCESS (both main and test code).
- On compilation success: Commit and proceed (even if tests fail - document count)
- On compilation error: Fix IMMEDIATELY and re-verify until both main and test code compile
- NO deferred fixes (for compilation): "Fix post-merge", "TODO later", "can be addressed separately" are NOT acceptable. Fix NOW or document as genuine unfixable limitation.
- Final Validation Step: Achieve COMPILATION SUCCESS + 100% TEST PASS.
- On test failure: Enter iterative test & fix loop until 100% pass or rollback to last-good-commit after exhaustive fix attempts
- NO deferring test fixes - this is the final gate
- NO categorical dismissals: "Test-specific issues", "doesn't affect production", "sample/demo code" are NOT valid reasons to skip. ALL tests must pass.
- NO "close enough" acceptance: 95% is NOT 100%. Every failing test requires a fix attempt with documented root cause.
- NO blame-shifting: "Known framework issue", "migration behavior change" require YOU to implement the fix or workaround.
Review Code Changes (MANDATORY for each step)
After completing changes in each step, review code changes BEFORE verification to ensure:
1. Sufficiency: All changes required for the upgrade goal are present — no missing modifications that would leave the upgrade incomplete.
- All dependencies/plugins listed in the plan for this step are updated
- All required code changes (API migrations, import updates, config changes) are made
- All compilation and compatibility issues introduced by the upgrade are addressed
2. Necessity: All changes are strictly necessary for the upgrade — no unnecessary modifications, refactoring, or "improvements" beyond what's required. This includes:
- Functional Behavior Consistency: Original code behavior and functionality are maintained:
- Business logic unchanged
- API contracts preserved (inputs, outputs, error handling)
- Expected outputs and side effects maintained
- Security Controls Preservation (critical subset of behavior):
- Authentication: Login mechanisms, session management, token validation, MFA configurations
- Authorization: Role-based access control, permission checks, access policies, security annotations (@PreAuthorize, @Secured, etc.)
- Password handling: Password encoding/hashing algorithms, password policies, credential storage
- Security configurations: CORS policies, CSRF protection, security headers, SSL/TLS settings, OAuth/OIDC configurations
- Audit logging: Security event logging, access logging
Review Code Changes Actions:
- Review each changed file for missing upgrade changes, unintended behavior or security modifications
- If behavior must change due to framework requirements, document the change, the reason, and confirm equivalent functionality/protection is maintained
- Add missing changes that are required for the upgrade step to be complete
- Revert unnecessary changes that don't affect behavior or security controls
- Document review results in progress.md and commit message
Commit Message Format
- First line:
Step <x>: <title> - Compile: <result>orStep <x>: <title> - Compile: <result>, Tests: <pass>/<total> passed - Body: Changes summary + concise known issues/limitations (≤5 lines)
- Security note: If any security-related changes were made, include "Security: <change description and justification>"
Efficiency (IMPORTANT)
- Targeted reads: Use
grepover full file reads; read specific sections, not entire files. Template files are large - only read the section you need. - Quiet commands: Use
-q,--quietfor build/test commands when appropriate - Progressive writes: Update progress.md incrementally after each step, not at end
-->
Upgrade Progress: <PROJECT_NAME> (<RUN_ID>)
- Started: <timestamp> <!-- replace with actual start timestamp -->
- Plan Location:
.github/java-upgrade/<RUN_ID>/plan.md - Total Steps: <number of steps from plan.md>
Step Details
<!-- For each step in plan.md, track progress using this bullet list format:
- Step N: <Step Title>
- Status: <status emoji>
- 🔘 Not Started - Step has not been started yet
- ⏳ In Progress - Currently working on this step
- ✅ Completed - Step completed successfully
- ❗ Failed - Step failed after exhaustive attempts
- Changes Made: (≤5 bullets, keep each ≤20 words)
- Focus on what changed, not how
- Review Code Changes:
- Sufficiency: ✅ All required changes present / ⚠️ <list missing changes added, short and concise>
- Necessity: ✅ All changes necessary / ⚠️ <list unnecessary changes reverted, short and concise>
- Functional Behavior: ✅ Preserved / ⚠️ <list unavoidable changes with justification, short and concise>
- Security Controls: ✅ Preserved / ⚠️ <list unavoidable changes with justification and equivalent protection, short and concise>
- Verification:
- Command: <actual command executed>
- JDK: <JDK path used>
- Build tool: <Path of build tool used>
- Result: <SUCCESS/FAILURE with details>
- Notes: <any skipped checks, excluded modules, known issues>
- Deferred Work: List any deferred work, temporary workarounds (or "None")
- Commit: <commit hash> - <commit message first line>
---
SAMPLE UPGRADE STEP:
- Step X: Migrate Azure Management Dependencies
- Status: ✅ Completed
- Changes Made:
- Added azure-sdk-bom to dependencyManagement
- Replaced com.microsoft.azure:azure-mgmt-* with com.azure.resourcemanager
- Replaced azure-client-authentication with azure-identity
- Review Code Changes:
- Sufficiency: ✅ All required changes present
- Necessity: ✅ All changes necessary
- Functional Behavior: ✅ Preserved - API contracts and business logic unchanged
- Security Controls: ✅ Preserved - authentication pattern updated with equivalent protection
- Verification:
- Command:
mvn clean test-compile -q - JDK: /usr/lib/jvm/java-8-openjdk
- Build tool: /usr/local/maven/bin/mvn
- Result: ✅ Compilation SUCCESS | ⚠️ Tests: 10/12 passed (2 failures deferred to Final Validation)
- Notes: 2 test failures related to auth mock setup
- Deferred Work: Fix 2 test failures in Final Validation step (TestAuthHelper, TestResourceCreation)
- Commit: abc1234 - Step X: Migrate Azure Management Dependencies - Compile: SUCCESS, Tests: 10/12 passed
---
SAMPLE FINAL VALIDATION STEP:
- Step X: Final Validation
- Status: ✅ Completed
- Changes Made:
- Verified no legacy com.microsoft.azure.* dependencies remain
- Resolved 2 TODOs from Step 3
- Fixed 2 test failures (auth mock setup, resource assertion)
- Review Code Changes:
- Sufficiency: ✅ All required changes present
- Necessity: ✅ All changes necessary
- Functional Behavior: ✅ Preserved - all business logic and API contracts maintained
- Security Controls: ✅ Preserved - all authentication, authorization unchanged
- Verification:
- Command:
mvn clean test -q - JDK: /usr/lib/jvm/java-8-openjdk
- Build tool: /usr/local/maven/bin/mvn
- Result: ✅ Compilation SUCCESS | ✅ Tests: 12/12 passed (100% pass rate achieved)
- Deferred Work: None - all TODOs resolved
- Commit: xyz3456 - Step X: Final Validation - Compile: SUCCESS, Tests: 12/12 passed
-->
---
Notes
<!-- Additional context, observations, or lessons learned during execution. Use this section for:
- Unexpected challenges encountered
- Deviation from original plan
- Performance observations
- Recommendations for future upgrades
SAMPLE:
- azure-sdk-bom simplified version management significantly
- Authentication migration required adding jackson-databind for file-based auth
- Modern SDK fluent API method names differ from legacy — migration guide was essential
-->
<!-- This is the upgrade summary generated after successful completion of the Azure SDK migration. It documents the final results, changes made, and lessons learned.
SUMMARY RULES
!!! DON'T REMOVE THIS COMMENT BLOCK BEFORE UPGRADE IS COMPLETE AS IT CONTAINS IMPORTANT INSTRUCTIONS.
Prerequisites (must be met before generating summary)
- All steps in plan.md have ✅ in progress.md
- Final Validation step completed successfully
Success Criteria Verification
- Goal: All legacy Azure SDK dependencies (com.microsoft.azure.) replaced with modern equivalents (com.azure.)
- Compilation: Both main AND test code compile =
mvn clean test-compilesucceeds - Test: 100% pass rate =
mvn clean testsucceeds (or ≥ baseline with documented pre-existing flaky tests)
Content Guidelines
- Upgrade Result: MUST show 100% pass rate or justify EACH failure with exhaustive documentation
- Tech Stack Changes: Table with Dependency | Before | After | Reason
- Commits: List with IDs and messages from each step
- Challenges: Key issues and resolutions encountered
- Limitations: Only genuinely unfixable items where: (1) multiple fix approaches attempted, (2) root cause identified, (3) technically impossible to fix
- Next Steps: Recommendations for post-upgrade actions
Efficiency (IMPORTANT)
- Targeted reads: Use
grepover full file reads; read specific sections from progress.md, not entire files.
-->
Upgrade Summary: <PROJECT_NAME> (<RUN_ID>)
- Completed: <timestamp> <!-- replace with actual completion timestamp -->
- Plan Location:
plan.md - Progress Location:
progress.md
Upgrade Result
<!-- Compare final compile/test results against baseline. MUST show 100% pass rate or justify EACH failure with exhaustive documentation.
SAMPLE:
| Metric | Baseline | Final | Status |
|---|---|---|---|
| Compile | ✅ SUCCESS | ✅ SUCCESS | ✅ |
| Tests | 12/12 passed | 12/12 passed | ✅ |
| JDK | JDK 8 | JDK 8 | ✅ |
| Build Tool | Maven 3.9.6 | Maven 3.9.6 | ✅ |
Upgrade Goals Achieved:
- ✅ All com.microsoft.azure. dependencies replaced with com.azure. equivalents
- ✅ Source code migrated to modern Azure SDK APIs
-->
| Metric | Baseline | Final | Status |
|---|---|---|---|
| Compile | |||
| Tests | |||
| JDK | |||
| Build Tool |
Upgrade Goals Achieved:
Tech Stack Changes
<!-- Table documenting all dependency changes made during the upgrade. Only include dependencies that were actually changed.
SAMPLE:
| Dependency | Before | After | Reason |
|---|---|---|---|
| com.microsoft.azure:azure-mgmt-resources | 1.41.4 | Removed | Replaced by azure-resourcemanager |
| com.azure.resourcemanager:azure-resourcemanager | N/A | (managed by azure-sdk-bom) | Modern replacement |
| com.microsoft.azure:azure-client-authentication | 1.7.14 | Removed | Replaced by azure-identity |
| com.azure:azure-identity | N/A | (managed by azure-sdk-bom) | Modern auth library |
| com.azure:azure-sdk-bom | N/A | 1.3.3 | Centralized version management |
-->
| Dependency | Before | After | Reason |
|---|
Commits
<!-- List all commits made during the upgrade with their short IDs and messages.
SAMPLE:
| Commit | Message |
|---|---|
| abc1234 | Step 1: Setup Baseline - Compile: SUCCESS \ |
| def5678 | Step 2: Migrate Azure Dependencies - Compile: SUCCESS |
| ghi9012 | Step 3: Migrate Source Code - Compile: SUCCESS |
| jkl3456 | Step 4: Final Validation - Compile: SUCCESS \ |
-->
| Commit | Message |
|---|
Challenges
<!-- Document key challenges encountered during the upgrade and how they were resolved.
SAMPLE:
- Authentication Migration
- Issue: Legacy code uses Azure.authenticate(credentialFile) which has no direct equivalent in modern SDK.
- Resolution: Read credential file with Jackson ObjectMapper, construct ClientSecretCredential, use AzureProfile.
- Files Changed: AzureHelper.java, AppConfig.java
- Fluent API Changes
- Issue: Method names differ between legacy Azure.management and modern azure-resourcemanager.
- Resolution: Followed migration guide at https://aka.ms/java-track2-migration-guide
- Files Changed: ResourceProvisioner.java, StorageSetup.java
-->
Limitations
<!-- Document any genuinely unfixable limitations that remain after the upgrade. This section should be empty if all issues were resolved. Only include items where: (1) multiple fix approaches were attempted, (2) root cause is identified, (3) fix is technically impossible without breaking other functionality. -->
Review Code Changes Summary
<!-- Document review code changes results from the upgrade. This section ensures the upgrade is both sufficient (complete) and necessary (no extraneous changes), with original functionality and security controls preserved.
VERIFICATION AREAS: 1. Sufficiency: All required upgrade changes are present — no missing modifications 2. Necessity: All changes are strictly necessary — no unnecessary modifications, including:
- Functional Behavior Consistency: Business logic, API contracts, expected outputs
- Security Controls Preservation (critical subset of behavior):
- Authentication: Login mechanisms, session management, token validation, MFA configurations
- Authorization: Role-based access control, permission checks, access policies, security annotations (@PreAuthorize, @Secured, etc.)
- Password handling: Password encoding/hashing algorithms, password policies, credential storage
- Security configurations: CORS policies, CSRF protection, security headers, SSL/TLS settings, OAuth/OIDC configurations
- Audit logging: Security event logging, access logging
SAMPLE (no issues): Review Status: ✅ All Passed
Sufficiency: ✅ All required upgrade changes are present Necessity: ✅ All changes are strictly necessary
- Functional Behavior: ✅ Preserved — business logic, API contracts unchanged
- Security Controls: ✅ Preserved — authentication, authorization, password handling, security configs, audit logging unchanged
SAMPLE (with behavior changes): Review Status: ⚠️ Changes Documented Below
Sufficiency: ✅ All required upgrade changes are present
Necessity: ⚠️ Behavior changes required by SDK migration (documented below)
- Functional Behavior: ✅ Preserved
- Security Controls: ⚠️ Changes made with equivalent protection
| Area | Change Made | Reason | Equivalent Behavior |
|---|---|---|---|
| Authentication | Azure.authenticate() → ClientSecretCredential | Legacy auth API removed in modern SDK | ✅ Same credentials |
-->
Next Steps
<!-- Recommendations for post-upgrade actions.
SAMPLE:
- [ ] Run full integration test suite in staging environment
- [ ] Performance testing to validate no regression
- [ ] Update CI/CD pipelines if dependency versions changed
- [ ] Update documentation to reflect new Azure SDK versions
- [ ] Review azure-sdk-bom version periodically for updates
-->
Artifacts
- Plan:
.github/java-upgrade/<RUN_ID>/plan.md - Progress:
.github/java-upgrade/<RUN_ID>/progress.md - Summary:
.github/java-upgrade/<RUN_ID>/summary.md(this file) - Branch:
java-upgrade/<RUN_ID>
Phase 1: Precheck
Load this file when executing Phase 1. Refer back to `upgrade-success-criteria` and `upgrade-strategy` for success criteria and strategy, and `../rules/troubleshooting.md` when failures occur.
| Category | Scenario | Action |
|---|---|---|
| Unsupported Project | Not a Maven/Gradle project | STOP with error |
| Unsupported Project | Git not installed or not managed | Log warning, continue without git |
| Invalid Goal | No legacy Azure SDK deps found | STOP — nothing to migrate |
| Java Version | Below JDK 8 | Include Java upgrade as part of the migration plan |
Prerequisites: JDK 8+ and Maven or Gradle must be pre-installed.
Environment detection:
Detect available JDKs: 1. Check JAVA_HOME and JDK_HOME environment variables 2. Run java -version and javac -version to detect the default JDK 3. Search common JDK installation paths (platform-specific: Program Files on Windows, /usr/lib/jvm on Linux, /Library/Java on macOS) 4. Check for version manager installations (SDKMAN, ASDF, jenv, Jabba) 5. For each found JDK, read the release file to determine the version
Report all found JDKs with their path, version, and discovery source.
Detect build tools: 1. Check for Maven Wrapper (mvnw/mvnw.cmd) or Gradle Wrapper (gradlew/gradlew.bat) in the project root — prefer wrappers when present 2. If a wrapper exists, read .mvn/wrapper/maven-wrapper.properties or gradle/wrapper/gradle-wrapper.properties to determine the wrapper-defined version 3. Run mvn --version or gradle --version to detect system installations 4. Check MAVEN_HOME/M2_HOME environment variables
Report all found installations with their path, version, and source.
On success: Create .github/java-upgrade/{RUN_ID}/plan.md from the Plan Template — replace placeholders (<RUN_ID>, <PROJECT_NAME>, <current_branch>, <current_commit_id>, datetime) and follow the HTML-comment instructions to populate each section.
Phase 2: Generate Upgrade Plan
Load this file when executing Phase 2. Refer back to `upgrade-success-criteria` and `upgrade-strategy` for success criteria and strategy, and `../rules/troubleshooting.md` when failures occur.
1. Initialize
1. Update plan.md: replace all remaining placeholders 2. Extract user-specified guidelines from prompt into "Guidelines" section (bulleted list; leave empty if none)
2. Environment Analysis
1. Read HTML comments in "Available Tools" section of plan.md to understand rules and expected format 2. Record discovered JDK versions and paths 3. Detect wrapper presence; if wrapper exists, read wrapper properties to determine build tool version 4. Check build tool version compatibility with JDK — flag incompatible versions for upgrade
3. Dependency Analysis
1. Read HTML comments in "Technology Stack" and "Derived Upgrades" sections of plan.md to understand rules and expected format 2. Identify core tech stack across ALL modules (direct deps + upgrade-critical deps) 3. Include build tool (Maven/Gradle) and build plugins (maven-compiler-plugin, maven-surefire-plugin, etc.) in the technology stack analysis 4. Flag EOL dependencies (high priority for upgrade) 5. Consult the Migration Guidelines for package mappings and migration guides 6. Populate "Technology Stack" and "Derived Upgrades"
4. Upgrade Path Design
1. Read HTML comments in "Key Challenges" and "Upgrade Steps" sections of plan.md to understand rules and expected format 2. For incompatible deps, prefer: Replacement > Adaptation > Rewrite 3. Finalize "Available Tools" section based on the planned step sequence 4. Design step sequence:
- Step 1 (MANDATORY): Setup Baseline — run compile/test with current JDK, document results
- Steps 2-N: Upgrade steps — dependency order, high-risk early, isolated breaking changes. Compilation must pass (both main and test code); test failures documented for Final Validation.
- Final step (MANDATORY): Final Validation — verify all goals met, all TODOs resolved, achieve Upgrade Success Criteria through iterative test & fix loop.
5. Identify high-risk areas for "Key Challenges" section 6. Write steps following format in plan.md
5. Plan Review
1. Verify all placeholders filled in plan.md, check for missing coverage/infeasibility/limitations 2. Revise plan as needed for completeness and feasibility; document unfixable limitations in "Plan Review" section 3. Ensure all sections of plan.md are fully populated (per Template compliance rule) and all HTML comments removed
After plan generation, proceed directly to execution — create .github/java-upgrade/{RUN_ID}/progress.md from the Progress Template, replace placeholders, and begin execution. Log the migration plan, then proceed without pausing for confirmation.
Phase 3: Execute Upgrade Plan
Load this file when executing Phase 3. Refer back to `upgrade-success-criteria` and `upgrade-strategy` for success criteria and strategy, and `../rules/troubleshooting.md` when failures occur.
1. Initialize
1. Read plan.md for step details 2. Update progress.md:
- Replace
<RUN_ID>,<PROJECT_NAME>and timestamp placeholders - Create step entries for each step in
plan.md(per Template compliance rule)
2. Execute
For each step:
1. Read plan.md for step details and guidelines 2. Mark ⏳ in progress.md 3. Make changes as planned (use OpenRewrite if helpful, verify results)
- Add TODOs for any deferred work, e.g., temporary workarounds
4. Review Code Changes (per rules in Progress Template): Verify sufficiency (all required changes present) and necessity (no unnecessary changes, functional behavior preserved, security controls maintained).
- Add missing changes and revert unnecessary changes. Document any unavoidable behavior changes with justification.
5. Verify with specified command/JDK:
- Steps 1-N (Setup/Upgrade): Compilation must pass (including both main and test code, fix immediately if not). Test failures acceptable — document count.
- Final Validation Step: Achieve Upgrade Success Criteria — iterative test & fix loop until 100% pass (or ≥ baseline). NO deferring. See `../rules/troubleshooting.md` when stuck.
- Build:
mvn clean test-compile(or./gradlew compileTestJavafor Gradle) - Test:
mvn clean test(or./gradlew testfor Gradle)
6. Commit on the java-upgrade/{RUN_ID} branch with message format (if git available; otherwise, log details in progress.md):
- First line:
Step <x>: <title> - Compile: <result>orStep <x>: <title> - Compile: <result>, Tests: <pass>/<total> passed(if tests run) - Body: Changes summary + concise known issues/limitations (≤5 lines)
- Security note: If any security-related changes were made, include "Security: <change description and justification>"
7. Update progress.md with step details and mark ✅ or ❗
3. Complete
1. Validate all steps in plan.md have ✅ in progress.md 2. Validate all Upgrade Success Criteria are met, or otherwise go back to Final Validation step to fix
Phase 4: Summarize & Validate
Load this file when executing Phase 4. Refer back to `upgrade-success-criteria` and `upgrade-strategy` for success criteria and strategy, and `../rules/troubleshooting.md` when failures occur.
1. Create .github/java-upgrade/{RUN_ID}/summary.md from the Summary Template — replace placeholders and follow HTML-comment instructions to populate final results. 2. Apply the validation checklist from the Migration Guidelines:
- Migrated project passes compilation
- All tests pass — don't silently skip tests
- No legacy SDK dependencies/references exist
- If
azure-sdk-bomis used, ensure no explicit version dependencies for Azure libraries in the BOM - For each migration guide recorded during migration, fetch and verify the migrated code follows the guide's recommendations. Fix any deviations.
3. Populate summary.md (Upgrade Result, Tech Stack Changes, Commits, Challenges, Limitations, Next Steps) 4. Clean up temp files; remove HTML comments from all .md files 5. Verify all goals met
Assessment: Functions Plan Upgrade
Generate an upgrade assessment report before any changes to Azure resources.
Prerequisites
- User has an existing Azure Functions app on a Consumption or other plan
- User has Azure CLI v2.77.0+ installed
- User has Owner or Contributor role in the target resource group
- The
resource-graphextension is installed (az extension add --name resource-graph)
Assessment Steps
1. Identify Source App — Confirm the function app name, resource group, region, and current hosting plan 2. Check Region Compatibility — Verify the target plan is available in the app's region 3. Verify Language Stack — Confirm the app's runtime is supported on the target plan 4. Verify Stack Version — Confirm the runtime version is supported on the target plan in the region 5. Check Deployment Slots — Determine if slots are in use (Flex Consumption doesn't support slots) 6. Check Certificates — Determine if TLS/SSL certificates are in use (not yet supported in Flex Consumption) 7. Check Blob Triggers — Verify blob triggers use EventGrid source (container polling not supported in Flex Consumption) 8. Assess Dependencies — Review upstream and downstream service dependencies and plan mitigation strategies 9. Generate Report — Create upgrade-assessment-report.md
Assessment Report Format
⚠️ MANDATORY: Use these exact section headings in every assessment report. Do NOT rename, reorder, or omit sections.
The report MUST be saved as upgrade-assessment-report.md in the workspace root.
# Upgrade Assessment Report
## 1. Executive Summary
| Property | Value |
|----------|-------|
| **App Name** | <app-name> |
| **Resource Group** | <resource-group> |
| **Current Plan** | <current-plan (e.g., Consumption / Y1 Dynamic)> |
| **Target Plan** | <target-plan (e.g., Flex Consumption / FC1)> |
| **Region** | <region> |
| **Runtime** | <runtime and version> |
| **OS** | <Linux / Windows> |
| **Upgrade Readiness** | <Ready / Needs Attention / Blocked> |
| **Assessment Date** | <date> |
## 2. Compatibility Checks
| Check | Status | Details |
|-------|--------|---------|
| Region supported | ✅ / ❌ | |
| Language stack supported | ✅ / ❌ | |
| Stack version supported | ✅ / ❌ | |
| No deployment slots | ✅ / ⚠️ | |
| No TLS/SSL certificates | ✅ / ⚠️ | |
| Blob triggers use EventGrid | ✅ / ⚠️ / N/A | |
| .NET isolated (not in-process) | ✅ / ❌ / N/A | |
## 3. App Settings Inventory
| Setting | Value | Migrate? | Notes |
|---------|-------|----------|-------|
| | | Yes / No / Convert | |
## 4. Managed Identities
| Type | Principal ID | Roles | Action |
|------|-------------|-------|--------|
| System-assigned | | | Recreate in new app |
| User-assigned | | | Reassign to new app |
## 5. Application Configurations
| Configuration | Current Value | Migrate? | Notes |
|---------------|---------------|----------|-------|
| CORS settings | | | |
| Custom domains | | | |
| HTTP version | | | |
| HTTPS only | | | |
| TLS version | | | |
| Client certificates | | | |
| Access restrictions | | | |
| Built-in auth | | | |
## 6. Trigger & Binding Analysis
| Function | Trigger Type | Source | Migration Risk | Mitigation |
|----------|-------------|--------|----------------|------------|
| | | | Low / Medium / High | |
## 7. Dependent Services
| Service | Dependency Type | Migration Risk | Mitigation Strategy |
|---------|----------------|----------------|---------------------|
| | Upstream / Downstream | | |
## 8. Blockers & Warnings
### Blockers (must fix before upgrade)
- [ ] <any blocking issues>
### Warnings (should address but not blocking)
- [ ] <any non-blocking concerns>
## 9. Recommendations
1. **Plan**: <recommended target plan>
2. **Auth**: <switch to Managed Identity if using connection strings>
3. **Monitoring**: <Application Insights configuration>
4. **Scaling**: <recommended instance count and concurrency settings>
## 10. Next Steps
- [ ] Review and approve this assessment
- [ ] Address any blockers listed above
- [ ] Proceed to automated upgrade (Phase 3-4)💡 Tip: Use mcp_azure_mcp_get_azure_bestpractices to get the latest recommendations for the target hosting plan.Workflow Details
Upgrade Workflow Phases
The azure-upgrade skill follows a structured workflow to ensure safe, repeatable upgrades.
Phase Overview
┌──────────┐ ┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌──────────┐
│ Identify │───▶│ Assess │───▶│ Pre-migrate │───▶│ Upgrade │───▶│ Validate │
└──────────┘ └──────────┘ └─────────────┘ └─────────┘ └──────────┘Progress Tracking
Create and maintain upgrade-status.md in the workspace root:
# Upgrade Status
## Upgrade Details
| Property | Value |
|----------|-------|
| **Source App** | <app-name> |
| **Source Plan** | <current-plan> |
| **Target Plan** | <target-plan> |
| **Resource Group** | <resource-group> |
| **Region** | <region> |
| **Started** | <date> |
## Phase Status
- [ ] Phase 1: Identify — Determine source/target plans
- [ ] Phase 2: Assess — Check readiness and compatibility
- [ ] Phase 3: Pre-migrate — Collect settings and configurations
- [ ] Phase 4: Upgrade — Execute upgrade automation
- [ ] Phase 5: Validate — Verify new app functionality
## Notes
<any issues, decisions, or observations during upgrade>Error Handling
If any phase fails: 1. Log the error in upgrade-status.md 2. Do NOT proceed to the next phase 3. Inform the user of the failure and suggest remediation 4. Offer to retry the failed phase or rollback
Hand-off
After successful validation:
- Offer to hand off to
azure-validatefor deeper testing - Offer to hand off to
azure-deployfor CI/CD pipeline setup - Ask if the user wants to clean up the original app
Related skills
How it compares
Use azure-upgrade when an existing Azure deployment needs plan, SKU, or SDK migration rather than greenfield provisioning skills.
FAQ
What Azure migrations does azure-upgrade handle?
azure-upgrade handles Consumption-to-Flex-Consumption Functions upgrades, App Service-to-Container-Apps migration, com.microsoft.azure-to-com.azure Java SDK modernization, and Azure Cache for Redis to Azure Managed Redis transitions.
What runtime does azure-upgrade require?
azure-upgrade requires Python 3.10 or newer and ships at version 1.1.3 under the MIT license in the microsoft/azure-skills repository.
Is Azure Upgrade safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.