Gradle插件引入第三方Maven仓库后跨项目引用依赖解析失败问题
includeBuild引用Gradle插件时依赖无法解析,能否从插件内部配置仓库? 背景
我正在开发一个Gradle插件,插件项目的核心配置如下:
plugins { id 'java-gradle-plugin' id 'groovy' } repositories { mavenCentral() jcenter() // 自定义Maven仓库 maven { url = "https://maven.gentics.com/maven2" } } dependencies { implementation gradleApi(), localGroovy(), "com.gentics.mesh:mesh-rest-client:${MESH_VER}" testImplementation gradleTestKit() testImplementation("org.spockframework:spock-core:${SPOCK_VER}") { exclude module : 'groovy-all' } } // 其余配置...
当我在另一个项目的settings.gradle中用includeBuild "./gradle-mesh"引用这个插件时,抛出了依赖解析错误:
A problem occurred configuring root project 'functionalTest'.
Could not resolve all artifacts for configuration ':classpath'.
Could not find com.gentics.mesh:mesh-rest-client:1.7.1.
Searched in the following locations:
- https://plugins.gradle.org/m2/com/gentics/mesh/mesh-rest-client/1.7.1/mesh-rest-client-1.7.1.pom
If the artifact you are trying to retrieve can be found in the repository but without metadata in 'Maven POM' format, you need to adjust the 'metadataSources { ... }' of the repository declaration.
Required by:
project : > project :gradle-mesh
奇怪的是:
- 插件自身的functionalTest运行完全正常
- 把插件文件夹重命名为
buildSrc并移除settings.gradle里的includeBuild配置后,也能正常工作
我试过在插件的入口类里配置buildscript仓库,但没有效果:
class GradleMeshPlugin implements Plugin<Project> { public void apply(Project project) { project.buildscript.repositories.configure { mavenLocal() jcenter() maven { url = "https://maven.gentics.com/maven2" } } // 此处引用依赖... } }
后来在消费项目的settings.gradle中添加pluginManagement配置后,问题解决了:
pluginManagement { repositories { mavenCentral() jcenter() maven { url = "https://maven.gentics.com/maven2" } } } rootProject.name = 'website' includeBuild "./gradle-mesh"
现在的疑问是:能不能直接从插件应用内部完成这个仓库配置,而不需要在消费项目的settings.gradle里手动添加?
系统环境:
------------------------------------------------------------ Gradle 6.6.1 ------------------------------------------------------------ Build time: 2020-08-25 16:29:12 UTC Revision: f2d1fb54a951d8b11d25748e4711bec8d128d7e3 Kotlin: 1.3.72 Groovy: 2.5.12 Ant: Apache Ant(TM) version 1.10.8 compiled on May 10 2020 JVM: 11.0.8 (Ubuntu 11.0.8+10-post-Ubuntu-0ubuntu120.04) OS: Linux 5.4.0-47-generic amd64
解答
首先直接给结论:你没办法直接从插件应用内部完成这个仓库配置,原因和Gradle的构建生命周期机制密切相关,具体来说:
为什么插件内部配置没用?
Gradle的构建流程是分阶段执行的:
- 第一阶段是Settings阶段:这个阶段要搞定插件仓库配置、解析插件依赖、确定参与构建的项目——简单说,Gradle得先找到你的插件代码,才能运行插件里的
apply方法。 - 第二阶段才是配置阶段:这时候插件的
apply方法才会执行,你在里面配置的buildscript.repositories都是给项目本身的构建脚本用的,对之前的插件类路径解析完全没帮助。
当你用includeBuild引用本地插件时,Gradle需要先解析插件项目的implementation依赖(也就是那个mesh-rest-client)才能加载插件类。这个动作发生在Settings阶段,远早于插件的apply方法执行——等你插件代码跑起来的时候,依赖解析已经失败报错了。
至于buildSrc能正常工作,是因为Gradle对buildSrc有特殊处理:它会自动把buildSrc里的仓库配置用于自身的依赖解析,相当于跳过了手动配置的步骤。
那怎么简化消费端的配置?
虽然不能从插件内部解决,但可以用这些办法减少重复工作:
- 发布插件到私有仓库(最推荐):把你的插件打包发布到
https://maven.gentics.com/maven2这个仓库里,然后消费项目只需要在pluginManagement里添加这个仓库,再通过插件ID引用即可,不需要用includeBuild。这是Gradle插件的标准用法,也能统一管理依赖版本。 - 共享Settings配置片段:如果团队里多个项目都要引用这个本地插件,可以把
pluginManagement的配置抽成一个单独的文件,比如在插件项目里建个shared-settings.gradle:
然后消费项目的pluginManagement { repositories { mavenCentral() jcenter() maven { url = "https://maven.gentics.com/maven2" } } }settings.gradle里只需要引用这个文件就行:
这样就不用每个项目都手动写一遍仓库配置了。apply from: file("./gradle-mesh/shared-settings.gradle") rootProject.name = 'website' includeBuild "./gradle-mesh"
内容的提问来源于stack exchange,提问作者drkstr101

