Skip to content

ADFA-4911: Inject plugin-api + builder coordinates into localMvnRepository during onboarding - #1600

Merged
hal-eisen-adfa merged 16 commits into
stagefrom
ADFA-4911-inject-plugin-jars-localmvn
Jul 30, 2026
Merged

ADFA-4911: Inject plugin-api + builder coordinates into localMvnRepository during onboarding#1600
hal-eisen-adfa merged 16 commits into
stagefrom
ADFA-4911-inject-plugin-jars-localmvn

Conversation

@hal-eisen-adfa

Copy link
Copy Markdown
Collaborator

ADFA-4911: Inject plugin-api + builder coordinates into localMvnRepository during onboarding

During CoGo onboarding, materialize the plugin-api + plugin-builder Maven coordinates and the com.itsaky.androidide.plugins.build Gradle plugin marker into the on-device localMvnRepository, so plugin projects resolve them by coordinate, offline, with no libs/*.jar. Unblocks building plugins inside CoGo at scale (ADFA-4693).

How it works

  • Build time: assemble a small Maven-layout plugin-maven-repo.zip:
    • a fat com.itsaky.androidide:plugin-api:1.0.0 jar (merged classes of plugin-api + common + eventbus-events + idetooltips) with a dependency-free POM (it's compile-only/provided);
    • the plugin-builder impl + POM + the plugin marker, emitted by real maven-publish.
      Shipped as both a bundled .br asset and a split-zip entry.
  • On device: both installers (BundledAssetsInstaller, SplitAssetsInstaller) merge that zip into LOCAL_MAVEN_DIR inside the existing localMvnRepository branch (after its wipe+extract, via the non-wiping extractZipToDir) — avoiding a wipe/concurrency race. The overlay is deliberately not a separate install entry.

Onboarding reuses the already-shipped artifacts as the single source of truth, keeps versions in sync automatically, and leaves the fragile harvest pipeline untouched.

On-device version pins

The fat plugin-api + the three add-on modules pin Kotlin languageVersion/apiVersion to 2.0 so their metadata is readable by the on-device Kotlin 1.9.22 compiler; the builder targets on-device AGP 8.11.0 as compileOnly (dependency-free published POM) so offline resolution doesn't drag transitives.

Verification

  • Unit test ExtractZipToDirMergeTest: the merge primitive adds overlay entries without wiping existing files and rejects path traversal.
  • On-device (emulator, fresh onboarding from this branch's APK + assets):
    • AC1 — all three coordinates + the marker land at correct Maven paths; harvested repo preserved (merge, not wipe: 178 jars, all top-level groups intact).
    • AC2 — a coordinate-only plugin (app/ module, no libs/) builds :app:assemblePluginDebug fully offline (device network cut + --offline) to an 818 KB .cgp (valid archive, classes.dex compiled against the coordinate). No resolution errors.

Docs

PLUGIN_AUTHORING.md documents the plugin-api:1.0.0 coordinate and, from the on-device verification, the on-device AGP 8.11.0 / Kotlin 1.9.22 constraint and the root apply false AGP requirement (for CoGo's init-script LogSenderPlugin). PLUGIN_API_CHANGELOG.md updated.

Out of scope (companion tickets)

  • Plugin detection by manifest plugin.id instead of libs/plugin-api.jar — ADFA-4913 (until then, a coordinate-only project is built via Run Tasks, not the quick-run plugin path).
  • Migrating plugin-examples to coordinates + committed CI maven repo — ADFA-4908.

Blocks ADFA-4693. Relates to ADFA-4908, ADFA-4913.

…lMvnRepository

Ship plugin-api (fat compile jar) + plugin-builder + the Gradle plugin marker
as a sibling asset that onboarding merges into the on-device localMvnRepository,
so plugins resolve the API and builder by coordinate, offline, with no libs/ jars.
…e flavors

- localMvnRepository archive branch wipes its dir and entries install
  concurrently, so apply the plugin overlay inside that branch (not a
  separate racing entry).
- common/eventbus-events/idetooltips carry v7/v8 flavors; harvest v8
  classes.jar for the fat plugin-api coordinate.
…ring onboarding

Split LOCAL_MAVEN_REPO_ARCHIVE_ZIP_NAME out of the shared archive branch in
both BundledAssetsInstaller and SplitAssetsInstaller so the harvested repo
extract (wipe+extract) is followed, in the same job, by a merge (no wipe) of
plugin-maven-repo.zip via AssetsInstallationHelper.extractZipToDir. This
keeps the overlay out of the concurrent install-entry race that would
otherwise let the generic archive branch's destDir.deleteRecursively() wipe
it.

Adds ExtractZipToDirMergeTest to pin the merge/no-wipe and path-traversal
contract both installers depend on.
… 8.8.2 implementation

The builder pinned com.android.tools.build:gradle:8.8.2 (the CoGo app's own `agp`)
as an `implementation` dep, so its published POM forced 8.8.2 as a runtime transitive.
But on-device plugin builds use the tooling AGP (`agp-tooling` = 8.11.0), which is what
the harvested localMvnRepository ships -- so resolving the builder-by-coordinate offline
failed: "Could not find com.android.tools.build:gradle:8.8.2".

Fix: compile against 8.11.0 and make it compileOnly. AGP is supplied at runtime by the
plugin project's own com.android.application, so the builder must not force its own AGP.
The published plugin-builder POM is now dependency-free; plugin-api + builder + marker
resolve offline, and the builder plugin applies and runs against the harvested AGP.

Found by the ADFA-4911 end-to-end offline verification (Task 7).
…ead for the plugin-api coordinate

The fat plugin-api jar bundles plugin-api + common + eventbus-events + idetooltips.
plugin-api pinned languageVersion 2.1 (metadata 2.1.0) and the three add-ons inherited
the project's 2.3.0 (metadata 2.3.0). The on-device Kotlin compiler that builds plugins
is 1.9.22, which reads metadata only up to 2.0.0 -- so a plugin compiling against the
coordinate failed: "compiled with an incompatible version of Kotlin ... metadata is 2.1.0
/ 2.3.0, expected ... up to 2.0.0".

Pin all four modules to languageVersion/apiVersion 2.0 so every class in the coordinate
emits metadata 2.0.0. Verified: offline coordinate-only plugin build now compiles against
the fat jar and produces a .cgp with no -Xskip-metadata-version-check; plugin-api apiCheck
and the full app compile still pass.

Found by the ADFA-4911 end-to-end offline verification (Task 7). Shipped on-device
toolchain: AGP 8.11.0, Kotlin 1.9.22, Gradle 8.14.3, JDK 21.
The tests exercise the real extractZipToDir (no stubs were ever defined), so
mockkObject(AssetsInstallationHelper) did nothing but leak a process-global
object mock (no unmock), which could bleed into other tests sharing the JVM.
…irement

On-device offline builds resolve AGP/Kotlin from the harvested localMvnRepository
(AGP 8.11.0, Kotlin 1.9.22), and require AGP declared apply-false at the root so
CoGo's init-script LogSenderPlugin resolves AGP's ApplicationVariant. Verified on
emulator via a coordinate-only offline .cgp build.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough
  • Injects plugin Maven coordinates into the on-device localMvnRepository during onboarding.
  • Builds and ships plugin-maven-repo.zip containing:
    • A dependency-free fat com.itsaky.androidide:plugin-api:1.0.0 artifact (fat jar + dependency-free POM).
    • The plugin-builder implementation + POM.
    • The Gradle plugin marker POM.
  • Ships the repo in both bundled compressed assets and split-zip assets, merging it into the existing harvested Maven repo without wiping unrelated artifacts and avoiding install-entry races.
  • Adds installer merge behavior hardening, including path traversal protection and non-wiping merge + traversal rejection unit tests for extractZipToDir.
  • Aligns Kotlin metadata with on-device Kotlin: sets Kotlin apiVersion/languageVersion to 2.0 for plugin-related modules (for compatibility with the on-device Kotlin 1.9.22 toolchain).
  • Updates plugin-builder publication to publish offline-friendly POMs: compiles against AGP 8.11.0 as compileOnly and publishes via maven-publish with module metadata generation disabled.
  • Updates documentation (plugin authoring/changelog/specs) to reflect coordinate-based usage and on-device/offline requirements.
  • Risks / best-practice considerations:
    • The manually generated dependency-free POM approach means any future plugin API dependency changes must be reflected in the generated POM logic to avoid mismatches.
    • Installation now requires the overlay/split entry to be present; if the plugin Maven overlay asset is missing, onboarding installation should fail rather than silently degrade.
    • Asset merge correctness and safety rely on the overlay merge primitive; tests cover both “do not remove existing files” behavior and rejecting path traversal entries.
    • Documentation includes a future-dated changelog entry and references coordinate-only detection as not yet fully implemented.

Walkthrough

The PR builds a Maven repository containing plugin API and builder artifacts, packages it into bundled and split assets, merges it into the on-device local Maven repository during installation, and documents coordinate-based plugin authoring.

Changes

Plugin Maven repository injection

Layer / File(s) Summary
Coordinate publication and compiler compatibility
composite-builds/.../constants.kt, common/build.gradle.kts, eventbus-events/build.gradle.kts, idetooltips/build.gradle.kts, plugin-api/build.gradle.kts, plugin-api/plugin-builder/build.gradle.kts, docs/superpowers/...
Defines repository constants, Kotlin 2.0 metadata settings, builder Maven publication, and repository design constraints.
Repository assembly and asset packaging
app/build.gradle.kts, composite-builds/.../AndroidIDEAssetsPlugin.kt, .gitignore, docs/superpowers/...
Builds the fat plugin API JAR, dependency-free POM, and Maven repository ZIP, then includes it in bundled and split assets.
Installer overlay merge and validation
app/src/main/java/com/itsaky/androidide/assets/*, app/src/test/java/com/itsaky/androidide/assets/ExtractZipToDirMergeTest.kt, docs/superpowers/...
Merges the plugin repository after the harvested repository and tests preservation of existing files and rejection of path traversal.
Authoring documentation and acceptance checks
docs/PLUGIN_API_CHANGELOG.md, docs/PLUGIN_AUTHORING.md, docs/superpowers/...
Documents coordinate-based plugin dependencies, on-device build requirements, and offline verification steps.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant app_build_gradle
  participant AndroidIDEAssetsPlugin
  participant BundledOrSplitInstaller
  participant LocalMavenRepository
  app_build_gradle->>AndroidIDEAssetsPlugin: provide plugin-maven-repo.zip
  AndroidIDEAssetsPlugin->>BundledOrSplitInstaller: package bundled or split asset
  BundledOrSplitInstaller->>LocalMavenRepository: extract harvested repository
  BundledOrSplitInstaller->>LocalMavenRepository: merge plugin Maven overlay
Loading

Possibly related PRs

Suggested reviewers: jomen-adfa, jatezzz, itsaky-adfa

Poem

A bunny packs coordinates bright,
Into Maven burrows overnight.
Fat jars hop in,
Offline builds begin,
While overlays merge just right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: injecting plugin-api and plugin-builder coordinates into localMvnRepository during onboarding.
Description check ✅ Passed The description is clearly aligned with the changeset and describes the build-time packaging, asset shipping, and onboarding merge flow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ADFA-4911-inject-plugin-jars-localmvn

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
app/src/test/java/com/itsaky/androidide/assets/ExtractZipToDirMergeTest.kt (1)

3-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Migrate this test to JUnit Jupiter and Truth.

This new test introduces org.junit.Test and JUnit 4 assertions. Use JUnit Jupiter annotations/assertions instead, and apply Truth for equality/boolean checks where appropriate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/test/java/com/itsaky/androidide/assets/ExtractZipToDirMergeTest.kt`
around lines 3 - 6, Update ExtractZipToDirMergeTest to use JUnit Jupiter’s Test
annotation and assertions instead of org.junit.Test and JUnit 4 Assert imports;
replace equality and boolean checks with the project’s Truth assertions, while
preserving the test behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/build.gradle.kts`:
- Around line 492-507: Update writePluginApiPom to create pomFile’s parent
directory before calling writeText, ensuring the task succeeds when run directly
or before assemblePluginApiFatJar. Use the existing pomFile path and create its
parent without changing the generated POM content.

In
`@docs/superpowers/plans/2026-07-28-inject-plugin-coordinates-localmvnrepository.md`:
- Line 17: Align both design documents with the shipped dependency model: in
docs/superpowers/plans/2026-07-28-inject-plugin-coordinates-localmvnrepository.md
lines 17, 48-50, and 104-109, remove the claim that plugin-api build files
remain untouched, document compileOnly AGP 8.11.0, and describe a
dependency-free builder POM; in
docs/superpowers/specs/2026-07-28-inject-plugin-coordinates-localmvnrepository-design.md
lines 64-69 and 172-175, replace the builder-POM transitive dependency
requirement and add plugin-api/build.gradle.kts to the touched-file list.

---

Nitpick comments:
In `@app/src/test/java/com/itsaky/androidide/assets/ExtractZipToDirMergeTest.kt`:
- Around line 3-6: Update ExtractZipToDirMergeTest to use JUnit Jupiter’s Test
annotation and assertions instead of org.junit.Test and JUnit 4 Assert imports;
replace equality and boolean checks with the project’s Truth assertions, while
preserving the test behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b987166-dc34-48c3-a8e1-85d399938493

📥 Commits

Reviewing files that changed from the base of the PR and between b865016 and 5ac1022.

📒 Files selected for processing (16)
  • .gitignore
  • app/build.gradle.kts
  • app/src/main/java/com/itsaky/androidide/assets/BundledAssetsInstaller.kt
  • app/src/main/java/com/itsaky/androidide/assets/SplitAssetsInstaller.kt
  • app/src/test/java/com/itsaky/androidide/assets/ExtractZipToDirMergeTest.kt
  • common/build.gradle.kts
  • composite-builds/build-deps-common/constants/src/main/java/org/adfa/constants/constants.kt
  • composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/AndroidIDEAssetsPlugin.kt
  • docs/PLUGIN_API_CHANGELOG.md
  • docs/PLUGIN_AUTHORING.md
  • docs/superpowers/plans/2026-07-28-inject-plugin-coordinates-localmvnrepository.md
  • docs/superpowers/specs/2026-07-28-inject-plugin-coordinates-localmvnrepository-design.md
  • eventbus-events/build.gradle.kts
  • idetooltips/build.gradle.kts
  • plugin-api/build.gradle.kts
  • plugin-api/plugin-builder/build.gradle.kts

Comment thread app/build.gradle.kts
Comment thread docs/superpowers/plans/2026-07-28-inject-plugin-coordinates-localmvnrepository.md Outdated
createPluginMavenRepoZip depends on both writePluginApiPom and
assemblePluginApiFatJar but declares no order between them; the staging dir was
only created as a side effect of the Jar task, so writePluginApiPom could run
first (or standalone) and fail with FileNotFoundException. mkdirs() the parent.
The final implementation differs from the pre-implementation planning docs:
- The four module build files (plugin-api/common/eventbus-events/idetooltips)
  ARE edited (Kotlin languageVersion/apiVersion 2.0 pins), not untouched.
- The builder declares AGP compileOnly 8.11.0 (not implementation 8.8.2), so its
  published POM is dependency-free; plugin-builder applies maven-publish.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@docs/superpowers/specs/2026-07-28-inject-plugin-coordinates-localmvnrepository-design.md`:
- Around line 68-73: Align the coordinate table’s builder POM description with
the dependency-free claim in the surrounding section. Update the “real
config-time deps” wording to state that AGP is compile-only and excluded from
the published POM, while preserving the distinction between compile-time
availability and published transitive dependencies.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: df8bf3db-afb8-4d94-b097-f55ef26d5d81

📥 Commits

Reviewing files that changed from the base of the PR and between 5ac1022 and a27262b.

📒 Files selected for processing (3)
  • app/build.gradle.kts
  • docs/superpowers/plans/2026-07-28-inject-plugin-coordinates-localmvnrepository.md
  • docs/superpowers/specs/2026-07-28-inject-plugin-coordinates-localmvnrepository-design.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/superpowers/plans/2026-07-28-inject-plugin-coordinates-localmvnrepository.md

@hal-eisen-adfa
hal-eisen-adfa requested a review from a team July 30, 2026 03:15
@hal-eisen-adfa
hal-eisen-adfa merged commit c52cb7e into stage Jul 30, 2026
4 checks passed
@hal-eisen-adfa
hal-eisen-adfa deleted the ADFA-4911-inject-plugin-jars-localmvn branch July 30, 2026 18:15
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.

2 participants