Skip to content

feat(aem-65-lts): add Java 21 code migration skill with custom OpenRewrite recipes#169

Draft
abhishekgarg18 wants to merge 1 commit into
mainfrom
feat/aem65lts-code-migration-skill
Draft

feat(aem-65-lts): add Java 21 code migration skill with custom OpenRewrite recipes#169
abhishekgarg18 wants to merge 1 commit into
mainfrom
feat/aem65lts-code-migration-skill

Conversation

@abhishekgarg18

Copy link
Copy Markdown
Member

Summary

Adds a new java21-migration skill (beta) to the aem-6-5-lts plugin that automates upgrading AEM 6.5 Maven projects to AEM 6.5 LTS on Java 21.

The skill is designed around determinism — every code/POM transformation is implemented as an AST-based OpenRewrite recipe (Java visitor or declarative YAML), not text substitution. This minimises LLM hallucination during agent-driven migrations and gives reviewers a predictable, replayable diff.

What's inside

Two Maven modules under plugins/aem/6.5-lts/skills/java21-migration/:

  • aem65lts-migration-recipes/ — Four custom OpenRewrite recipes implemented as Java visitors with full unit-test coverage (17 tests, all passing).
  • aem65lts-migration-cli/ — A picocli CLI (aem-migrate) that wraps rewrite-maven-plugin invocations into a single full-migrate pipeline plus discrete upgrade-* subcommands.

Bundled declarative YAML recipes compose the custom recipes with the official rewrite-migrate-java and rewrite-testing-frameworks recipe modules.

Custom recipes

Recipe Purpose
ChangeFilevaultEmbeddedArtifact Updates embedded artefact coordinates inside filevault-package-maven-plugin (handles Groovy Console groupId migration)
RemoveBndPluginInstruction Removes SCRDescriptorBndPlugin and similar legacy BND instructions incompatible with bnd 6.x / Java 21
RevertJakartaInAemSource Safeguard recipe — reverts accidental jakarta.* imports back to javax.* in AEM source files (jakarta annotations compile but fail silently at runtime on AEM 6.5 LTS)
DetectUnsupportedPackages Read-only scanner that marks BLOCKER and WARNING imports for the analyze command

CLI commands

Command What it does
analyze Pre-migration scan for blockers and warnings; exit codes 0=ready, 1=warnings, 2=blockers
upgrade-code Java 8/11 → 21 source migration. Cherry-picks recipes from rewrite-migrate-java and explicitly excludes javaxjakarta migration
upgrade-tests Mockito 1.x → 5.x progressive migration via rewrite-testing-frameworks
upgrade-uberjar UberJar bump to 6.6.0 with apis classifier
upgrade-plugins maven-bundle-plugin 5.1.9, bnd-maven-plugin 6.4.0, maven-scr-plugin 1.26.4 + ASM 9.7.1, maven-compiler-plugin release=21, filevault-package-maven-plugin 1.3.6
upgrade-dependencies Core WCM Components, Groovy 4, Groovy Console coordinate updates
full-migrate Orchestrated 8-step pipeline (validate → baseline build → code → plugins → deps + uberjar → CloudManager version → intermediate build → tests)
verify Post-migration checks: compiler settings (= 21), jakarta-in-AEM detection, MIGRATION_TEMP markers, uber-jar apis classifier across all POMs, unsupported package imports, .cloudmanager/java-version, git diff summary

Critical guardrails

  • javax, not jakarta — AEM 6.5 LTS uses the javax namespace. The Java migration excludes jakarta recipes; a custom revert recipe and a verify check guard against silent regressions.
  • Unsupported packages → hard stop — Commerce, Communities, Granite Social, Screens, We.Retail, DAM PIM/rating, Search & Promote, MCM Campaign.
  • Removed bundles — Guava, Caffeine, Jetty, Commons Collections 3 produce WARNINGs with class-level remediation guidance.
  • Enforcer version floor — monotonically increasing (1.8 → 11 → 21), never lowered.

Documentation

