Skip to content

ADFA-3588: Enforce plugin-api binary compatibility with BCV#1474

Open
Daniel-ADFA wants to merge 1 commit into
stagefrom
ADFA-3588-bcv
Open

ADFA-3588: Enforce plugin-api binary compatibility with BCV#1474
Daniel-ADFA wants to merge 1 commit into
stagefrom
ADFA-3588-bcv

Conversation

@Daniel-ADFA

Copy link
Copy Markdown
Contributor

No description provided.

@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 to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

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

@Daniel-ADFA Daniel-ADFA requested a review from a team July 4, 2026 15:03
@Daniel-ADFA

Copy link
Copy Markdown
Contributor Author

@claude review

@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.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, comment @claude review on this pull request to trigger a review.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough
  • Added BCV-based binary compatibility validation for plugin-api by wiring the Gradle Binary Compatibility Validator plugin and introducing :plugin-api:apiCheck into the CI build flow before APK assembly.

  • Introduced a new plugin-api API dump that captures the exported plugin framework surface, including plugin lifecycle, context/logging, permissions, resource/service access, UI helpers, extension points, IDE services, and template builder types.

  • Updated plugin-api build configuration to apply the validator plugin and ignore com.itsaky.androidide.plugins.api.BuildConfig from API validation.

  • Added version-catalog entries for org.jetbrains.kotlinx.binary-compatibility-validator to keep the plugin version centrally managed.

  • Risk/notes: the new API dump is large and represents a broad public surface, so future changes to plugin contracts may become breaking and require careful versioning. Also, excluding BuildConfig from validation is practical, but it should be kept minimal to avoid hiding accidental public API changes.

Walkthrough

This PR adds Kotlin binary-compatibility validation to the plugin-api module: a new version-catalog plugin entry, application of the validator in plugin-api/build.gradle.kts with a BuildConfig exclusion, a CI workflow step running :plugin-api:apiCheck, and a generated plugin-api.api dump of the module's public ABI.

Changes

Plugin API Binary Compatibility Validation

Layer / File(s) Summary
Version catalog and build script wiring
gradle/libs.versions.toml, plugin-api/build.gradle.kts
Adds a binary-compatibility-validator version/plugin entry, applies the plugin in plugin-api, and configures apiValidation to ignore BuildConfig; existing dependencies and jar task logic are unchanged.
CI apiCheck step
.github/workflows/debug.yml
Adds a build step that activates the flox/base environment and runs :plugin-api:apiCheck before assembling the Universal APK.
Core plugin ABI dump
plugin-api/api/plugin-api.api
Generated API surface for IPlugin, PluginContext, PluginInfo, PluginLogger, PluginMetadata, PluginPermission, ResourceManager, ServiceRegistry, PluginFragmentHelper, SafePluginLayoutInflater.
Extension ABI dump
plugin-api/api/plugin-api.api
Generated API surface for build/code actions, completions, diagnostics, documentation, editor, project/module, navigation, tooltip, template, snippet, and UI extension contracts.
IDE service layer & template builder ABI dump
plugin-api/api/plugin-api.api
Generated API surface for archive, build, command, editor, environment, file, project, theme, tooltip, and UI services, plus CgtTemplateBuilder.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: itsaky-adfa, jatezzz

Poem

A rabbit hopped through Gradle's maze,
Found an API dump in a binary haze,
"apiCheck" now guards each hop and jump,
No breaking change shall pass this bump! 🐰
Carrots and contracts, safely stashed,
Compatibility kept, nothing crashed! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No author description was provided, so the PR text is too vague to assess meaningfully. Add a brief description of the plugin-api BCV enforcement and workflow changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately names the main change: enforcing plugin-api binary compatibility with BCV.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ADFA-3588-bcv

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: 1

🧹 Nitpick comments (2)
plugin-api/build.gradle.kts (1)

31-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider ignoring the generated R class as well.

