So we distribute our convention plugins via an int...
# plugin-development
a
So we distribute our convention plugins via an internal artifactory, but keep them in the same repository for quick iteration, so that when we want to modify them, we just
includeBuild
the directory in our settings script This works fine, however, I want to add all these plugins to the project classpath as such by adding them to the root project build script
Copy code
plugins {
  alias(libs.plugins.internal.company.plugin) apply false
  alias(libs.plugins.internal.company.otherPlugin) apply false
  // etc
}
When I do this, it works fine until I include the build for local iteration. I basically can’t sync because of the following error
Error resolving plugin [id: 'plugin.name', version: '1.0.43'] > The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version, so compatibility cannot be checked.
I’m guessing this happens because when I include the build, gradle seems to add the plugins in it to the classpath with an
unknown
version, but then also tries to grab the latest published versions since I’m also trying to add them to the classpath, thus creating a conflict. Is there any way to work around this or will I have to resort to just commenting out my plugins from the
plugins
block whenever I want to work on them locally?
v
Having an included build does not add anyhting. Only if you use it, it is build and added as usual. From a cursory look I'd say it should just work fine. If it is not you are maybe hitting some edge case or bug or did not tell some relevant information. Can you steam it down to an MCVE showing the problem?
p
Yeah, I have the same problem and I don’t use the alias at all. Instead, we add the plugins to the classpath via an includedBuild and apply the plugins via id.
v
Still, please knit an MCVE. I regularly replace applied plublished plugins by simply adding an
includeBuild
without any problems.
a
Our setup is exactly the same as nowinandroid. I just noticed they don’t add their plugins to the root project plugins block either, but they don’t publish theirs at all
v
You already noted two differences yourself and it is a rather big project. That are three significant reasons why this project is useless as MCVE for your case.
n
I have the same issue as Adam and Philip. In our case we are building our plugin
com.emergetools.android
and we want to test it against another repository as a sort of integration test. https://github.com/EmergeTools/hackernews/blob/main/android/build.gradle.kts We removed our plugin (
com.emergetools.android
) from the build.gradle.kts in the other repository to be able to run this integration test without experiencing the issue that Adam explained.
MCVE would be checkout https://github.com/EmergeTools/emerge-android checkout https://github.com/EmergeTools/hackernews add
alias(libs.plugins.emerge) apply false
to
plugins
block in
hackernews/android/build.gradle.kts
cd hackernews/android && ./gradlew :app:emergeUploadSnapshotBundleDebug --include-build ../../emerge-android/gradle-plugin
v
Hm, from a quick debug I'd say this is indeed a Gradle bug (or shortcoming). When adding the plugin to the root project class loader, the
AlreadyOnClasspathPluginResolver
sees the plugin is not present on the classpath so just forwards to its delegate. The delegate is the
CompositePluginResolver
. This has the plugin repositories and the
CompositeBuildPluginResolver
as delegates. The
CompositeBuildPluginResolver
finds the included plugin build and provides the plugin, but does not record in the
PluginVersionTracker
that this plugin is coming from an included build. When then adding the plugin to the subproject class loader, the
AlreadyOnClasspathPluginResolver
sees the plugin is already present on the classpath through the parent classloader. It asks the
PluginVersionTracker
which version was applied there but this does not know the version and thus fails.
DefaultPluginRequestApplicator.applyPlugins
gets from the resolved plugin the plugin version and records it to the
PluginVersionTracker
after resolving it successfully. But for the included build, no version is set and so no version is tracked. Even if the version would be tracked, this is not the version that should be tracked, as included build should override plugin application with version and in @no's example the included build has a different version from the one used in the version catalog. So I guess a plugin coming to the classpath through an included build should either record that it is coming from an included build and then not fail due to unknown version, or it should record the originally requested version to not fail if the requests would be consistent without using an included build. The proper work-around to sometimes use an included build and sometimes not use an included build, with the plugin being on related classloaders would be to not use a version for the plugin on the sub-classloader (i.e. the
app
project), but only use the version on the top-most place where you add it. So in @no's example you would have the plugin with version in the root project, but without version in the
app
project and it would work with and without included build. Another work-around would be to define the plugin version in
pluginManagement { plugins { ... } }
and nowhere use a version in the build scripts. Because the version check for already on classpath compatibility check is done with the originally declared version, ignoring the version coming from
pluginManagement
and thus also does not suffer from this problem.
🙌 1
And here @Adam already reported it yesterday: https://github.com/gradle/gradle/issues/33227 🙂
a
thanks @Vampire!
👌 1