All reference documents include links to public Adobe Experience League, OpenRewrite, Apache Maven, and Sling documentation so every claim is verifiable.

Test plan

  • mvn clean install from the skill root → BUILD SUCCESS for all three reactor modules
  • mvn test -pl aem65lts-migration-recipes → 17 tests pass across 4 recipe test classes
  • Java 8 source compatibility for the custom recipes (so the tool can run on the broadest JDK range)
  • CLI --help renders for all 8 subcommands
  • analyze correctly returns exit code 2 on a project containing an unsupported-package import
  • verify walks all POMs (not just the root) when checking the uber-jar apis classifier
  • npx skills-ref validate passes locally
  • End-to-end smoke test on a representative AEM 6.5 Maven project (recommended before promoting out of beta)

Beta status

The skill is marked beta. The [BETA] prefix in the description and a blockquote in the SKILL.md body signal beta status to the LLM during skill selection and execution. Validate all migrations against the post-migration checklist before promoting changes to production.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown

Tessl Skill Lint

edge-delivery-services — clean

stardust — clean


✅ All 2 tile(s) clean.

Updated by tessl-lint for commit 28bc84d.

…ewrite recipes

Adds the `java21-migration` skill (beta) to the `aem-6-5-lts` plugin. The
skill automates the upgrade of AEM 6.5 Maven projects to AEM 6.5 LTS on
Java 21 using deterministic AST-based transformations rather than text
substitution.

## Architecture

Two Maven modules under `plugins/aem/6.5-lts/skills/java21-migration/`:

- `aem65lts-migration-recipes/` — four custom OpenRewrite recipes
  implemented as Java visitors with unit-test coverage.
- `aem65lts-migration-cli/` — a picocli CLI (`aem-migrate`) that wraps
  `rewrite-maven-plugin` invocations into a single `full-migrate`
  pipeline plus discrete `upgrade-*` subcommands. Declarative composite
  recipes are bundled in `META-INF/config/openrewrite/recipes/` and
  loaded automatically via OpenRewrite classpath discovery.

## Custom Recipes

| Recipe | Purpose |
|--------|---------|
| `ChangeFilevaultEmbeddedArtifact` | Updates embedded artefact coordinates inside `filevault-package-maven-plugin` (handles Groovy Console groupId migration). |
| `RemoveBndPluginInstruction` | Removes `SCRDescriptorBndPlugin` and similar legacy BND instructions incompatible with bnd 6.x / Java 21. |
| `RevertJakartaInAemSource` | Safeguard that reverts accidental `jakarta.*` imports back to `javax.*` in AEM source files — jakarta annotations compile but fail silently at runtime on AEM 6.5 LTS. |
| `DetectUnsupportedPackages` | Read-only scanner that marks BLOCKER and WARNING imports for the `analyze` command. |

## CLI Commands

| Command | What it does |
|---------|-------------|
| `analyze [--json]` | Pre-migration scan with exit codes 0=ready, 1=warnings, 2=blockers. `--json` emits a schema-versioned report consumable by CI. |
| `upgrade-code` | Java 8/11 → 21 source migration. Cherry-picks recipes from `rewrite-migrate-java` and explicitly excludes `javax`→`jakarta` migration. |
| `upgrade-tests` | Mockito 1.x → 5.x progressive migration via `rewrite-testing-frameworks`. |
| `upgrade-uberjar` | UberJar bump to 6.6.0 with `apis` classifier. |
| `upgrade-plugins` | `maven-bundle-plugin` 5.1.9, `bnd-maven-plugin` 6.4.0, `maven-scr-plugin` 1.26.4 + ASM 9.7.1, `maven-compiler-plugin` `release=21`, `filevault-package-maven-plugin` 1.3.6. |
| `upgrade-dependencies` | Core WCM Components, Groovy 4, Groovy Console coordinate updates. |
| `full-migrate` | Orchestrated 8-step pipeline (validate → baseline build → code → plugins → deps + uberjar → CloudManager version → intermediate build → tests). |
| `verify` | Post-migration checks: compiler settings (= 21), jakarta-in-AEM detection, `MIGRATION_TEMP` markers, uber-jar `apis` classifier across all POMs, unsupported package imports, `.cloudmanager/java-version`, `git diff` summary. |

