From 418565e9532e9d126d1267e2e598a7f95b86d40b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 29 Apr 2026 18:25:54 +0000 Subject: [PATCH] Sync plugin files from GitHub-Copilot-for-Azure --- .../azure-skills/.claude-plugin/plugin.json | 2 +- .../azure-skills/.cursor-plugin/plugin.json | 2 +- .github/plugins/azure-skills/.mcp.json | 4 - .../plugins/azure-skills/.plugin/plugin.json | 2 +- .github/plugins/azure-skills/CHANGELOG.md | 8 + .../azure-skills/gemini-extension.json | 4 - .../skills/azure-hosted-copilot-sdk/SKILL.md | 2 +- .../references/copilot-sdk.md | 6 +- .../existing-project-integration.md | 2 +- .../skills/azure-prepare/SKILL.md | 2 +- .../references/recipes/azd/iac-rules.md | 4 +- .../references/recipes/azd/terraform.md | 6 +- .../skills/azure-upgrade/SKILL.md | 15 +- .../references/languages/java/INSTRUCTION.md | 130 +++++ .../references/languages/java/README.md | 35 ++ .../java/bom-migration/bom-gradle-settings.md | 212 ++++++++ .../java/bom-migration/bom-gradle-toml.md | 75 +++ .../java/bom-migration/bom-gradle.md | 128 +++++ .../languages/java/bom-migration/bom-maven.md | 113 ++++ .../java/bom-migration/bom-migration.md | 71 +++ .../java/bom-migration/bom-validation.md | 20 + .../com.microsoft.azure.eventprocessorhost.md | 111 ++++ .../com.microsoft.azure.management.md | 187 +++++++ .../languages/java/rules/efficiency.md | 5 + .../java/rules/execution-guidelines.md | 7 + .../java/rules/review-code-changes.md | 6 + .../languages/java/rules/troubleshooting.md | 26 + .../languages/java/rules/upgrade-strategy.md | 10 + .../java/rules/upgrade-success-criteria.md | 7 + .../languages/java/scripts/upgrade_bom.py | 485 ++++++++++++++++++ .../languages/java/templates/PLAN_TEMPLATE.md | 201 ++++++++ .../java/templates/PROGRESS_TEMPLATE.md | 165 ++++++ .../java/templates/SUMMARY_TEMPLATE.md | 184 +++++++ .../java/workflow/phase-1-precheck.md | 33 ++ .../languages/java/workflow/phase-2-plan.md | 44 ++ .../java/workflow/phase-3-execute.md | 36 ++ .../java/workflow/phase-4-summarize.md | 14 + 37 files changed, 2342 insertions(+), 22 deletions(-) create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/INSTRUCTION.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/README.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-settings.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-toml.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-maven.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-migration.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-validation.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.eventprocessorhost.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.management.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/efficiency.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/execution-guidelines.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/review-code-changes.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/troubleshooting.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-strategy.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-success-criteria.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/scripts/upgrade_bom.py create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PLAN_TEMPLATE.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PROGRESS_TEMPLATE.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/SUMMARY_TEMPLATE.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-1-precheck.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-2-plan.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-3-execute.md create mode 100644 .github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-4-summarize.md diff --git a/.github/plugins/azure-skills/.claude-plugin/plugin.json b/.github/plugins/azure-skills/.claude-plugin/plugin.json index 2c8c5e67..071c4775 100644 --- a/.github/plugins/azure-skills/.claude-plugin/plugin.json +++ b/.github/plugins/azure-skills/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "azure", "description": "Microsoft Azure MCP and Skills integration for cloud resource management, deployments, and Azure services. Manage your Azure infrastructure, monitor applications, and deploy resources directly from Claude Code.", - "version": "1.1.20", + "version": "1.1.22", "author": { "name": "Microsoft", "url": "https://www.microsoft.com" diff --git a/.github/plugins/azure-skills/.cursor-plugin/plugin.json b/.github/plugins/azure-skills/.cursor-plugin/plugin.json index b93557ae..d54f7cb1 100644 --- a/.github/plugins/azure-skills/.cursor-plugin/plugin.json +++ b/.github/plugins/azure-skills/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "azure", "description": "Microsoft Azure MCP and Skills integration for cloud resource management, deployments, and Azure services. Manage your Azure infrastructure, monitor applications, and deploy resources directly from Cursor.", - "version": "1.1.20", + "version": "1.1.22", "author": { "name": "Microsoft", "url": "https://www.microsoft.com" diff --git a/.github/plugins/azure-skills/.mcp.json b/.github/plugins/azure-skills/.mcp.json index b5ae1a6c..90cf4d2d 100644 --- a/.github/plugins/azure-skills/.mcp.json +++ b/.github/plugins/azure-skills/.mcp.json @@ -3,10 +3,6 @@ "azure": { "command": "npx", "args": ["-y", "@azure/mcp@latest", "server", "start"] - }, - "context7": { - "command": "npx", - "args": ["-y", "@upstash/context7-mcp@latest"] } } } diff --git a/.github/plugins/azure-skills/.plugin/plugin.json b/.github/plugins/azure-skills/.plugin/plugin.json index a6d6441f..9359040e 100644 --- a/.github/plugins/azure-skills/.plugin/plugin.json +++ b/.github/plugins/azure-skills/.plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "azure", "description": "Microsoft Azure MCP and Skills integration for cloud resource management, deployments, and Azure services. Manage your Azure infrastructure, monitor applications, and deploy resources directly from your development environment.", - "version": "1.1.20", + "version": "1.1.22", "author": { "name": "Microsoft", "url": "https://www.microsoft.com" diff --git a/.github/plugins/azure-skills/CHANGELOG.md b/.github/plugins/azure-skills/CHANGELOG.md index 43530228..fd2a6761 100644 --- a/.github/plugins/azure-skills/CHANGELOG.md +++ b/.github/plugins/azure-skills/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.1.22 + +- fix: Remove context7 MCP server from plugin config ([#2100](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2100)) + +## 1.1.21 + +- feat: Extend `azure-upgrade` skill by adding workflow for migrating legacy Azure SDKs for Java to latest modern ones ([#1901](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/1901)) + ## 1.1.19 - fix: strengthen azure-resource-lookup routing for web app/website prompts ([#2006](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2006)) diff --git a/.github/plugins/azure-skills/gemini-extension.json b/.github/plugins/azure-skills/gemini-extension.json index 9e4e27cc..6fee5561 100644 --- a/.github/plugins/azure-skills/gemini-extension.json +++ b/.github/plugins/azure-skills/gemini-extension.json @@ -6,10 +6,6 @@ "azure": { "command": "npx", "args": ["-y", "@azure/mcp@latest", "server", "start"] - }, - "context7": { - "command": "npx", - "args": ["-y", "@upstash/context7-mcp@latest"] } } } \ No newline at end of file diff --git a/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/SKILL.md b/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/SKILL.md index 7389b00a..f579bbb6 100644 --- a/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/SKILL.md +++ b/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/SKILL.md @@ -4,7 +4,7 @@ description: "Build, deploy, modify GitHub Copilot SDK apps on Azure. MANDATORY license: MIT metadata: author: Microsoft - version: "1.1.1" + version: "1.1.2" --- # GitHub Copilot SDK on Azure diff --git a/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/copilot-sdk.md b/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/copilot-sdk.md index 10c6c61d..cc90b3df 100644 --- a/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/copilot-sdk.md +++ b/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/copilot-sdk.md @@ -23,13 +23,15 @@ azd init --template azure-samples/copilot-sdk-service ## Getting Current Examples -Use **context7** MCP tools as the PRIMARY way to get SDK documentation and code examples: +Use `github-mcp-server-get_file_contents` with `owner: "github"`, `repo: "copilot-sdk"` to read files directly from the repo and get current SDK documentation and code examples. + +If the **context7** MCP server is available, it can also be used to query SDK docs: 1. Call `context7-resolve-library-id` with `libraryName: "copilot-sdk"` to find the library ID 2. Call `context7-query-docs` with the resolved ID and a query matching the user's goal 3. Select the most relevant snippets for the user's scenario -> πŸ’‘ **Tip:** Fall back to `github-mcp-server-get_file_contents` with `owner: "github"`, `repo: "copilot-sdk"` to read files directly from the repo. +> πŸ’‘ **Tip:** If context7 is not installed, instruct the user to add it. For a quick one-off use: `npx -y @upstash/context7-mcp@latest`. To persist it, add `@upstash/context7-mcp` as an entry in their MCP server configuration file. ## Three Model Paths diff --git a/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/existing-project-integration.md b/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/existing-project-integration.md index 3a48b4d8..4f057f5a 100644 --- a/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/existing-project-integration.md +++ b/.github/plugins/azure-skills/skills/azure-hosted-copilot-sdk/references/existing-project-integration.md @@ -19,7 +19,7 @@ Read the template via MCP for reference implementation: `github-mcp-server-get_file_contents` with `owner: "azure-samples"`, `repo: "copilot-sdk-service"`. Read `AGENTS.md` first. -Use context7 tools (`context7-resolve-library-id` β†’ `context7-query-docs`) for current SDK API examples. +Use `github-mcp-server-get_file_contents` with `owner: "github"`, `repo: "copilot-sdk"` for current SDK API examples. If context7 is available, you can also use it (`context7-resolve-library-id` then `context7-query-docs`). If context7 is not available, instruct the user to install it: `npx -y @upstash/context7-mcp@latest`. ## Integration Steps diff --git a/.github/plugins/azure-skills/skills/azure-prepare/SKILL.md b/.github/plugins/azure-skills/skills/azure-prepare/SKILL.md index af3d3114..9b2c3616 100644 --- a/.github/plugins/azure-skills/skills/azure-prepare/SKILL.md +++ b/.github/plugins/azure-skills/skills/azure-prepare/SKILL.md @@ -4,7 +4,7 @@ description: "Prepare Azure apps for deployment (infra Bicep/Terraform, azure.ya license: MIT metadata: author: Microsoft - version: "1.2.7" + version: "1.2.8" --- # Azure Prepare diff --git a/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/iac-rules.md b/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/iac-rules.md index 9d78fe55..400f19e5 100644 --- a/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/iac-rules.md +++ b/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/iac-rules.md @@ -18,11 +18,11 @@ For **Terraform**: If no pattern module exists for the active provider, default immediately to AVM modules in the same provider order (resource, then utility) instead of using non-AVM modules. -## Retrieval Strategy (Hybrid: azure-documentation MCP + Context7) +## Retrieval Strategy (azure-documentation MCP primary + optional Context7) - **Primary (authoritative):** Use `mcp_azure_mcp_documentation` (`azure-documentation`) for current Azure guidance and AVM integration documentation. - **Primary (module catalog):** Use `mcp_bicep_list_avm_metadata` plus official AVM indexes to select concrete modules. -- **Secondary (supplemental):** Use Context7 only for implementation examples when `mcp_azure_mcp_documentation` does not provide enough detail. +- **Secondary (supplemental):** Use Context7 only for implementation examples when `mcp_azure_mcp_documentation` does not provide enough detail. If Context7 is not available, instruct the user to install it: `npx -y @upstash/context7-mcp@latest`. ## Validation Plan diff --git a/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/terraform.md b/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/terraform.md index 4cd754a0..d4d037b1 100644 --- a/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/terraform.md +++ b/.github/plugins/azure-skills/skills/azure-prepare/references/recipes/azd/terraform.md @@ -322,7 +322,11 @@ For Terraform module selection, enforce this order: 2. AVM Terraform Resource Modules 3. AVM Terraform Utility Modules -Use `mcp_azure_mcp_documentation` (`azure-documentation`) for current guidance and AVM context first, then use Context7 only as supplemental examples if required. +Use `mcp_azure_mcp_documentation` (`azure-documentation`) for current guidance and AVM context first, then use Context7 only as supplemental examples if required. If Context7 is not available, instruct the user to install it: + +```bash +npx @upstash/context7-mcp@latest +``` ## Migration from Pure Terraform diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/SKILL.md b/.github/plugins/azure-skills/skills/azure-upgrade/SKILL.md index d3e285fc..99493211 100644 --- a/.github/plugins/azure-skills/skills/azure-upgrade/SKILL.md +++ b/.github/plugins/azure-skills/skills/azure-upgrade/SKILL.md @@ -1,15 +1,16 @@ --- name: azure-upgrade -description: "Assess and upgrade Azure workloads between plans, tiers, or SKUs within Azure. Generates assessment reports and automates upgrade steps. WHEN: upgrade Consumption to Flex Consumption, upgrade Azure Functions plan, migrate hosting plan, upgrade Functions SKU, move to Flex Consumption, upgrade Azure service tier, change hosting plan, upgrade function app plan, migrate App Service to Container Apps." +description: "Assess and upgrade Azure workloads between plans, tiers, or SKUs, or modernize Azure SDK dependencies in source code. WHEN: upgrade Consumption to Flex Consumption, upgrade Azure Functions plan, migrate hosting plan, change hosting plan, function app SKU, migrate App Service to Container Apps, migrate legacy Azure SDKs for Java, upgrade legacy Azure Java SDK, com.microsoft.azure to com.azure." license: MIT +compatibility: python3.10+ metadata: author: Microsoft - version: "1.1.1" + version: "1.1.2" --- # 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. This is NOT for cross-cloud migration β€” use `azure-cloud-migrate` for that. +> 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.*` β†’ modern `com.azure.*`). This is NOT for cross-cloud migration β€” use `azure-cloud-migrate` for that. ## Triggers @@ -19,6 +20,7 @@ metadata: | 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" | ## Rules @@ -36,6 +38,9 @@ metadata: | Source | Target | Reference | |--------|--------|-----------| | Azure Functions Consumption Plan | Azure Functions Flex Consumption Plan | [consumption-to-flex.md](references/services/functions/consumption-to-flex.md) | +| Legacy Azure Java SDK (`com.microsoft.azure.*`) | Modern Azure Java SDK (`com.azure.*`) | [languages/java/README.md](references/languages/java/README.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? Use `mcp_azure_mcp_documentation` and `mcp_azure_mcp_get_azure_bestpractices` tools to research the upgrade path. @@ -68,6 +73,10 @@ Track progress in `upgrade-status.md` inside the workspace root. - [Consumption to Flex Consumption](references/services/functions/consumption-to-flex.md) - [Assessment](references/services/functions/assessment.md) - [Automation Scripts](references/services/functions/automation.md) +- **Java SDK Migration Templates** + - [Plan Template](references/languages/java/templates/PLAN_TEMPLATE.md) + - [Progress Template](references/languages/java/templates/PROGRESS_TEMPLATE.md) + - [Summary Template](references/languages/java/templates/SUMMARY_TEMPLATE.md) ## Next diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/INSTRUCTION.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/INSTRUCTION.md new file mode 100644 index 00000000..43948ff5 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/INSTRUCTION.md @@ -0,0 +1,130 @@ +# 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:tree` or `gradlew dependencies` to find every `com.microsoft.azure.*` SDK and map each one to its modern counterpart under `com.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: + + ```bash + # 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): + + ```powershell + 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.xml` or `build.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](./bom-migration/bom-migration.md) β€” 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](#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 `.java` file in its original directory; only update `import` statements and type usages inside the file body. For example, if a file lives in `src/main/java/com/microsoft/azure/eventprocessorhosts/Consumer.java` with `package com.microsoft.azure.eventprocessorhosts;`, it must stay in that exact directory and keep that exact package declaration β€” even though the modern SDK uses `com.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.**](./package-specific/com.microsoft.azure.management.md) +- [com.microsoft.azure.eventprocessorhost](./package-specific/com.microsoft.azure.eventprocessorhost.md) + +## 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: + + ```bash + # 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' \) -print + ``` + + PowerShell equivalent (run from repo root): + + ```powershell + # 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 FullName + ``` + + Pay 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](./bom-migration/bom-migration.md) to fix it. +- **Version catalog projects**: Follow the [BOM Validation Checklist](./bom-migration/bom-validation.md) β€” it covers TOML, programmatic `settings.gradle` catalogs, 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.**`](https://aka.ms/java-track2-migration-guide) +- [Migrate to com.azure:azure-messaging-servicebus from com.microsoft.azure:azure-servicebus](https://aka.ms/azsdk/java/migrate/sb) +- [Migrate to azure-messaging-eventhubs from azure-eventhubs and azure-eventhubs-eph](https://aka.ms/azsdk/java/migrate/eh) +- [Migrate to `azure-messaging-eventgrid` from `microsoft-azure-eventgrid`](https://aka.ms/azsdk/java/migrate/eg) +- [Storage Blob Service SDK Migration Guide from 8.x to 12.x](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/storage/azure-storage-blob/migrationGuides/V8_V12.md) +- [Storage Blob Service SDK Migration Guide from 10.x/11.x to 12.x](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/storage/azure-storage-blob/migrationGuides/V10_V12.md) +- [Storage Queue Service SDK Migration Guide from 8.x to 12.x](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/storage/azure-storage-queue/migrationGuides/V8_V12.md) +- [Storage File Share Service SDK Migration Guide from 8.x to 12.x](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/storage/azure-storage-file-share/migrationGuides/V8_V12.md) +- [Migrate to azure-security-keyvault-secrets from azure-keyvault](https://aka.ms/azsdk/java/migrate/kv-secrets) +- [Migrate to azure-security-keyvault-keys from azure-keyvault](https://aka.ms/azsdk/java/migrate/kv-keys) +- [Migrate to azure-security-keyvault-certificates from azure-keyvault](https://aka.ms/azsdk/java/migrate/kv-cert) +- [Migrate to `Azure-Compute-Batch` from `Microsoft-Azure-Batch`](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/batch/azure-compute-batch/MigrationGuide.md) +- [Migrate to `azure-ai-documentintelligence` from `azure-ai-formrecognizer`](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/documentintelligence/azure-ai-documentintelligence/MIGRATION_GUIDE.md) +- [Migrate to `azure-ai-formrecognizer 4.0.0-beta.1 - above` from `azure-ai-formrecognizer 3.1.x - lower`](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/formrecognizer/azure-ai-formrecognizer/migration-guide.md) +- [Migration Guide from Azure OpenAI Java SDK to OpenAI Java SDK](https://raw.githubusercontent.com/Azure/azure-sdk-for-java/main/sdk/openai/azure-ai-openai-stainless/MIGRATION.md) +- [Migrate to azure-monitor-query from azure-loganalytics and azure-applicationinsights-query](https://aka.ms/azsdk/java/migrate/monitorquery) diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/README.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/README.md new file mode 100644 index 00000000..5ffeee15 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/README.md @@ -0,0 +1,35 @@ +# Java Legacy Azure SDK β†’ Modern Azure SDK + +> **Scenario scope**: Upgrade a Maven/Gradle project's Azure SDK dependencies from `com.microsoft.azure.*` (legacy, end-of-support 2023) to `com.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/execution-guidelines.md), [rules/efficiency.md](./rules/efficiency.md). + +1. **Precheck** ([workflow/phase-1-precheck.md](./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](./rules/execution-guidelines.md) (Output directory, Git, Wrapper preference). +2. **Plan** ([workflow/phase-2-plan.md](./workflow/phase-2-plan.md)) β€” Inventory deps and populate `plan.md`. β†’ load `./INSTRUCTION.md` for package mappings. + - Step-wise rules: [rules/upgrade-strategy.md](./rules/upgrade-strategy.md) (Incremental, Risk-first, Successor preference, Necessary/Meaningful steps). +3. **Execute** ([workflow/phase-3-execute.md](./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/review-code-changes.md), [rules/upgrade-strategy.md](./rules/upgrade-strategy.md) (Automation tools, Temporary errors OK), [rules/execution-guidelines.md](./rules/execution-guidelines.md) (Template compliance, Git). +4. **Validate** ([workflow/phase-4-summarize.md](./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](./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 β†’ validate +``` diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-settings.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-settings.md new file mode 100644 index 00000000..67ce81cf --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-settings.md @@ -0,0 +1,212 @@ +# 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](https://github.com/openrewrite/rewrite/issues/4852)). Handle manually. + +## Step 0 β€” Detect programmatic catalog usage + +Look for a `dependencyResolutionManagement` block in `settings.gradle` or `settings.gradle.kts`: + +```groovy +// 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") + } + } +} +``` + +```kotlin +// 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): +```groovy +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.` 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 +// Groovy DSL +dependencyResolutionManagement { + versionCatalogs { + libs { + version("azureSdkBom", "{bom_version}") + library("azure-sdk-bom", "com.azure", "azure-sdk-bom").versionRef("azureSdkBom") + } + } +} +``` + +```kotlin +// 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`): +```groovy +dependencies { + implementation enforcedPlatform(libs.azure.sdk.bom) +} +``` + +Kotlin DSL (`build.gradle.kts`): +```kotlin +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: +```groovy +library("azure-identity", "com.azure", "azure-identity").versionRef("azureIdentity") +``` + +After: +```groovy +library("azure-identity", "com.azure", "azure-identity").withoutVersion() +``` + +For the two-arg module form (the same syntax applies to Kotlin DSL): +```groovy +// 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: +```groovy +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: +```groovy +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): +```groovy +// Before +implementation libs.azure +implementation libs.azure.storage + +// After +implementation libs.azure.resourcemanager +implementation libs.azure.storage.blob +``` + +Or `build.gradle.kts` (Kotlin DSL): +```kotlin +// 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`): +```groovy +// Before +bundle("azureLibs", ["azure", "azure-storage"]) +// After +bundle("azureLibs", ["azure-resourcemanager", "azure-storage-blob", "azure-identity"]) +``` + +Kotlin DSL (`settings.gradle.kts`): +```kotlin +// 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`): +```groovy +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`): +```kotlin +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() + } + } +} +``` + diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-toml.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-toml.md new file mode 100644 index 00000000..15053395 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle-toml.md @@ -0,0 +1,75 @@ +# BOM Migration β€” Gradle TOML Version Catalog (`libs.versions.toml`) + +OpenRewrite does not yet support TOML version catalogs ([openrewrite/rewrite#4400](https://github.com/openrewrite/rewrite/issues/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 alias `azure-sdk-bom` becomes accessor `libs.azure.sdk.bom` (hyphensβ†’dots). CamelCase `azureSdkBom` becomes `libs.azureSdkBom`. Match the project's existing convention. + +## Step 1 β€” Add or upgrade the BOM + +In `gradle/libs.versions.toml`: +```toml +[versions] +azureSdkBom = "{bom_version}" + +[libraries] +azure-sdk-bom = { group = "com.azure", name = "azure-sdk-bom", version.ref = "azureSdkBom" } +``` + +In `build.gradle` (Groovy DSL): +```groovy +implementation enforcedPlatform(libs.azure.sdk.bom) +``` + +In `build.gradle.kts` (Kotlin DSL): +```kotlin +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. + +```toml +# 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]`. + +```toml +# 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: +```toml +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" } } +``` diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle.md new file mode 100644 index 00000000..d792b2b3 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-gradle.md @@ -0,0 +1,128 @@ +# BOM Migration β€” Gradle Projects (No Version Catalogs) + +> **Python availability**: The script below requires Python 3.8+. If `python3 --version` (or `python --version`) fails, skip the script section and follow [Manual Fallback (no Python)](#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**: + +```bash +# Path is relative to the skill directory (plugin/skills/azure-upgrade/) +python3 ./references/languages/java/scripts/upgrade_bom.py +``` + +Options: +- `--gradle ` β€” override the Gradle command (default: auto-detects `gradlew` or `gradle`). + +Under the hood (OpenRewrite recipes): +- **Add BOM**: `AddPlatformDependency` ([docs](https://docs.openrewrite.org/recipes/gradle/addplatformdependency)) +- **Upgrade BOM**: `UpgradeDependencyVersion` ([docs](https://docs.openrewrite.org/recipes/gradle/upgradedependencyversion)) +- **Remove redundant versions**: `RemoveRedundantDependencyVersions` ([docs](https://docs.openrewrite.org/recipes/gradle/removeredundantdependencyversions)) + +> ⚠️ **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](./bom-gradle-toml.md) or [programmatic catalog steps](./bom-gradle-settings.md) instead. + +## Expected build.gradle after migration + +Groovy DSL (`build.gradle`): +```groovy +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`): +```kotlin +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: +```groovy +dependencies { + implementation enforcedPlatform("com.azure:azure-sdk-bom:{bom_version}") + // ...other dependencies... +} +``` + +Kotlin DSL: +```kotlin +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 `dependencies` block. +- 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: +```groovy +// Before +implementation "com.azure:azure-identity:1.13.0" +// After +implementation "com.azure:azure-identity" +``` + +Groovy DSL β€” map notation: +```groovy +// Before +implementation group: "com.azure", name: "azure-identity", version: "1.13.0" +// After +implementation group: "com.azure", name: "azure-identity" +``` + +Kotlin DSL: +```kotlin +// 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 +# bash / macOS / Linux +./gradlew dependencies --configuration runtimeClasspath +``` + +```powershell +# PowerShell on Windows +.\gradlew.bat dependencies --configuration runtimeClasspath +``` + +Then 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-validation.md). diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-maven.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-maven.md new file mode 100644 index 00000000..b5bf8fa4 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-maven.md @@ -0,0 +1,113 @@ +# BOM Migration β€” Maven Projects + +> **Python availability**: The script below requires Python 3.8+. If `python3 --version` (or `python --version`) fails, skip the script section and follow [Manual Fallback (no Python)](#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 `` tags from individual Azure dependencies that are now managed by the BOM. + +The following invocation works identically in **bash** and **PowerShell**: + +```bash +# Path is relative to the skill directory (plugin/skills/azure-upgrade/) +python3 ./references/languages/java/scripts/upgrade_bom.py +``` + +Options: +- `--mvn ` β€” override the Maven command (default: auto-detects `mvnw` or `mvn`). + +Under the hood (OpenRewrite recipes): +- **Add BOM**: `AddManagedDependency` ([docs](https://docs.openrewrite.org/recipes/maven/addmanageddependency)) +- **Upgrade BOM**: `UpgradeDependencyVersion` ([docs](https://docs.openrewrite.org/recipes/maven/upgradedependencyversion)) +- **Remove redundant versions**: `RemoveRedundantDependencyVersions` ([docs](https://docs.openrewrite.org/recipes/maven/removeredundantdependencyversions)) + +## Expected pom.xml after migration + +```xml + + + + com.azure + azure-sdk-bom + {bom_version} + pom + import + + + + + + + com.azure + azure-identity + + + com.azure.resourcemanager + azure-resourcemanager + + +``` + +## 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 `` block (create it inside `` if absent). Add or update the BOM entry: + +```xml + + + + com.azure + azure-sdk-bom + {bom_version} + pom + import + + + + +``` + +- **If the entry exists**: update only the `` value to `{bom_version}`. +- **If the entry is missing**: insert the full `` block above. Preserve any other existing managed dependencies. +- **Multi-module project**: add the BOM in the parent (aggregator) `pom.xml` only. Child modules inherit it. + +### Step 2 β€” Remove redundant explicit versions + +For every `` whose `` 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 `` element entirely. +- Leave ``, ``, ``, ``, ``, etc. unchanged. + +Before: +```xml + + com.azure + azure-identity + 1.13.0 + +``` + +After: +```xml + + com.azure + azure-identity + +``` + +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}:import` appears 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-validation.md). diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-migration.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-migration.md new file mode 100644 index 00000000..41e03b5b --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-migration.md @@ -0,0 +1,71 @@ +# 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): + +```bash +python3 --version || python --version +``` + +For Windows PowerShell 5.1, use: + +```powershell +python3 --version; if ($LASTEXITCODE -ne 0) { python --version } +``` + +- **Python available** β†’ use the script as documented in [bom-maven.md](./bom-maven.md) / [bom-gradle.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-toml.md), [bom-gradle-settings.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): + +```bash +# 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-version +``` + +If 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 `` 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}.pom` +> and look for `` entries. + +## Build-System Guides + +| Build system | Guide | +|---|---| +| Maven | [bom-maven.md](./bom-maven.md) | +| Gradle (no version catalog) | [bom-gradle.md](./bom-gradle.md) | +| Gradle + TOML version catalog | [bom-gradle-toml.md](./bom-gradle-toml.md) | +| Gradle + programmatic catalog | [bom-gradle-settings.md](./bom-gradle-settings.md) | + +## Validation + +See the [Validation Checklist](./bom-validation.md) β€” covers all build systems including TOML and programmatic `settings.gradle` catalogs. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-validation.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-validation.md new file mode 100644 index 00000000..034b8dee --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/bom-migration/bom-validation.md @@ -0,0 +1,20 @@ +# 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 `` tag, no version string, no `version.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.gradle` uses `libs.` 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 one `library` or `plugin` entry). +- [ ] `bundle(...)` aliases match current `library(...)` aliases (no stale references). +- [ ] `build.gradle` uses `libs.` references β€” no raw `"group:artifact:version"` strings for Azure libraries. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.eventprocessorhost.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.eventprocessorhost.md new file mode 100644 index 00000000..e8e47c7c --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.eventprocessorhost.md @@ -0,0 +1,111 @@ +# com.microsoft.azure.eventprocessorhost + +## Hard Rules (MUST follow) + +- **MUST** replace any legacy `InMemoryCheckpointManager` / `InMemoryLeaseManager` and any `EventProcessorHost` checkpoint/lease usage with `BlobCheckpointStore` backed by Azure Blob Storage. This is the **only** acceptable replacement. +- **MUST NOT** create a class named `InMemoryCheckpointStore`, copy/inline `SampleCheckpointStore`, or implement any custom in-memory `CheckpointStore`. The modern SDK intentionally omits an in-memory implementation due to production issues. +- **MUST NOT** introduce any other custom `CheckpointStore` implementation as part of this migration. If the legacy code stored checkpoints in memory, switch to `BlobCheckpointStore` β€” do not preserve the in-memory semantics. +- If the user explicitly asks for an in-memory implementation, refuse and direct them to the upstream `SampleCheckpointStore` reference instead of generating one. + +> ⚠️ **Important:** The switch from `InMemoryCheckpointManager`/`InMemoryLeaseManager` to `BlobCheckpointStore` is 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 with `BlobCheckpointStore` and complete the migration. + +## Code Samples + +### EventProcessorHost with InMemoryCheckpointManager / InMemoryLeaseManager + +Replace usage of `InMemoryCheckpointManager` / `InMemoryLeaseManager` with [BlobCheckpointStore](https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java). The modern EventProcessorClient does **not** ship an in-memory checkpoint store, and you must not create one. + +Legacy code: +```java +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: +```java +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 dependency `com.azure:azure-messaging-eventhubs-checkpointstore-blob` to the project when using `BlobCheckpointStore`. + +### EventProcessorHost with Azure Storage checkpoint/lease + +Legacy code using the built-in storage-backed checkpoint/lease: +```java +EventProcessorHost host = EventProcessorHost.EventProcessorHostBuilder + .newBuilder(hostName, consumerGroupName) + .useAzureStorageCheckpointLeaseManager(storageConnectionString, storageContainerName, null) + .useEventHubConnectionString(eventHubConnectionString, eventHubName) + .build(); +host.registerEventProcessor(MyEventProcessor.class).get(); +``` + +Migrated code: +```java +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 + +```java +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` | diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.management.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.management.md new file mode 100644 index 00000000..e86f2a24 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/package-specific/com.microsoft.azure.management.md @@ -0,0 +1,187 @@ +# 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` should not be replaced by a direct `.create()` call. Similarly, when provisioning a resource, do not swap `.withNewDependencyResource` for `.withExistingDependencyResource` unless 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()` with `resource.regionName()`; doing so changes the type from `Region` to `String` and 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. + +```java +// 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: + +```java +// 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: +```java +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): +```java +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): +```java +BatchManager batchManager = BatchManager.configure() + .withLogLevel(LogLevel.BASIC) + .withInterceptor(new ProviderRegistrationInterceptor(credentials)) + .authenticate(credentials, subscriptionId); +``` +should be migrated to: +```java +BatchManager batchManager = BatchManager.configure() + .withPolicy(new ProviderRegistrationPolicy()) + .withLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BASIC)) + .authenticate(credential, profile); +``` + +2. Legacy client(premium clients): +```java +Azure azure = Azure.configure() + .withInterceptor(new ProviderRegistrationInterceptor(credentials)) + .withLogLevel(LogLevel.BASIC) + .authenticate(credentials) + .withSubscription(subscriptionId); +``` +should be migrated to: +```java +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: +```java +BatchAccount batchAccount = azure.batchAccounts().define(batchAccountName) + .withRegion(region) + .withNewResourceGroup(rgName) + .defineNewApplication(applicationName) + .defineNewApplicationPackage(applicationPackageName) + .withAllowUpdates(true) + .withDisplayName(applicationDisplayName) + .attach() + .withNewStorageAccount(storageAccountName) + .create(); +``` + +Migrated: +```java +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(); +``` diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/efficiency.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/efficiency.md new file mode 100644 index 00000000..8e522ff1 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/efficiency.md @@ -0,0 +1,5 @@ +# Efficiency + +- **Targeted reads**: Use `grep` over full file reads; read sections, not entire files. +- **Quiet commands**: Use `-q`, `--quiet` for build/test when appropriate. +- **Progressive writes**: Update `plan.md` and `progress.md` incrementally, not at end. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/execution-guidelines.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/execution-guidelines.md new file mode 100644 index 00000000..eac7c9f1 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/execution-guidelines.md @@ -0,0 +1,7 @@ +# 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. Use `N/A` for `` and `` placeholders. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/review-code-changes.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/review-code-changes.md new file mode 100644 index 00000000..2fa42397 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/review-code-changes.md @@ -0,0 +1,6 @@ +# 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. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/troubleshooting.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/troubleshooting.md new file mode 100644 index 00000000..35cbfc06 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/troubleshooting.md @@ -0,0 +1,26 @@ +# 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. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-strategy.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-strategy.md new file mode 100644 index 00000000..6a6fa9fb --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-strategy.md @@ -0,0 +1,10 @@ +# 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`](../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-migration/bom-maven.md) / [bom-gradle.md](../bom-migration/bom-gradle.md) instead (see [Migration Guidelines](../INSTRUCTION.md#maven-use-the-upgrade_bom-script)). +- **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. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-success-criteria.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-success-criteria.md new file mode 100644 index 00000000..8d8b67df --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/rules/upgrade-success-criteria.md @@ -0,0 +1,7 @@ +# 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 test` succeeds. 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`](./troubleshooting.md) at that point β€” do NOT stop or defer. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/scripts/upgrade_bom.py b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/scripts/upgrade_bom.py new file mode 100644 index 00000000..47802ec1 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/scripts/upgrade_bom.py @@ -0,0 +1,485 @@ +#!/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 [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 Maven command override. + --gradle 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 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()) diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PLAN_TEMPLATE.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PLAN_TEMPLATE.md new file mode 100644 index 00000000..69c09561 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PLAN_TEMPLATE.md @@ -0,0 +1,201 @@ + + +# Upgrade Plan: () + +- **Generated**: +- **HEAD Branch**: +- **HEAD Commit ID**: + +## Available Tools + + + +## Guidelines + + + +> Note: You can add any specific guidelines or constraints for the upgrade process here if needed, bullet points are preferred. + +## Upgrade Goals + + + +### Technology Stack + + + +| Technology/Dependency | Current | Modern Equivalent | Migration Notes | +| --------------------- | ------- | ----------------- | --------------- | + +### Derived Upgrades + + + +## Upgrade Steps + + + +## Key Challenges + + diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PROGRESS_TEMPLATE.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PROGRESS_TEMPLATE.md new file mode 100644 index 00000000..434ad486 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/PROGRESS_TEMPLATE.md @@ -0,0 +1,165 @@ + + +# Upgrade Progress: () + +- **Started**: +- **Plan Location**: `.github/java-upgrade//plan.md` +- **Total Steps**: + +## Step Details + + + +--- + +## Notes + + diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/SUMMARY_TEMPLATE.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/SUMMARY_TEMPLATE.md new file mode 100644 index 00000000..f58226be --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/templates/SUMMARY_TEMPLATE.md @@ -0,0 +1,184 @@ + + +# Upgrade Summary: () + +- **Completed**: +- **Plan Location**: `plan.md` +- **Progress Location**: `progress.md` + +## Upgrade Result + + + +| Metric | Baseline | Final | Status | +| ---------- | -------- | ----- | ------ | +| Compile | | | | +| Tests | | | | +| JDK | | | | +| Build Tool | | | | + +**Upgrade Goals Achieved**: + +## Tech Stack Changes + + + +| Dependency | Before | After | Reason | +| ---------- | ------ | ----- | ------ | + +## Commits + + + +| Commit | Message | +| ------ | ------- | + +## Challenges + + + +## Limitations + + + +## Review Code Changes Summary + + + +## Next Steps + + + +## Artifacts + +- **Plan**: `.github/java-upgrade//plan.md` +- **Progress**: `.github/java-upgrade//progress.md` +- **Summary**: `.github/java-upgrade//summary.md` (this file) +- **Branch**: `java-upgrade/` diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-1-precheck.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-1-precheck.md new file mode 100644 index 00000000..428a0f45 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-1-precheck.md @@ -0,0 +1,33 @@ +# Phase 1: Precheck + +Load this file when executing Phase 1. Refer back to [`upgrade-success-criteria`](../rules/upgrade-success-criteria.md) and [`upgrade-strategy`](../rules/upgrade-strategy.md) for success criteria and strategy, and [`../rules/troubleshooting.md`](../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 (``, ``, ``, ``, datetime) and follow the HTML-comment instructions to populate each section. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-2-plan.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-2-plan.md new file mode 100644 index 00000000..42b1fef0 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-2-plan.md @@ -0,0 +1,44 @@ +# Phase 2: Generate Upgrade Plan + +Load this file when executing Phase 2. Refer back to [`upgrade-success-criteria`](../rules/upgrade-success-criteria.md) and [`upgrade-strategy`](../rules/upgrade-strategy.md) for success criteria and strategy, and [`../rules/troubleshooting.md`](../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. diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-3-execute.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-3-execute.md new file mode 100644 index 00000000..060eccbf --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-3-execute.md @@ -0,0 +1,36 @@ +# Phase 3: Execute Upgrade Plan + +Load this file when executing Phase 3. Refer back to [`upgrade-success-criteria`](../rules/upgrade-success-criteria.md) and [`upgrade-strategy`](../rules/upgrade-strategy.md) for success criteria and strategy, and [`../rules/troubleshooting.md`](../rules/troubleshooting.md) when failures occur. + +## 1. Initialize + +1. Read `plan.md` for step details +2. Update `progress.md`: + - Replace ``, `` 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`](../rules/troubleshooting.md) when stuck. + - Build: `mvn clean test-compile` (or `./gradlew compileTestJava` for Gradle) + - Test: `mvn clean test` (or `./gradlew test` for 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 : - Compile: <result>` or `Step <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 diff --git a/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-4-summarize.md b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-4-summarize.md new file mode 100644 index 00000000..69b54994 --- /dev/null +++ b/.github/plugins/azure-skills/skills/azure-upgrade/references/languages/java/workflow/phase-4-summarize.md @@ -0,0 +1,14 @@ +# Phase 4: Summarize & Validate + +Load this file when executing Phase 4. Refer back to [`upgrade-success-criteria`](../rules/upgrade-success-criteria.md) and [`upgrade-strategy`](../rules/upgrade-strategy.md) for success criteria and strategy, and [`../rules/troubleshooting.md`](../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-bom` is 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