Only BuildConfig is excluded from the ABI dump. Android library modules also generate a public R class (com.itsaky.androidide.plugins.api.R), which will likely show up in plugin-api.api and cause spurious apiCheck failures whenever resources change, unrelated to actual API changes.

♻️ Proposed addition
 apiValidation {
 	ignoredClasses.add("com.itsaky.androidide.plugins.api.BuildConfig")
+	ignoredClasses.add("com.itsaky.androidide.plugins.api.R")
 }
🤖 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 `@plugin-api/build.gradle.kts` around lines 31 - 34, The apiValidation block
currently ignores only BuildConfig, so the generated public R class can still
pollute the ABI dump and trigger false apiCheck failures. Update the
apiValidation configuration in build.gradle.kts to also ignore the generated R
class for the plugin-api module, using the same ignoredClasses list alongside
com.itsaky.androidide.plugins.api.BuildConfig.
.github/workflows/debug.yml (1)

133-136: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider combining apiCheck into the main Gradle invocation.

Running :plugin-api:apiCheck as a separate flox activate/Gradle invocation before :app:assembleV8Debug incurs a second full Gradle configuration pass. Combining both tasks into a single invocation (./gradlew :plugin-api:apiCheck :app:assembleV8Debug --no-daemon) would preserve fail-fast semantics for the API check while avoiding duplicate startup/configuration overhead.

🤖 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 @.github/workflows/debug.yml around lines 133 - 136, The workflow currently
runs :plugin-api:apiCheck in a separate flox activate/Gradle invocation before
:app:assembleV8Debug, causing an extra full Gradle configuration pass. Update
the debug workflow step that invokes ./gradlew so :plugin-api:apiCheck and
:app:assembleV8Debug run in the same Gradle command, preserving fail-fast
behavior while removing the duplicate startup overhead. Use the existing
workflow job and the Gradle invocation around :plugin-api:apiCheck and
:app:assembleV8Debug as the location to adjust.
🤖 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 `@plugin-api/api/plugin-api.api`:
- Around line 111-125: `PluginFragmentHelper` is exposing host-owned mutators in
the public plugin ABI, so move the lifecycle/state-changing APIs out of the
plugin-facing surface. Keep `getCurrentActivityContext`,
`getCurrentActivityTheme`, `getPluginContext`, `getPluginInflater`,
`getServiceRegistry`, and the error callback accessors public, but hide or
relocate `registerPluginContext`, `registerServiceRegistry`,
`unregisterPluginContext`, and `clearAllContexts` to a host-internal API so
plugins cannot modify shared state.

---

Nitpick comments:
In @.github/workflows/debug.yml:
- Around line 133-136: The workflow currently runs :plugin-api:apiCheck in a
separate flox activate/Gradle invocation before :app:assembleV8Debug, causing an
extra full Gradle configuration pass. Update the debug workflow step that
invokes ./gradlew so :plugin-api:apiCheck and :app:assembleV8Debug run in the
same Gradle command, preserving fail-fast behavior while removing the duplicate
startup overhead. Use the existing workflow job and the Gradle invocation around
:plugin-api:apiCheck and :app:assembleV8Debug as the location to adjust.

In `@plugin-api/build.gradle.kts`:
- Around line 31-34: The apiValidation block currently ignores only BuildConfig,
so the generated public R class can still pollute the ABI dump and trigger false
apiCheck failures. Update the apiValidation configuration in build.gradle.kts to
also ignore the generated R class for the plugin-api module, using the same
ignoredClasses list alongside com.itsaky.androidide.plugins.api.BuildConfig.
🪄 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

Run ID: aa38a1fa-f60c-4b71-a78c-bbb40328b386

📥 Commits

Reviewing files that changed from the base of the PR and between feff84f and a7e8dc2.

📒 Files selected for processing (4)
  • .github/workflows/debug.yml
  • gradle/libs.versions.toml
  • plugin-api/api/plugin-api.api
  • plugin-api/build.gradle.kts

