Azure Upgrade
MicrosoftOfficialCreated by Microsoft
- Skill
- Workflow
- Cloud and DevOps
- MIT
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Azure Upgrade provides a structured, automated approach to upgrading Azure resources and modernizing source code dependencies. It supports complex transitions such as moving Azure Functions from Consumption to Flex Consumption, migrating various Redis cache tiers to Azure Managed Redis, and refactoring legacy Java applications from the deprecated com.microsoft.azure SDKs to the modern com.azure ecosystem. The skill enforces safety through pre-migration assessments, explicit user confirmation for destructive actions, and idempotent automation scripts, ensuring that original workloads remain intact until the new configuration is fully validated.
What it does
- Assesses Azure workloads for upgrade readiness across plans, tiers, and SKUs.
- Automates the migration of Azure Functions from Consumption to Flex Consumption.
- Modernizes legacy Java applications by replacing deprecated com.microsoft.azure SDKs with modern com.azure equivalents.
- Facilitates the migration of Azure Cache for Redis (ACR/ACRE) to Azure Managed Redis (AMR).
- Generates detailed migration status reports and maintains artifact isolation.
- Provides a safe, gated workflow requiring user approval for all resource creation and configuration changes.
When to use it
- When you need to upgrade your Azure Functions hosting plan to a more performant or cost-effective tier.
- When your Java project relies on deprecated Azure SDKs and requires modernization to supported libraries.
- When migrating existing Redis cache instances to the newer Azure Managed Redis service.
- When you need a repeatable, documented process for changing Azure resource SKUs or hosting plans.
Advantages
- Reduces manual effort and risk during complex infrastructure and code migrations.
- Ensures safety by requiring explicit user approval for all destructive or state-changing operations.
- Maintains high availability by keeping original resources running until the new ones are validated.
- Promotes security best practices by encouraging the use of managed identities over connection strings.
- Provides clear, step-by-step guidance for both infrastructure upgrades and source-code refactoring.
Usage examples
- “Upgrade my function app from Consumption to Flex Consumption”
- The agent will identify the current plan, assess compatibility, and guide you through the migration steps to the Flex Consumption plan.
- “Migrate my Java project from com.microsoft.azure to com.azure”
- The agent will inventory legacy dependencies, provide a migration plan, and assist in updating your build files and source code imports.
- “Migrate my Redis cache to AMR”
- The agent will assess your current Redis configuration and execute the migration path to Azure Managed Redis.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/microsoft/azure-upgrade/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip azure-upgrade.zip -d .agents/skills
Documentation by Microsoft
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 Java
com.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" |
| Discover Functions upgrade candidates | "What Consumption Function Apps do I have that can be upgraded 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
Follow phases in order. Skip or defer work only when the selected scenario explicitly permits it, and record the reason in the migration status.
Generate an assessment before any upgrade operations
Load the scenario reference and follow its rules
Use
mcp_azure_mcp_get_azure_bestpracticesandmcp_azure_mcp_documentationMCP toolsDestructive actions require
ask_user— global-rulesAlways confirm the target plan/SKU with the user before proceeding
Propose a name for any new resource (default:
<source>-<target-suffix>, e.g.<source>-flexfor Flex Consumption migrations) and announce the proposed name to the user before creating it so they can override without a blocking prompt. Same pattern applies to other newly-created resources (storage accounts, App Insights, etc.) — see the scenario reference for service-specific defaults.Windows Consumption → Flex source-change gate: treat the source app as read-only by default. Immediately before every command that would change its settings, triggers, state, deployment, bindings, or existence, use
ask_userto describe the exact change and obtain explicit approval. Approval is action-specific and cannot be reused for later source changes.Never delete or stop the original app without explicit user confirmation
Keep approval-gated workflows moving: after each completed step, immediately perform the next read-only preflight. If the next action requires approval, invoke
ask_userin the same turn — never stop after merely announcing the next step and wait for the user to re-engage.All automation scripts must be idempotent and resumable
Upgrade Scenarios
| Source | Target | Reference |
|---|---|---|
| Azure Functions Consumption Plan (Linux) | Azure Functions Flex Consumption Plan | workflow.md |
| Azure Functions Consumption Plan (Windows) | Azure Functions Flex Consumption Plan | workflow.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 |
Functions Consumption-to-Flex routing: For a named app, inspect its Azure platform and load only the matching Linux or Windows workflow. For subscription-wide discovery, evaluate both platforms: use
az functionapp flex-migration listfor Linux and the Windows workflow's manual discovery and compatibility checks for Windows. Label Windows results as candidates until per-app code compatibility is assessed.
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? Use
mcp_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
Identify — Determine the source and target Azure plans/SKUs. Ask user to confirm.
Assess — Analyze existing app for upgrade readiness → load scenario reference (e.g., workflow.md)
Pre-migrate — Collect settings, identities, configs from the existing app
Upgrade — Execute the automated upgrade steps (create new resources, migrate settings, deploy code)
Validate — Use the checks defined by the selected scenario: verify target resource state, applicable HTTP endpoints and non-HTTP triggers, and monitoring. If access restrictions or unavailable test resources prevent execution, record validation as deferred — never relax security automatically or report functional success.
Ask User — Offer performance validation and IaC updates. Offer source cleanup only when the selected scenario confirms production cutover and all cleanup prerequisites are complete.
Hand off to
azure-validatefor deep validation orazure-deployfor CI/CD setup
Track progress in <UPGRADE_DIR>/upgrade-status.md — see Artifact Output Policy for path resolution.
References
Functions
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
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
Files
- ATTRIBUTION.mdAdded by AutoGineer971 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md8.7 KiB
- references/global-rules.md4.5 KiB
- references/languages/java/INSTRUCTION.md11.3 KiB
- references/languages/java/README.md3.0 KiB
- references/languages/java/bom-migration/bom-gradle-settings.md6.7 KiB
- references/languages/java/bom-migration/bom-gradle-toml.md2.7 KiB
- references/languages/java/bom-migration/bom-gradle.md5.1 KiB
- references/languages/java/bom-migration/bom-maven.md4.7 KiB
- references/languages/java/bom-migration/bom-migration.md4.2 KiB
- references/languages/java/bom-migration/bom-validation.md1.5 KiB
- references/languages/java/package-specific/com.microsoft.azure.eventprocessorhost.md5.5 KiB
- references/languages/java/package-specific/com.microsoft.azure.management.md9.5 KiB
- references/languages/java/rules/efficiency.md265 B
- references/languages/java/rules/execution-guidelines.md1.0 KiB
- references/languages/java/rules/review-code-changes.md541 B
- references/languages/java/rules/troubleshooting.md2.5 KiB
- references/languages/java/rules/upgrade-strategy.md1.4 KiB
- references/languages/java/rules/upgrade-success-criteria.md686 B
- references/languages/java/scripts/upgrade_bom.pyScript19.6 KiB
- references/languages/java/templates/PLAN_TEMPLATE.md9.4 KiB
- references/languages/java/templates/PROGRESS_TEMPLATE.md9.1 KiB
- references/languages/java/templates/SUMMARY_TEMPLATE.md8.6 KiB
- references/languages/java/workflow/phase-1-precheck.md2.3 KiB
- references/languages/java/workflow/phase-2-plan.md2.9 KiB
- references/languages/java/workflow/phase-3-execute.md2.4 KiB
- references/languages/java/workflow/phase-4-summarize.md1.1 KiB
- references/services/functions/consumption-to-flex/linux/assessment.md4.6 KiB
- references/services/functions/consumption-to-flex/linux/automation.md17.3 KiB
- references/services/functions/consumption-to-flex/linux/workflow.md11.6 KiB
- references/services/functions/consumption-to-flex/windows/assessment.md6.8 KiB
- references/services/functions/consumption-to-flex/windows/automation.md4.1 KiB
- references/services/functions/consumption-to-flex/windows/automation/access-key-copy.md2.5 KiB
- references/services/functions/consumption-to-flex/windows/automation/access-key-strategy.md2.1 KiB
- references/services/functions/consumption-to-flex/windows/automation/app-creation.md16.6 KiB
- references/services/functions/consumption-to-flex/windows/automation/app-settings.md12.0 KiB
- references/services/functions/consumption-to-flex/windows/automation/built-in-authentication.md3.3 KiB
- references/services/functions/consumption-to-flex/windows/automation/cleanup-and-rollback.md3.2 KiB
- references/services/functions/consumption-to-flex/windows/automation/code-deployment.md8.6 KiB
- references/services/functions/consumption-to-flex/windows/automation/configuration-inventory.md7.2 KiB
- references/services/functions/consumption-to-flex/windows/automation/deployment-package.md6.0 KiB
- references/services/functions/consumption-to-flex/windows/automation/discovery-and-assessment.md9.1 KiB
- references/services/functions/consumption-to-flex/windows/automation/networking-and-storage.md3.9 KiB
- references/services/functions/consumption-to-flex/windows/automation/site-and-identity.md5.0 KiB
- references/services/functions/consumption-to-flex/windows/automation/trigger-safety-and-monitoring.md11.8 KiB
- references/services/functions/consumption-to-flex/windows/automation/validation-and-cutover.md9.7 KiB
- references/services/functions/consumption-to-flex/windows/dependency-scan.md13.3 KiB
- references/services/functions/consumption-to-flex/windows/progress-tracking.md5.2 KiB
- references/services/functions/consumption-to-flex/windows/workflow.md27.9 KiB
- references/services/redis/redis-to-amr.md7.5 KiB
- references/workflow-details.md2.1 KiB
references/languages/java/scripts/upgrade_bom.py
#!/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> [latest] [options]
python3 upgrade_bom.py --get-latest-version
Arguments:
project_dir Path to the project root (must contain pom.xml or build.gradle).
latest Optional compatibility token. Explicit version pins are rejected.
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"}
MIN_BOM_VERSION = "1.3.0"
LATEST_VERSION_SENTINEL = "latest"
HTTP_TIMEOUT_SECONDS = 30
STABLE_SEMVER_RE = re.compile(r"^(\d+)\.(\d+)\.(\d+)$")
# 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, timeout=HTTP_TIMEOUT_SECONDS) 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()
def _parse_stable_semver(version: str) -> tuple[int, int, int]:
match = STABLE_SEMVER_RE.fullmatch(version.strip())
if not match:
raise ValueError(
f"Invalid azure-sdk-bom version '{version}'. Expected stable MAJOR.MINOR.PATCH."
)
return tuple(int(part) for part in match.groups())
def _validate_minimum_bom_version(version: str) -> None:
parsed = _parse_stable_semver(version)
minimum = _parse_stable_semver(MIN_BOM_VERSION)
if parsed < minimum:
raise ValueError(
f"azure-sdk-bom {version} is below the minimum supported version "
f"{MIN_BOM_VERSION}; resolve the latest stable version from {BOM_POM_URL}."
)
def _resolve_latest_bom_version(requested_version: str | None) -> str:
if requested_version and requested_version.strip().lower() != LATEST_VERSION_SENTINEL:
raise ValueError(
"Explicit azure-sdk-bom version pins are not allowed in this migration flow. "
f"Use no version argument, or use '{LATEST_VERSION_SENTINEL}' for compatibility."
)
latest = _get_latest_bom_version()
_validate_minimum_bom_version(latest)
print(f"[upgrade_bom] Resolved latest azure-sdk-bom version: {latest}")
print(f"[upgrade_bom] Source: {BOM_POM_URL}")
return latest
# ---------------------------------------------------------------------------
# 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="Optional compatibility token. Only 'latest' is accepted; explicit versions are rejected.",
)
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:
parser.error("project_dir is required unless --get-latest-version is used.")
try:
bom_version = _resolve_latest_bom_version(args.bom_version)
except ValueError as exc:
raise SystemExit(f"[upgrade_bom] ERROR: {exc}") from exc
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, bom_version, args.mvn)
elif build_system == "gradle":
print("[upgrade_bom] Detected Gradle project.")
return _handle_gradle(project_dir, 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())
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python
The author says: python3.10+
Security
What our scanner noticed· Low risk
- Instructions that use the network
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Microsoft
- Publisher
- Microsoft (Official)
- Source
- microsoft/skills · .github/plugins/azure-skills/skills/azure-upgrade · commit 0696600
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from .github/plugins/azure-skills/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- microsoft/azure-skills
AutoGineer is not affiliated with or endorsed by Microsoft.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download azure-upgrade.zip