## Determinism Guarantees

- Every transformation is AST-based via OpenRewrite. POM formatting is
  preserved by construction.
- `IdempotencyTest` runs each custom recipe twice over its post-migration
  output and asserts the second pass produces zero changes — oscillating
  edits, visitor reruns, and order-dependent transforms are caught at
  build time.
- The CLI is the only supported entry point. Recipe artefact coordinates
  and active-recipe names are pinned in code so they cannot drift between
  runs.
- The `--json` analyze report carries a `schemaVersion` field (currently
  `1`) so downstream consumers can refuse versions they were not written
  against.

## Hard Guardrails (Tier 0 / Tier 1)

- **`javax`, not `jakarta`** — AEM 6.5 LTS uses the `javax` namespace.
  The Java migration excludes jakarta recipes; the
  `RevertJakartaInAemSource` recipe and a `verify` check guard against
  silent regressions.
- **Unsupported packages → hard stop** — Commerce, Communities, Granite
  Social, Screens, We.Retail, DAM PIM/rating, Search & Promote, MCM
  Campaign.
- **Removed bundles** — Guava, Caffeine, Jetty, Commons Collections 3
  produce WARNINGs with class-level remediation guidance.
- **Enforcer version floor** — monotonically increasing (1.8 → 11 → 21),
  never lowered.
- **Attribution marker** — every agent-authored fix carries
  `// aem-lts-migration: ai-fix` (kebab-cased, machine-parseable) so the
  audit trail is `grep`-able without natural-language ambiguity.

The guardrails are documented in `references/build-fix-constraints.md`
under stable rule IDs (T0.1 … T3.3) so PR reviews can reference rules by
identifier.

## Documentation

All reference documents include links to public [Adobe Experience League](https://experienceleague.adobe.com/en/docs/experience-manager-65-lts/content/release-notes/release-notes),
[OpenRewrite](https://docs.openrewrite.org/), Apache Maven, and Sling
documentation so every claim is verifiable.

## Test Plan

- [x] `mvn clean install` from the skill root → BUILD SUCCESS for all
  three reactor modules.
- [x] `mvn test` → 27 tests pass (22 recipe tests including 5 idempotency
  tests + 5 analysis-report contract tests).
- [x] Java 8 source compatibility for the custom recipes (broadest JDK
  range for the tool itself).
- [x] CLI `--help` renders for all 8 subcommands.
- [x] `analyze` returns exit code 2 on a project containing an
  unsupported-package import; `--json` emits the matching machine-readable
  report.
- [x] `verify` walks all POMs (not just the root) when checking the
  uber-jar `apis` classifier.
- [x] `npx skills-ref validate` passes locally.
- [ ] End-to-end smoke test on a representative AEM 6.5 Maven project
  (recommended before promoting out of beta).

## Beta Status

The skill is marked beta. The `[BETA]` prefix in the description and a
blockquote in the SKILL.md body signal beta status to the LLM during skill
selection and execution. Validate all migrations against the
post-migration checklist before promoting changes to production.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@abhishekgarg18 abhishekgarg18 force-pushed the feat/aem65lts-code-migration-skill branch from 700df28 to 4565238 Compare June 3, 2026 15:42
@rombert

rombert commented Jun 5, 2026

Copy link
Copy Markdown
Member

Thanks for the PR @abhigargadobe . I know this is a draft but wanted to mention early on that we need to decide what kind of scripts/tools we use from our skills and ideally use only one approach.

This PR use an embedded Java/Maven project ; not saying this is good or bad but we must decide if this is the way we go forward.

I am thinking on one side on the experience that users get when using the skill (ideally we don't bootstrap and/or require different tools for different skills ) but also on reusing patterns and maybe code for low-level plumbing for skills.

/cc @Himanich @mandeep294 @akankshajain18 @pkumargaddam

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants