我目前正在努力改进项目共享配置的方式.我们为所有库和微服务(即许多git repos)提供了许多不同的多模块gradle项目.
我的主要目标是:
不要在每个项目中复制我的Nexus存储库配置(同样,我可以放心地假设URL不会更改)
为了使我的自定义Gradle插件(发布到Nexus)可用于每个项目,只需极少的样板/复制(它们应该可用于每个项目,项目唯一关心的是它使用的版本)
没有魔力 - 开发人员应该明白如何配置所有内容
我目前的解决方案是使用init脚本的自定义gradle分发:
添加mavenLocal()
和我们的Nexus存储库到项目repos(非常类似于Gradle init脚本文档示例,除了它添加repos以及验证它们)
配置一个扩展,允许我们的gradle插件添加到buildscript类路径(使用此解决方法).它还添加了我们的Nexus repo作为buildcript repo,因为它是托管插件的地方.我们有很多插件(基于Netflix优秀的星云插件)用于各种样板:标准项目设置(kotlin设置,测试设置等),发布,发布,文档等,这意味着我们的项目build.gradle
文件几乎只用于依赖.
这是init脚本(已清理):
/**
* Gradle extension applied to all projects to allow automatic configuration of Corporate plugins.
*/
class CorporatePlugins {
public static final String NEXUS_URL = "https://example.com/repository/maven-public"
public static final String CORPORATE_PLUGINS = "com.example:corporate-gradle-plugins"
def buildscript
CorporatePlugins(buildscript) {
this.buildscript = buildscript
}
void version(String corporatePluginsVersion) {
buildscript.repositories {
maven {
url NEXUS_URL
}
}
buildscript.dependencies {
classpath "$CORPORATE_PLUGINS:$corporatePluginsVersion"
}
}
}
allprojects {
extensions.create('corporatePlugins', CorporatePlugins, buildscript)
}
apply plugin: CorporateInitPlugin
class CorporateInitPlugin implements Plugin {
void apply(Gradle gradle) {
gradle.allprojects { project ->
project.repositories {
all { ArtifactRepository repo ->
if (!(repo instanceof MavenArtifactRepository)) {
project.logger.warn "Non-maven repository ${repo.name} detected in project ${project.name}. What are you doing???"
} else if(repo.url.toString() == CorporatePlugins.NEXUS_URL || repo.name == "MavenLocal") {
// Nexus and local maven are good!
} else if (repo.name.startsWith("MavenLocal") && repo.url.toString().startsWith("file:")){
// Duplicate local maven - remove it!
project.logger.warn("Duplicate mavenLocal() repo detected in project ${project.name} - the corporate gradle distribution has already configured it, so you should remove this!")
remove repo
} else {
project.logger.warn "External repository ${repo.url} detected in project ${project.name}. You should only be using Nexus!"
}
}
mavenLocal()
// define Nexus repo for downloads
maven {
name "CorporateNexus"
url CorporatePlugins.NEXUS_URL
}
}
}
}
}
然后我通过将以下内容添加到根build.gradle文件来配置每个新项目:
buildscript {
// makes our plugins (and any others in Nexus) available to all build scripts in the project
allprojects {
corporatePlugins.version "1.2.3"
}
}
allprojects {
// apply plugins relevant to all projects (other plugins are applied where required)
apply plugin: 'corporate.project'
group = 'com.example'
// allows quickly updating the wrapper for our custom distribution
task wrapper(type: Wrapper) {
distributiOnUrl= 'https://com.example/repository/maven-public/com/example/corporate-gradle/3.5/corporate-gradle-3.5.zip'
}
}
虽然这种方法有效,但允许可重复的构建(不像我们以前的设置,它从URL应用了构建脚本 - 当时不可缓存),并允许脱机工作,它确实使它有点神奇,我想知道我是否可以做得更好.
这一切都是通过阅读Gradle dev Stefan Oehme 对Github的评论引发的,说明构建应该不依赖于init脚本,即init脚本应该是装饰性的并且做一些类似于记录的示例 - 防止未经授权的回购等.
我的想法是写一些扩展功能,让我对我们的Nexus回购和插件添加到构建的方式,看起来好像他们是建成gradle这个(类似扩展函数gradleScriptKotlin()
和kotlin-dsl()
由摇篮科特林DSL提供.
所以我在kotlin gradle项目中创建了我的扩展函数:
package com.example
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
fun RepositoryHandler.corporateNexus(): MavenArtifactRepository {
return maven {
with(it) {
name = "Nexus"
setUrl("https://example.com/repository/maven-public")
}
}
}
fun DependencyHandler.corporatePlugins(version: String) : Any {
return "com.example:corporate-gradle-plugins:$version"
}
计划在我的项目中使用它们build.gradle.kts
如下:
import com.example.corporateNexus
import com.example.corporatePlugins
buildscript {
repositories {
corporateNexus()
}
dependencies {
classpath(corporatePlugins(version = "1.2.3"))
}
}
但是,Gradle在buildscript
块中使用时无法看到我的函数(无法编译脚本).在正常的项目repos/dependencies中使用它们工作正常(它们是可见的并按预期工作).
如果这有效,我希望将jar捆绑到我的自定义发行版中,这意味着我的init脚本可以只进行简单的验证,而不是隐藏神奇的插件和repo配置.扩展函数不需要更改,因此在插件更改时不需要释放新的Gradle分布.
我尝试了什么:
将我的jar添加到测试项目的buildscript类路径(即buildscript.dependencies
) - 不起作用(可能这在设计上不起作用,因为buildscript
在同一块中引用的依赖项似乎不正确)
将函数放入buildSrc
(适用于普通的项目deps/repos但不是buildscript
,但不是真正的解决方案,因为它只是移动样板)
将jar放在发行版的lib
文件夹中
所以我的问题归结为:
我正在尝试实现的是什么(是否可以使buildScript
块可见的自定义类/函数)?
是否有更好的方法来配置企业Nexus仓库并使用最少的样板配置在许多单独的项目(即完全不同的代码库)中提供自定义插件(发布到Nexus)?
eskatos..
12
如果您想从所有Gradle Kotlin DSL中获益,您应该努力使用该plugins {}
块应用所有插件.请参阅https://github.com/gradle/kotlin-dsl/blob/master/doc/getting-started/Configuring-Plugins.md
您可以在设置文件中管理插件存储库和解决方案策略(例如,他们的版本).从Gradle 4.4开始,可以使用Kotlin DSL编写此文件settings.gradle.kts
.请参阅https://docs.gradle.org/4.4-rc-1/release-notes.html.
考虑到这一点,您可以拥有一个集中的Settings
脚本插件,可以设置并在构建settings.gradle.kts
文件中应用它:
// corporate-settings.gradle.kts
pluginManagement {
repositories {
maven {
name = "Corporate Nexus"
url = uri("https://example.com/repository/maven-public")
}
gradlePluginPortal()
}
}
和:
// settings.gradle.kts
apply(from = "https://url.to/corporate-settings.gradle.kts")
然后在项目构建脚本中,您只需从公司存储库中请求插件:
// build.gradle.kts
plugins {
id("my-corporate-plugin") version "1.2.3"
}
如果您希望项目在多项目构建中构建脚本以不重复插件版本,则可以通过在根项目中声明版本来使用Gradle 4.3执行此操作.请注意,您也可以将它的版本中settings.gradle.kts
使用pluginManagement.resolutionStrategy
,如果让所有建立使用相同的插件版本是你所需要的.
另请注意,要使所有这些工作正常,必须使用插件标记工件发布插件.这可以通过使用java-gradle-plugin
插件轻松完成.
1> eskatos..:
如果您想从所有Gradle Kotlin DSL中获益,您应该努力使用该plugins {}
块应用所有插件.请参阅https://github.com/gradle/kotlin-dsl/blob/master/doc/getting-started/Configuring-Plugins.md
您可以在设置文件中管理插件存储库和解决方案策略(例如,他们的版本).从Gradle 4.4开始,可以使用Kotlin DSL编写此文件settings.gradle.kts
.请参阅https://docs.gradle.org/4.4-rc-1/release-notes.html.
考虑到这一点,您可以拥有一个集中的Settings
脚本插件,可以设置并在构建settings.gradle.kts
文件中应用它:
// corporate-settings.gradle.kts
pluginManagement {
repositories {
maven {
name = "Corporate Nexus"
url = uri("https://example.com/repository/maven-public")
}
gradlePluginPortal()
}
}
和:
// settings.gradle.kts
apply(from = "https://url.to/corporate-settings.gradle.kts")
然后在项目构建脚本中,您只需从公司存储库中请求插件:
// build.gradle.kts
plugins {
id("my-corporate-plugin") version "1.2.3"
}
如果您希望项目在多项目构建中构建脚本以不重复插件版本,则可以通过在根项目中声明版本来使用Gradle 4.3执行此操作.请注意,您也可以将它的版本中settings.gradle.kts
使用pluginManagement.resolutionStrategy
,如果让所有建立使用相同的插件版本是你所需要的.
另请注意,要使所有这些工作正常,必须使用插件标记工件发布插件.这可以通过使用java-gradle-plugin
插件轻松完成.