使用 Gradle Kotlin DSL 在 Gradle 中配置样板项目
Boilerplate project configuration in Gradle with Gradle Kotlin DSL
我目前正在尝试改进我们的项目共享其配置的方式。我们有很多不同的多模块 gradle 项目用于我们所有的库和微服务(即许多 git 回购)。
我的主要目标是:
- 不要在每个项目中复制我的 Nexus 存储库配置(另外,我可以放心地假设 URL 不会更改)
- 使我的自定义 Gradle 插件(已发布到 Nexus)可用于每个项目,并尽量减少样板文件/重复(它们应该可用于每个项目,项目唯一关心的是它的版本使用)
- 没有魔法 - 开发人员应该很清楚一切是如何配置的
我当前的解决方案是自定义 gradle 发行版,其中包含一个初始化脚本:
- 将
mavenLocal()
和我们的 Nexus 存储库添加到项目存储库(与 Gradle init script documentation example 非常相似,除了它添加存储库并验证它们)
- 配置一个扩展,允许我们的 gradle 插件添加到构建脚本类路径(使用 this workaround). It also adds our Nexus repo as a buildscript repo as that's where the plugins are hosted. We have quite a few plugins (built upon Netflix's excellent nebula plugins)用于各种样板文件:标准项目设置(kotlin 设置、测试设置等)、发布、发布、文档等,这意味着我们的项目
build.gradle
文件几乎只用于依赖项。
这是初始化脚本(已清理):
/**
* 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<Gradle> {
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 开发者 Stefan Oehme 的 a comment on Github 引发的,他指出构建应该在不依赖初始化脚本的情况下工作,即初始化脚本应该只是装饰性的,并且可以做类似记录的示例 - 防止未经授权的回购等
我的想法是编写一些扩展函数,让我可以将我们的 Nexus 存储库和插件添加到构建中,就像它们内置于 gradle 中一样(类似于扩展函数 gradleScriptKotlin()
and kotlin-dsl()
由 Gradle Kotlin 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.dependencies
)- 不起作用(也许这在设计上不起作用,因为添加依赖项似乎不对 buildscript
在同一块中引用)
- 将函数放在
buildSrc
中(这适用于普通项目 deps/repos 但不适用于 buildscript
,但不是真正的解决方案,因为它只是移动样板文件)
- 将 jar 放到分发的
lib
文件夹中
所以我的问题归结为:
- 我想要实现的目标是否可行(是否可以使自定义 classes/functions 对
buildScript
块可见)?
- 是否有更好的方法来配置公司 Nexus 存储库并使自定义插件(发布到 Nexus)在许多单独的项目(即完全不同的代码库)中可用,并且具有最少的样板配置?
我在构建中一直在做类似的事情
buildscript {
project.apply {
from("${rootProject.projectDir}/sharedValues.gradle.kts")
}
val configureRepository: (Any) -> Unit by extra
configureRepository.invoke(repositories)
}
在我的 sharedValues.gradle.kts
文件中,我有这样的代码:
/**
* This method configures the repository handler to add all of the maven repos that your company relies upon.
* When trying to pull this method out of the [ExtraPropertiesExtension] use the following code:
*
* For Kotlin:
* ```kotlin
* val configureRepository : (Any) -> Unit by extra
* configureRepository.invoke(repositories)
* ```
* Any other casting will cause a compiler error.
*
* For Groovy:
* ```groovy
* def configureRepository = project.configureRepository
* configureRepository.invoke(repositories)
* ```
*
* @param repoHandler The RepositoryHandler to be configured with the company repositories.
*/
fun repositoryConfigurer(repoHandler : RepositoryHandler) {
repoHandler.apply {
// Do stuff here
}
}
var configureRepository : (RepositoryHandler) -> Unit by extra
configureRepository = this::repositoryConfigurer
我遵循类似的模式来配置插件的解析策略。
此模式的好处在于,您在 sharedValues.gradle.kts
中配置的任何内容也可以从您的 buildSrc
项目中使用,这意味着您可以重用存储库声明。
已更新:
您可以从 URL 应用另一个脚本,例如这样做:
apply {
// This was actually a plugin that I used at one point.
from("http://dl.bintray.com/shemnon/javafx-gradle/8.1.1/javafx.plugin")
}
只需托管您希望所有构建在某个 http 服务器上共享的脚本(强烈建议使用 HTTPS,这样您的构建就不会成为中间人攻击的目标)。
这样做的缺点是,我认为从 url 应用的脚本不会被缓存,因此每次您 运行 您的构建时都会重新下载它们。
这可能现在已经修复,我不确定。
当我遇到类似问题时,Stefan Oehme 向我提供了一个解决方案,即供应我自己的 Gradle 自定义发行版。据他说,这在大公司是很常见的事情。
只需创建 gradle 存储库的自定义分支,使用此自定义版本的 gradle 为每个项目添加贵公司的特殊调味料。
如果您想受益于所有 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 通过在根项目中声明版本来实现。请注意,如果您需要让所有构建使用相同的插件版本,您也可以使用 pluginManagement.resolutionStrategy
在 settings.gradle.kts
中设置版本。
另请注意,要使所有这些工作正常,您的插件必须与其 plugin marker artifact 一起发布。这可以通过使用 java-gradle-plugin
插件轻松完成。
我向@eskatos 保证我会回来对他的回答提供反馈 - 所以就在这里!
我的最终解决方案包括:
- Gradle 每个项目 4.7 个包装器(指向 Nexus 中 http://services.gradle.org/distributions 设置的镜像作为原始代理存储库,即它是普通的 Gradle 但通过 Nexus 下载)
- 自定义 Gradle 插件连同插件标记(由 Java Gradle Plugin Development Plugin 生成)
发布到我们的 Nexus 存储库
- 在我们的 Nexus 仓库中镜像 Gradle 插件门户(即指向 https://plugins.gradle.org/m2 的代理仓库)
- 每个项目一个
settings.gradle.kts
文件,将我们的 maven 仓库和 gradle 插件门户镜像(都在 Nexus 中)配置为插件管理存储库。
settings.gradle.kts
文件包含以下内容:
pluginManagement {
repositories {
// local maven to facilitate easy testing of our plugins
mavenLocal()
// our plugins and their markers are now available via Nexus
maven {
name = "CorporateNexus"
url = uri("https://nexus.example.com/repository/maven-public")
}
// all external gradle plugins are now mirrored via Nexus
maven {
name = "Gradle Plugin Portal"
url = uri("https://nexus.example.com/repository/gradle-plugin-portal")
}
}
}
这意味着所有插件及其依赖项现在都通过 Nexus 代理,并且 Gradle 将通过 id 找到我们的插件,因为插件标记也已发布到 Nexus。 mavenLocal
也有助于在本地轻松测试我们的插件更改。
每个项目的根 build.gradle.kts
文件然后按如下方式应用插件:
plugins {
// plugin markers for our custom plugins allow us to apply our
// plugins by id as if they were hosted in gradle plugin portal
val corporatePluginsVersion = "1.2.3"
id("corporate-project") version corporatePluginsVersion
// 'apply false` means this plugin can be applied in a subproject
// without having to specify the version again
id("corporate-publishing") version corporatePluginsVersion apply false
// and so on...
}
并配置 gradle 包装器以使用我们的镜像发行版,当与上述内容结合时意味着所有内容(gradle、插件、依赖项)都来自 Nexus:
tasks {
"wrapper"(Wrapper::class) {
distributionUrl = "https://nexus.example.com/repository/gradle-distributions/gradle-4.7-bin.zip"
}
}
我希望使用@eskatos 的建议在 settings.gradle.kts
中从远程 URL 应用脚本来避免设置文件中的样板。即
apply { from("https://nexus.example.com/repository/maven-public/com/example/gradle/corporate-settings/1.2.3/corporate-settings-1.2.3.kts" }
我什至设法生成了一个模板化脚本(与我们的插件一起发布):
- 配置了插件库(如上面的设置脚本)
- 如果请求的插件 ID 是我们的插件之一并且未提供版本(因此您可以通过 ID 应用它们),则使用解析策略来应用与脚本关联的插件版本
然而,即使它删除了样板,这意味着我们的构建依赖于与我们的 Nexus 存储库的连接,因为看起来即使从 URL 应用的脚本被缓存,Gradle 执行 HEAD 请求以检查更改。这也让在本地测试插件更改变得很烦人,因为我必须手动将其指向我本地 maven 目录中的脚本。使用我当前的配置,我可以简单地将插件发布到本地 Maven 并更新我项目中的版本。
我对当前的设置非常满意 - 我认为现在插件的应用方式对开发人员来说更加明显。现在,由于两者之间没有依赖性(并且不需要自定义 gradle 分发),因此独立升级 Gradle 和我们的插件变得容易得多。
在每个项目中复制通用配置时,我遇到了类似的问题。通过自定义 gradle 发行版解决了它,该发行版具有初始化脚本中定义的通用设置。
创建了一个 gradle 插件来准备此类自定义分发 - custom-gradle-dist。它非常适合我的项目,例如库项目的 build.gradle 看起来像这样(这是一个完整的文件):
dependencies {
compile 'org.springframework.kafka:spring-kafka'
}
我目前正在尝试改进我们的项目共享其配置的方式。我们有很多不同的多模块 gradle 项目用于我们所有的库和微服务(即许多 git 回购)。
我的主要目标是:
- 不要在每个项目中复制我的 Nexus 存储库配置(另外,我可以放心地假设 URL 不会更改)
- 使我的自定义 Gradle 插件(已发布到 Nexus)可用于每个项目,并尽量减少样板文件/重复(它们应该可用于每个项目,项目唯一关心的是它的版本使用)
- 没有魔法 - 开发人员应该很清楚一切是如何配置的
我当前的解决方案是自定义 gradle 发行版,其中包含一个初始化脚本:
- 将
mavenLocal()
和我们的 Nexus 存储库添加到项目存储库(与 Gradle init script documentation example 非常相似,除了它添加存储库并验证它们) - 配置一个扩展,允许我们的 gradle 插件添加到构建脚本类路径(使用 this workaround). It also adds our Nexus repo as a buildscript repo as that's where the plugins are hosted. We have quite a few plugins (built upon Netflix's excellent nebula plugins)用于各种样板文件:标准项目设置(kotlin 设置、测试设置等)、发布、发布、文档等,这意味着我们的项目
build.gradle
文件几乎只用于依赖项。
这是初始化脚本(已清理):
/**
* 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<Gradle> {
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 开发者 Stefan Oehme 的 a comment on Github 引发的,他指出构建应该在不依赖初始化脚本的情况下工作,即初始化脚本应该只是装饰性的,并且可以做类似记录的示例 - 防止未经授权的回购等
我的想法是编写一些扩展函数,让我可以将我们的 Nexus 存储库和插件添加到构建中,就像它们内置于 gradle 中一样(类似于扩展函数 gradleScriptKotlin()
and kotlin-dsl()
由 Gradle Kotlin 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.dependencies
)- 不起作用(也许这在设计上不起作用,因为添加依赖项似乎不对buildscript
在同一块中引用) - 将函数放在
buildSrc
中(这适用于普通项目 deps/repos 但不适用于buildscript
,但不是真正的解决方案,因为它只是移动样板文件) - 将 jar 放到分发的
lib
文件夹中
所以我的问题归结为:
- 我想要实现的目标是否可行(是否可以使自定义 classes/functions 对
buildScript
块可见)? - 是否有更好的方法来配置公司 Nexus 存储库并使自定义插件(发布到 Nexus)在许多单独的项目(即完全不同的代码库)中可用,并且具有最少的样板配置?
我在构建中一直在做类似的事情
buildscript {
project.apply {
from("${rootProject.projectDir}/sharedValues.gradle.kts")
}
val configureRepository: (Any) -> Unit by extra
configureRepository.invoke(repositories)
}
在我的 sharedValues.gradle.kts
文件中,我有这样的代码:
/**
* This method configures the repository handler to add all of the maven repos that your company relies upon.
* When trying to pull this method out of the [ExtraPropertiesExtension] use the following code:
*
* For Kotlin:
* ```kotlin
* val configureRepository : (Any) -> Unit by extra
* configureRepository.invoke(repositories)
* ```
* Any other casting will cause a compiler error.
*
* For Groovy:
* ```groovy
* def configureRepository = project.configureRepository
* configureRepository.invoke(repositories)
* ```
*
* @param repoHandler The RepositoryHandler to be configured with the company repositories.
*/
fun repositoryConfigurer(repoHandler : RepositoryHandler) {
repoHandler.apply {
// Do stuff here
}
}
var configureRepository : (RepositoryHandler) -> Unit by extra
configureRepository = this::repositoryConfigurer
我遵循类似的模式来配置插件的解析策略。
此模式的好处在于,您在 sharedValues.gradle.kts
中配置的任何内容也可以从您的 buildSrc
项目中使用,这意味着您可以重用存储库声明。
已更新:
您可以从 URL 应用另一个脚本,例如这样做:
apply {
// This was actually a plugin that I used at one point.
from("http://dl.bintray.com/shemnon/javafx-gradle/8.1.1/javafx.plugin")
}
只需托管您希望所有构建在某个 http 服务器上共享的脚本(强烈建议使用 HTTPS,这样您的构建就不会成为中间人攻击的目标)。
这样做的缺点是,我认为从 url 应用的脚本不会被缓存,因此每次您 运行 您的构建时都会重新下载它们。 这可能现在已经修复,我不确定。
当我遇到类似问题时,Stefan Oehme 向我提供了一个解决方案,即供应我自己的 Gradle 自定义发行版。据他说,这在大公司是很常见的事情。
只需创建 gradle 存储库的自定义分支,使用此自定义版本的 gradle 为每个项目添加贵公司的特殊调味料。
如果您想受益于所有 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 通过在根项目中声明版本来实现。请注意,如果您需要让所有构建使用相同的插件版本,您也可以使用 pluginManagement.resolutionStrategy
在 settings.gradle.kts
中设置版本。
另请注意,要使所有这些工作正常,您的插件必须与其 plugin marker artifact 一起发布。这可以通过使用 java-gradle-plugin
插件轻松完成。
我向@eskatos 保证我会回来对他的回答提供反馈 - 所以就在这里!
我的最终解决方案包括:
- Gradle 每个项目 4.7 个包装器(指向 Nexus 中 http://services.gradle.org/distributions 设置的镜像作为原始代理存储库,即它是普通的 Gradle 但通过 Nexus 下载)
- 自定义 Gradle 插件连同插件标记(由 Java Gradle Plugin Development Plugin 生成) 发布到我们的 Nexus 存储库
- 在我们的 Nexus 仓库中镜像 Gradle 插件门户(即指向 https://plugins.gradle.org/m2 的代理仓库)
- 每个项目一个
settings.gradle.kts
文件,将我们的 maven 仓库和 gradle 插件门户镜像(都在 Nexus 中)配置为插件管理存储库。
settings.gradle.kts
文件包含以下内容:
pluginManagement {
repositories {
// local maven to facilitate easy testing of our plugins
mavenLocal()
// our plugins and their markers are now available via Nexus
maven {
name = "CorporateNexus"
url = uri("https://nexus.example.com/repository/maven-public")
}
// all external gradle plugins are now mirrored via Nexus
maven {
name = "Gradle Plugin Portal"
url = uri("https://nexus.example.com/repository/gradle-plugin-portal")
}
}
}
这意味着所有插件及其依赖项现在都通过 Nexus 代理,并且 Gradle 将通过 id 找到我们的插件,因为插件标记也已发布到 Nexus。 mavenLocal
也有助于在本地轻松测试我们的插件更改。
每个项目的根 build.gradle.kts
文件然后按如下方式应用插件:
plugins {
// plugin markers for our custom plugins allow us to apply our
// plugins by id as if they were hosted in gradle plugin portal
val corporatePluginsVersion = "1.2.3"
id("corporate-project") version corporatePluginsVersion
// 'apply false` means this plugin can be applied in a subproject
// without having to specify the version again
id("corporate-publishing") version corporatePluginsVersion apply false
// and so on...
}
并配置 gradle 包装器以使用我们的镜像发行版,当与上述内容结合时意味着所有内容(gradle、插件、依赖项)都来自 Nexus:
tasks {
"wrapper"(Wrapper::class) {
distributionUrl = "https://nexus.example.com/repository/gradle-distributions/gradle-4.7-bin.zip"
}
}
我希望使用@eskatos 的建议在 settings.gradle.kts
中从远程 URL 应用脚本来避免设置文件中的样板。即
apply { from("https://nexus.example.com/repository/maven-public/com/example/gradle/corporate-settings/1.2.3/corporate-settings-1.2.3.kts" }
我什至设法生成了一个模板化脚本(与我们的插件一起发布):
- 配置了插件库(如上面的设置脚本)
- 如果请求的插件 ID 是我们的插件之一并且未提供版本(因此您可以通过 ID 应用它们),则使用解析策略来应用与脚本关联的插件版本
然而,即使它删除了样板,这意味着我们的构建依赖于与我们的 Nexus 存储库的连接,因为看起来即使从 URL 应用的脚本被缓存,Gradle 执行 HEAD 请求以检查更改。这也让在本地测试插件更改变得很烦人,因为我必须手动将其指向我本地 maven 目录中的脚本。使用我当前的配置,我可以简单地将插件发布到本地 Maven 并更新我项目中的版本。
我对当前的设置非常满意 - 我认为现在插件的应用方式对开发人员来说更加明显。现在,由于两者之间没有依赖性(并且不需要自定义 gradle 分发),因此独立升级 Gradle 和我们的插件变得容易得多。
在每个项目中复制通用配置时,我遇到了类似的问题。通过自定义 gradle 发行版解决了它,该发行版具有初始化脚本中定义的通用设置。
创建了一个 gradle 插件来准备此类自定义分发 - custom-gradle-dist。它非常适合我的项目,例如库项目的 build.gradle 看起来像这样(这是一个完整的文件):
dependencies {
compile 'org.springframework.kafka:spring-kafka'
}