Comment on lines +111 to +125
public final class com/itsaky/androidide/plugins/base/PluginFragmentHelper {
public static final field INSTANCE Lcom/itsaky/androidide/plugins/base/PluginFragmentHelper;
public static final fun clearAllContexts ()V
public static final fun getCurrentActivityContext (Ljava/lang/String;)Landroid/content/Context;
public static final fun getCurrentActivityTheme (Ljava/lang/String;)Landroid/content/res/Resources$Theme;
public static final fun getOnPluginInflationError ()Lkotlin/jvm/functions/Function2;
public static final fun getPluginContext (Ljava/lang/String;)Landroid/content/Context;
public static final fun getPluginInflater (Ljava/lang/String;Landroid/view/LayoutInflater;)Landroid/view/LayoutInflater;
public static final fun getServiceRegistry (Ljava/lang/String;)Lcom/itsaky/androidide/plugins/ServiceRegistry;
public static final fun registerPluginContext (Ljava/lang/String;Landroid/content/Context;)V
public static final fun registerPluginContext (Ljava/lang/String;Landroid/content/Context;Z)V
public static synthetic fun registerPluginContext$default (Ljava/lang/String;Landroid/content/Context;ZILjava/lang/Object;)V
public static final fun registerServiceRegistry (Ljava/lang/String;Lcom/itsaky/androidide/plugins/ServiceRegistry;)V
public static final fun setOnPluginInflationError (Lkotlin/jvm/functions/Function2;)V
public static final fun unregisterPluginContext (Ljava/lang/String;)V

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.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify source intent and callers before changing the ABI surface.
rg -n -C4 'clearAllContexts|registerPluginContext|registerServiceRegistry|unregisterPluginContext|onPluginInflationError' plugin-api/src/main/kotlin

Repository: appdevforall/CodeOnTheGo

Length of output: 6550


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the helper implementation and surrounding API surface.
sed -n '1,160p' plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/base/PluginFragment.kt
printf '\n--- API dump excerpt ---\n'
sed -n '100,140p' plugin-api/api/plugin-api.api

printf '\n--- References to the helper from plugin-api ---\n'
rg -n -C2 'PluginFragmentHelper\.' plugin-api/src/main/kotlin plugin-api/api

Repository: appdevforall/CodeOnTheGo

Length of output: 7888


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find who calls the helper mutators and how the package is described elsewhere.
rg -n -C3 'PluginFragmentHelper\.(clearAllContexts|registerPluginContext|registerServiceRegistry|unregisterPluginContext|setOnPluginInflationError|getPluginInflater|getPluginContext|getServiceRegistry)' .
printf '\n--- plugin-api module files ---\n'
git ls-files 'plugin-api/src/main/kotlin/**/*.kt' 'plugin-api/src/main/kotlin/*.kt'

Repository: appdevforall/CodeOnTheGo

Length of output: 14918


Keep PluginFragmentHelper mutators out of the plugin-facing API.

registerPluginContext, registerServiceRegistry, unregisterPluginContext, and clearAllContexts are host-owned lifecycle hooks, but they’re exposed as public ABI here. Any plugin can call them and wipe or replace shared context/registry state for other plugins. Split the manager-only mutators into a host-internal surface and keep only the read-only/plugin-side helpers public.

🤖 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 `@plugin-api/api/plugin-api.api` around lines 111 - 125, `PluginFragmentHelper`
is exposing host-owned mutators in the public plugin ABI, so move the
lifecycle/state-changing APIs out of the plugin-facing surface. Keep
`getCurrentActivityContext`, `getCurrentActivityTheme`, `getPluginContext`,
`getPluginInflater`, `getServiceRegistry`, and the error callback accessors
public, but hide or relocate `registerPluginContext`, `registerServiceRegistry`,
`unregisterPluginContext`, and `clearAllContexts` to a host-internal API so
plugins cannot modify shared state.

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.

1 participant