Skip to content

Conversation

@kaeawc
Copy link

@kaeawc kaeawc commented Jan 15, 2026

Summary

This PR updates the project-replicator plugin to work with modern Gradle (9.x) and Android Gradle Plugin (8.x) versions.

Changes

  1. AndroidCollector.kt: Replace internal BasePlugin class usage with public plugin ID checks

    • The BasePlugin class from com.android.build.gradle.internal.plugins was an internal API that has been removed/changed in AGP 8.x
  2. GatherModuleInfoTask.kt:

    • Replace deprecated JavaPluginConvention with JavaPluginExtension (Convention API was removed in Gradle 9)
    • Replace ProjectDependency.dependencyProject.path with path reconstruction from group/name (dependencyProject was removed in Gradle 9)
  3. ResourceDataGathering.kt: Replace AGP's internal XmlUtils class with standard Java SAX parser configuration

    • The com.android.utils.XmlUtils class was an internal utility that is no longer reliably available
  4. Versions.kt: Update AGP version to 8.3.0 and Kotlin to 1.7.20 for compilation compatibility

Test plan

  • Tested against a large Android project (1,337 modules) running Gradle 9.1.0 and AGP 8.13.2
  • Successfully extracted project structure and generated replica project
  • Plugin compiles without errors

Notes

The project path reconstruction for ProjectDependency uses the group/name convention where the group contains dot-separated path segments. This handles the common case where project groups follow the pattern rootProject.subpath.module.

🤖 Generated with Claude Code

This PR updates the project-replicator plugin to work with modern
Gradle and Android Gradle Plugin versions.

Changes:

1. **AndroidCollector.kt**: Replace internal `BasePlugin` class usage
   with public plugin ID checks. The `BasePlugin` class from
   `com.android.build.gradle.internal.plugins` was an internal API
   that has been removed/changed in AGP 8.x.

2. **GatherModuleInfoTask.kt**:
   - Replace deprecated `JavaPluginConvention` with `JavaPluginExtension`
     (Convention API was removed in Gradle 9)
   - Replace `ProjectDependency.dependencyProject.path` with path
     reconstruction from group/name (dependencyProject was removed in
     Gradle 9)

3. **ResourceDataGathering.kt**: Replace AGP's internal `XmlUtils`
   class with standard Java SAX parser configuration. The
   `com.android.utils.XmlUtils` class was an internal utility that
   is no longer reliably available.

4. **Versions.kt**: Update AGP version to 8.3.0 and Kotlin to 1.7.20
   for compilation compatibility.

These changes were tested against a large Android project (1,337
modules) running Gradle 9.1.0 and AGP 8.13.2.

Co-Authored-By: Claude <[email protected]>
@google-cla
Copy link

google-cla bot commented Jan 15, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link

Summary of Changes

Hello @kaeawc, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly modernizes the project-replicator plugin, ensuring its compatibility with the latest Gradle 9.x and Android Gradle Plugin 8.x versions. It addresses several breaking API changes by updating dependency versions, migrating from internal Android Gradle Plugin APIs to public plugin ID checks, and replacing deprecated Gradle conventions with their modern equivalents. Additionally, it refactors XML parsing to use standard Java SAX parsers, enhancing stability and future-proofing.

Highlights

  • Dependency Updates: Upgraded Android Gradle Plugin (AGP) to 8.3.0 and Kotlin to 1.7.20 for compilation compatibility.
  • Android Plugin Detection Modernization: Replaced the use of the internal BasePlugin class with public plugin ID checks in AndroidCollector.kt to ensure compatibility with AGP 8.x.
  • Gradle API Modernization: Updated GatherModuleInfoTask.kt to use JavaPluginExtension instead of the deprecated JavaPluginConvention and implemented a new method for reconstructing project dependency paths, as dependencyProject.path was removed in Gradle 9.
  • XML Parsing Update: Replaced the internal XmlUtils class with a standard Java SAX parser configuration in ResourceDataGathering.kt for robust XML processing.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively modernizes the plugin for compatibility with Gradle 9.x and AGP 8.x. The changes correctly replace usages of internal or deprecated APIs with their modern, public equivalents, which significantly improves the plugin's robustness and future-proofing. The approach to replace BasePlugin with plugin ID checks and JavaPluginConvention with JavaPluginExtension is well-executed. I have a couple of suggestions to improve code clarity and robustness in exception handling.

Comment on lines +333 to +343
val projectPath = if (group != null && group != name) {
// Extract path from group by converting dots to colons and removing root project name
val pathFromGroup = group.substringAfter('.', "").replace('.', ':')
if (pathFromGroup.isNotEmpty()) {
":$pathFromGroup:$name"
} else {
":$name"
}
} else {
":$name"
}

Choose a reason for hiding this comment

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

medium

This logic for reconstructing the project path is a bit complex and contains some redundant code due to the nested if-else structure and repeated else blocks. It can be refactored to be more linear and easier to read, which will improve maintainability.

                val projectPath = (if (group != null && group != name) {
                    // Extract path from group by converting dots to colons and removing root project name
                    group.substringAfter('.', "").replace('.', ':')
                } else {
                    ""
                }).let { pathFromGroup ->
                    if (pathFromGroup.isNotEmpty()) {
                        ":$pathFromGroup:$name"
                    } else {
                        ":$name"
                    }
                }

Comment on lines +125 to +127
} catch (e: Exception) {
// Ignore if features not supported
}

Choose a reason for hiding this comment

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

medium

Catching a generic Exception and silently ignoring it can hide potential configuration issues. While the intention is to ignore unsupported features, this could also swallow other unexpected errors. It would be better to log the exception to provide visibility into any problems during SAX parser configuration, especially since this is security-related configuration.

        } catch (e: Exception) {
            // Ignore if features not supported, but log a warning.
            println("Warning: Failed to set security features on SAX parser: ${e.message}")
        }

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