本章提供了将 Gradle 8.x 构建迁移到最新 Gradle 版本所需的信息。如需从 Gradle 4.x、5.x、6.x 或 7.x 迁移,请首先参阅较旧的迁移指南

我们建议所有用户执行以下步骤

  1. 尝试运行 gradle help --scan 并查看生成的构建扫描的弃用视图

    Deprecations View of a Gradle Build Scan

    这样,你可以看到适用于你的构建的任何弃用警告。

    或者,你可以运行 gradle help --warning-mode=all 以在控制台中查看弃用信息,尽管它可能不会报告如此详细的信息。

  2. 更新你的插件。

    一些插件将与此新版本的 Gradle 冲突,例如因为它们使用已删除或更改的内部 API。通过在插件尝试使用已弃用的 API 部分时发出弃用警告,上一步将帮助你识别潜在问题。

  3. 运行 gradle wrapper --gradle-version 8.7 以将项目更新到 8.7。

  4. 尝试运行项目并使用故障排除指南调试任何错误。

从 8.6 及更早版本升级

潜在的破坏性更改

升级到 Kotlin 1.9.22

已将嵌入式 Kotlin 更新至 Kotlin 1.9.22

升级至 Apache SSHD 2.10.0

已将 Apache SSHD 从 2.0.0 更新至 2.10.0

替换和升级 JSch

JSch 已被 com.github.mwiede:jsch 替换,并从 0.1.55 更新至 0.2.16

升级至 Eclipse JGit 5.13.3

已将 Eclipse JGit 从 5.7.0 更新至 5.13.3

其中包括通过从 JSch 迁移至 Apache SSHD,重新设计 Gradle 为 SSH 操作配置 JGit 的方式。

升级至 Apache Commons Compress 1.25.0

已将 Apache Commons Compress 从 1.21 更新至 1.25.0。此更改可能会影响所生成 jar、zip 和其他归档类型的校验和,因为所生成工件的元数据可能有所不同。

升级至 ASM 9.6

已将 ASM 从 9.5 升级至 9.6,以更好地支持多版本 jar。

升级版本目录解析器

已升级版本目录解析器,现符合 TOML 规范的 1.0.0 版本

这不会影响使用 推荐语法 或由 Gradle 生成以供发布的目录。

弃用

弃用插件约定的注册

自 Gradle 8.2 起,使用插件约定一直会发出警告。现在,注册插件约定还会触发弃用警告。有关更多信息,请参阅 关于插件约定弃用的部分

在 Kotlin DSL 中通过 "name"() 引用任务和域对象

在 Kotlin DSL 中,可以使用 "name"() 表示法按名称引用任务或其他域对象。

可以通过多种方式按名称在容器中查找元素

tasks {
    "wrapper"() // 1 - returns TaskProvider<Task>
    "wrapper"(Wrapper::class) // 2 - returns TaskProvider<Wrapper>
    "wrapper"(Wrapper::class) { // 3 - configures a task named wrapper of type Wrapper
    }
    "wrapper" { // 4 - configures a task named wrapper of type Task
    }
}

第一个符号已弃用,将在 Gradle 9.0 中删除。不要使用 "name"() 来引用任务或域对象,请使用 named("name") 或其他受支持的符号。

上面的示例将写成

tasks {
    named("wrapper") // returns TaskProvider<Task>
}

Groovy DSL 构建脚本和 Gradle API 不会受到此影响。

已弃用的无效 URL 解码行为

在 Gradle 8.3 之前,Gradle 会使用接受无效 URL 并错误解码其他 URL 的算法来解码传递给 Project.uri(Object)CharSequence。Gradle 现在使用 URI 类来解析和解码 URL,但在出现错误时会回退到旧行为。

从 Gradle 9.0 开始,将删除回退,而是抛出错误。

要修复弃用警告,需要旧行为的无效 URL 应重新编码为有效 URL,如下例所示

表 1. 旧 URL 转换
原始输入 新输入 推理

file:relative/path

relative/path

file 方案不支持相对路径。

file:relative/path%21

relative/path!

如果没有方案,则按原样获取路径,不进行解码。

https://example.com/my folder/

https://example.com/my%20folder/

URL 中不允许有空格。

https://example.com/my%%badly%encoded%path

https://example.com/my%25%25badly%25encoded%25path

URL 中的 % 必须编码为 %25,并且没有 % 转义字符无效。

已弃用的 SelfResolvingDependency

SelfResolvingDependency 接口已弃用,将在 Gradle 9.0 中删除。此类型可以追溯到 Gradle 的第一个版本,其中一些依赖项可以独立解析。现在,所有依赖项都应使用 Configuration 作为依赖项图的一部分进行解析。

目前,ProjectDependencyFileCollectionDependency 实现此接口。在 Gradle 9.0 中,这些类型将不再实现 SelfResolvingDependency。相反,它们都将直接实现 Dependency

因此,ProjectDependencyFileCollectionDependency 的以下方法将不再可用

  • resolve

  • resolve(boolean)

  • getBuildDependencies

考虑展示已弃用接口及其替换项的以下脚本

build.gradle.kts
plugins {
    id("java-library")
}

dependencies {
    implementation(files("bar.txt"))
    implementation(project(":foo"))
}

tasks.register("resolveDeprecated") {
    // Wire build dependencies (calls getBuildDependencies)
    dependsOn(configurations["implementation"].dependencies.toSet())

    // Resolve dependencies
    doLast {
        configurations["implementation"].dependencies.withType<FileCollectionDependency>() {
            assert(resolve().map { it.name } == listOf("bar.txt"))
            assert(resolve(true).map { it.name } == listOf("bar.txt"))
        }
        configurations["implementation"].dependencies.withType<ProjectDependency>() {
            // These methods do not even work properly.
            assert(resolve().map { it.name } == listOf<String>())
            assert(resolve(true).map { it.name } == listOf<String>())
        }
    }
}

tasks.register("resolveReplacement") {
    val conf = configurations["runtimeClasspath"]

    // Wire build dependencies
    dependsOn(conf)

    // Resolve dependencies
    val files = conf.files
    doLast {
        assert(files.map { it.name } == listOf("bar.txt", "foo.jar"))
    }
}

org.gradle.util 包的已弃用成员现在报告其弃用情况

这些成员将在 Gradle 9.0 中删除。

  • Collection.stringize(Collection)

从 8.5 及更早版本升级

潜在的重大更改

升级到 JaCoCo 0.8.11

JaCoCo 已更新至 0.8.11

DependencyAdder 重命名为 DependencyCollector

正在孵化的 DependencyAdder 接口已重命名为 DependencyCollector。已向该接口添加了一个 getDependencies 方法,该方法返回所有声明的依赖项。

弃用

已弃用使用 main 源集调用 registerFeature

java 扩展上使用 main 源集调用 registerFeature 已弃用,并且将在 Gradle 9.0 中更改行为。

目前,在使用 main 源集调用 usingSourceSet 时创建的功能与使用任何其他源集调用 usingSourceSet 时创建的功能初始化方式不同。以前,在使用 main 源集时,会创建新的 implementationcompileOnlyruntimeOnlyapicompileOnlyApi 配置,并将 main 源集的编译和运行时类路径配置为扩展这些配置。

从 Gradle 9.0 开始,main 源集将像任何其他源集一样处理。在应用 java-library 插件(或应用 java 插件的任何其他插件)后,使用 main 源集调用 usingSourceSet 将引发异常。这是因为 java 插件已经配置了一个主功能。仅当未应用 java 插件时,在调用 usingSourceSet 时才允许使用 main 源集。

当前使用主源集注册功能的代码,如下所示

build.gradle.kts
plugins {
    id("java-library")
}

java {
    registerFeature("feature") {
        usingSourceSet(sourceSets["main"])
    }
}
build.gradle
plugins {
    id("java-library")
}

java {
    registerFeature("feature") {
        usingSourceSet(sourceSets.main)
    }
}

应该为该功能创建一个单独的源集,并使用该源集注册该功能

build.gradle.kts
plugins {
    id("java-library")
}

sourceSets {
    create("feature")
}

java {
    registerFeature("feature") {
        usingSourceSet(sourceSets["feature"])
    }
}
build.gradle
plugins {
    id("java-library")
}

sourceSets {
    feature
}

java {
    registerFeature("feature") {
        usingSourceSet(sourceSets.feature)
    }
}

已弃用将具有显式名称的发布工件依赖项发布到 Maven 存储库

使用与依赖项的 artifactId 不同的显式工件向 Maven 存储库发布依赖项已被弃用。在向 Ivy 存储库发布时,此行为仍然被允许。在 Gradle 9.0 中,这将导致错误。

当前,在向 Maven 存储库发布时,Gradle 将把以下依赖项解释为使用坐标 org:notfoo:1.0 声明。

build.gradle.kts
dependencies {
    implementation("org:foo:1.0") {
        artifact {
            name = "notfoo"
        }
    }
}
build.gradle
dependencies {
    implementation("org:foo:1.0") {
        artifact {
            name = "notfoo"
        }
    }
}

相反,此依赖项应声明为

build.gradle.kts
dependencies {
    implementation("org:notfoo:1.0")
}
build.gradle
dependencies {
    implementation("org:notfoo:1.0")
}

已弃用的 ArtifactIdentifier

ArtifactIdentifier 类已弃用,将在 Gradle 9.0 中移除。

弃用在观察后对 DependencyCollector 依赖项进行变异

从 Gradle 9.0 开始,在观察到从 DependencyCollector 来源的依赖项后,对它们进行变异将导致错误。DependencyCollector 接口用于在测试套件 DSL 中声明依赖项。

考虑以下示例,其中在观察到测试套件的依赖项后对其进行变异

build.gradle.kts
plugins {
    id("java-library")
}

testing.suites {
    named<JvmTestSuite>("test") {
        dependencies {
            // Dependency is declared on a `DependencyCollector`
            implementation("com:foo")
        }
    }
}

configurations.testImplementation {
    // Calling `all` here realizes/observes all lazy sources, including the `DependencyCollector`
    // from the test suite block. Operations like resolving a configuration similarly realize lazy sources.
    dependencies.all {
        if (this is ExternalDependency && group == "com" && name == "foo" && version == null) {
            // Dependency is mutated after observation
            version {
                require("2.0")
            }
        }
    }
}

在上述示例中,构建逻辑使用迭代和变异来尝试为特定依赖项设置默认版本(如果尚未设置版本)。如上述示例所示,构建逻辑在解析已声明的依赖项时会造成难题,因为报告工具会将此依赖项显示为用户声明版本为“2.0”,即使他们从未声明过。相反,构建逻辑可以通过在依赖项的坐标上声明一个 preferred 版本约束来避免迭代和变异。如果未声明其他版本,这将允许依赖项管理引擎使用约束上声明的版本。

考虑以下示例,其中使用一个不加选择的 preferred 版本约束替换上述迭代

build.gradle.kts
dependencies {
    constraints {
        testImplementation("com:foo") {
            version {
                prefer("2.0")
            }
        }
    }
}

从 8.4 及更早版本升级

潜在的破坏性更改

升级到 Kotlin 1.9.20

嵌入式 Kotlin 已更新至 Kotlin 1.9.20

Groovy 任务约定的更改

groovy-base 插件现在负责配置所有 GroovyCompile 任务的源兼容性和目标兼容性版本约定。

如果你在 未应用 grooy-base 的情况下使用此任务,则必须手动设置这些任务的兼容性版本。通常,每当使用 Groovy 语言任务时,都应应用 groovy-base 插件。

Provider.filter

传递给 Provider.filter 的参数类型已从 Predicate 更改为 Spec,以实现更一致的 API。此更改不应影响使用 lambda 表达式使用 Provider.filter 的任何人。但是,如果插件作者不使用 SAM 转换来创建 lambda,则可能会影响他们。

弃用

org.gradle.util 包中已弃用的成员现在报告其弃用

这些成员将在 Gradle 9.0 中删除

  • VersionNumber.parse(String)

  • VersionNumber.compareTo(VersionNumber)

已弃用依赖于已解析配置

在解析 Configuration 时,有时可以选择将同一配置作为变体。配置应用于一个目的(解析、消耗或依赖项声明),因此仅当配置被标记为可消耗和可解析时才会发生这种情况。

这会导致令人困惑的循环依赖关系图,因为正在解析的配置用于两个不同的目的。

为了避免此问题,插件应将所有可解析配置标记为 canBeConsumed=false,或在创建用于解析的配置时使用 resolvable(String) 配置工厂方法。

在 Gradle 9.0 中,将不再允许以这种方式消耗配置,并且会导致错误。

包含没有现有目录的项目

如果将项目添加到构建中,而关联的 projectDir 不存在或不可写,Gradle 将发出警告。从 9.0 版开始,如果项目目录不存在或只读,Gradle 将不会运行构建。如果您打算动态合成项目,请务必也为它们创建目录

settings.gradle.kts
include("project-without-directory")
project(":project-without-directory").projectDir.mkdirs()
settings.gradle
include 'project-without-directory'
project(":project-without-directory").projectDir.mkdirs()

从 8.3 及更早版本升级

潜在的重大更改

升级到 Kotlin 1.9.10

已将嵌入式 Kotlin 更新到 Kotlin 1.9.10

XML 解析现在需要最新的解析器

Gradle 8.4 现在使用启用了安全功能的 XML 解析器配置 XML 解析器。如果您的构建逻辑依赖于不支持安全解析的旧 XML 解析器,您的构建现在可能会失败。如果您遇到失败,请检查并更新或删除对旧版 XML 解析器的任何依赖项。

如果您无法升级来自构建逻辑依赖项的 XML 解析器,则可以强制使用 JVM 中内置的 XML 解析器。例如,在 OpenJDK 中,可以通过将以下内容添加到 gradle.properties 来实现此目的

systemProp.javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
systemProp.javax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
systemProp.javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

有关详细信息和在以前的 Gradle 版本中启用安全 XML 处理的方法,请参阅 CVE-2023-42445 通告。

使用自定义 JEE 1.3 描述符的 EAR 插件

解析 XML 文档时,Gradle 8.4 禁止外部 XML 实体。如果您使用 EAR 插件并通过 EAR 插件的 DSL 配置 application.xml 描述符,并使用 withXml {} 自定义描述符,并在自定义块中使用 asElement{},则出于安全原因,构建现在将失败。

build.gradle.kts
plugins {
    id("ear")
}
ear {
    deploymentDescriptor {
        version = "1.3"
        withXml {
            asElement()
        }
    }
}
build.gradle
plugins {
    id("ear")
}
ear {
    deploymentDescriptor {
        version = "1.3"
        withXml {
            asElement()
        }
    }
}

如果您碰巧使用 asNode() 而不是 asElement(),则没有任何变化,因为 asNode() 只是忽略外部 DTD。

您可以通过运行构建来解决此问题,方法是将 javax.xml.accessExternalDTD 系统属性设置为 http

在命令行中,将此内容添加到您的 Gradle 调用中

-Djavax.xml.accessExternalDTD=http

要使此解决方法持久,请将以下行添加到您的 gradle.properties

systemProp.javax.xml.accessExternalDTD=http

请注意,这将为整个构建 JVM 启用对外部 DTD 的 HTTP 访问。有关更多详细信息,请参阅 JAXP 文档

弃用

已弃用的 GenerateMavenPom 方法

GenerateMavenPom 上的以下方法已弃用,将在 Gradle 9.0 中删除。它们从未打算成为公共 API。

  • getVersionRangeMapper

  • withCompileScopeAttributes

  • withRuntimeScopeAttributes

从 8.2 及更早版本升级

潜在破坏性更改

已弃用的 Project.buildDir 可能导致脚本编译失败

随着 Project.buildDir 的弃用,如果使用已弃用的字段,则编译时带有警告作为错误的构建脚本可能会失败。

请参阅 弃用条目 了解详情。

TestLauncher API 不再忽略构建失败

TestLauncher 接口是工具 API 的一部分,专门用于运行测试。它是 BuildLauncher 的逻辑扩展,只能启动任务。已报告其行为中的差异:如果执行相同的失败测试,则 BuildLauncher 将报告构建失败,但 TestLauncher 不会。最初,这是一个设计决策,目的是继续执行并在所有测试任务中运行测试,而不是在第一次失败时停止。同时,这种行为可能会让用户感到困惑,因为他们可能会在成功的构建中遇到失败的测试。为了使这两个 API 更加统一,我们让 TestLauncher 也使构建失败,这是一个潜在的破坏性更改。要继续测试执行,即使测试任务失败,工具 API 客户端也应明确地将 --continue 传递给构建。

使用 ArtifactViewArtifactCollection 修复了变体选择行为

用于选择不同工件或文件的依赖关系解析 API(Configuration.getIncoming().artifactView { }Configuration.getIncoming().getArtifacts())捕获了底层 `Configuration’s 属性的不可变副本,以用于变体选择。如果在调用这些方法后更改了 `Configuration’s 属性,则这些方法选择的工件可能是意外的。

考虑在创建 ArtifactView 后更改 Configuration 上的属性集的情况。

build.gradle.kts
tasks {
    myTask {
        inputFiles.from(configurations.classpath.incoming.artifactView {
            attributes {
                // Add attributes to select a different type of artifact
            }
        }.files)
    }
}

configurations {
    classpath {
        attributes {
            // Add more attributes to the configuration
        }
    }
}

myTaskinputFiles 属性使用 artifact 视图从配置 classpath 中选择不同类型的 artifact。由于 artifact 视图是在将属性添加到配置之前创建的,因此 Gradle 无法选择正确的 artifact。

一些构建可能通过也将其他属性放入 artifact 视图来解决此问题。这不再是必需的。

升级到 Kotlin 1.9.0

嵌入式 Kotlin 已从 1.8.20 更新到 Kotlin 1.9.0。Kotlin DSL 的 Kotlin 语言和 API 级别仍设置为 1.8 以保持向后兼容性。请参阅 Kotlin 1.8.22Kotlin 1.8.21 的发行说明。

Kotlin 1.9 放弃了对 Kotlin 语言和 API 级别 1.3 的支持。如果你使用此版本的 Gradle 构建用 Kotlin 编写的 Gradle 插件,并且需要支持 Gradle <7.0,则需要坚持使用 Kotlin Gradle 插件 <1.9.0,并将 Kotlin 语言和 API 级别配置为 1.3。有关其他版本的详细信息,请参阅 兼容性矩阵

Configuration 属性的热切求值

Gradle 8.3 更新了 JVM 配置的 org.gradle.libraryelementsorg.gradle.jvm.version 属性,以便在创建时出现,而不是以前,它们仅在 Configuration 已解析或使用后才出现。特别是,org.gradle.jvm.version 的值依赖于项目配置的工具链,这意味着查询此属性的值将最终确定项目 Java 工具链的值。

热切查询 JVM 配置属性的插件或构建逻辑现在可能会导致项目的 Java 工具链比以前更早最终确定。尝试在工具链最终确定后对其进行修改将导致类似于以下内容的错误消息

The value for property 'implementation' is final and cannot be changed any further.
The value for property 'languageVersion' is final and cannot be changed any further.
The value for property 'vendor' is final and cannot be changed any further.

当插件或构建逻辑热切查询现有 JVM 配置的属性以创建具有相同属性的新配置时,可能会出现这种情况。以前,此逻辑会完全省略上述两个属性,而现在相同的逻辑将复制属性并最终确定项目的 Java 工具链。为避免工具链过早最终确定,应更新属性复制逻辑以惰性查询源配置的属性

build.gradle.kts
fun <T> copyAttribute(attribute: Attribute<T>, from: AttributeContainer, to: AttributeContainer) =
    to.attributeProvider<T>(attribute, provider { from.getAttribute(attribute)!! })

val source = configurations["runtimeClasspath"].attributes
configurations {
    create("customRuntimeClasspath") {
        source.keySet().forEach { key ->
            copyAttribute(key, source, attributes)
        }
    }
}
build.gradle
def source = configurations.runtimeClasspath.attributes
configurations {
    customRuntimeClasspath {
        source.keySet().each { key ->
            attributes.attributeProvider(key, provider { source.getAttribute(key) })
        }
    }
}

弃用

弃用的 Project.buildDir 将被 Project.layout.buildDirectory 替换

Project.buildDir 属性已弃用。它使用急切 API,如果在构建逻辑中读取该值,然后稍后修改该值,则会出现排序问题。它可能导致输出最终位于不同的位置。

它被 DirectoryProperty 替换,该属性位于 Project.layout.buildDirectory。有关详细信息,请参阅 ProjectLayout 接口。

请注意,在此阶段,如果您仍使用 Project.buildDir,Gradle 不会打印弃用警告。我们知道这是一个重大更改,并希望给主要插件的作者一些时间来首先停止使用它。

File 切换到 DirectoryProperty 需要在构建逻辑中进行调整。主要影响是您不能在 String 中使用该属性来扩展它。相反,您应该利用 dirfile 方法来计算所需的位置。

以下是一个创建文件的示例,其中

build.gradle.kts
// Returns a java.io.File
file("$buildDir/myOutput.txt")
build.gradle
// Returns a java.io.File
file("$buildDir/myOutput.txt")

应替换为

build.gradle.kts
// Compatible with a number of Gradle lazy APIs that accept also java.io.File
val output: Provider<RegularFile> = layout.buildDirectory.file("myOutput.txt")

// If you really need the java.io.File for a non lazy API
output.get().asFile

// Or a path for a lazy String based API
output.map { it.asFile.path }
build.gradle
// Compatible with a number of Gradle lazy APIs that accept also java.io.File
Provider<RegularFile> output = layout.buildDirectory.file("myOutput.txt")

// If you really need the java.io.File for a non lazy API
output.get().asFile

// Or a path for a lazy String based API
output.map { it.asFile.path }

以下是如何创建目录的另一个示例,其中

build.gradle.kts
// Returns a java.io.File
file("$buildDir/outputLocation")
build.gradle
// Returns a java.io.File
file("$buildDir/outputLocation")

应替换为

build.gradle.kts
// Compatible with a number of Gradle APIs that accept a java.io.File
val output: Provider<Directory> = layout.buildDirectory.dir("outputLocation")

// If you really need the java.io.File for a non lazy API
output.get().asFile

// Or a path for a lazy String based API
output.map { it.asFile.path }
build.gradle
// Compatible with a number of Gradle APIs that accept a java.io.File
Provider<Directory> output = layout.buildDirectory.dir("outputLocation")

// If you really need the java.io.File for a non lazy API
output.get().asFile

// Or a path for a lazy String based API
output.map { it.asFile.path }

弃用的 ClientModule 依赖项

ClientModule 依赖项已弃用,将在 Gradle 9.0 中删除。

Client 模块依赖项最初旨在允许构建通过在本地定义元数据来覆盖外部依赖项的不正确或缺失的组件元数据。此功能现已由 组件元数据规则 替换。

考虑以下 Client 模块依赖项示例

build.gradle.kts
dependencies {
    implementation(module("org:foo:1.0") {
        dependency("org:bar:1.0")
        module("org:baz:1.0") {
            dependency("com:example:1.0")
        }
    })
}
build.gradle
dependencies {
    implementation module("org:foo:1.0") {
        dependency "org:bar:1.0"
        module("org:baz:1.0") {
            dependency "com:example:1.0"
        }
    }
}

可以用以下组件元数据规则替换

build-logic/src/main/kotlin/my-plugin.gradle.kts
@CacheableRule
abstract class AddDependenciesRule @Inject constructor(val dependencies: List<String>) : ComponentMetadataRule {
    override fun execute(context: ComponentMetadataContext) {
        listOf("compile", "runtime").forEach { base ->
            context.details.withVariant(base) {
                withDependencies {
                    dependencies.forEach {
                        add(it)
                    }
                }
            }
        }
    }
}
build.gradle.kts
dependencies {
    components {
        withModule<AddDependenciesRule>("org:foo") {
            params(listOf(
                "org:bar:1.0",
                "org:baz:1.0"
            ))
        }
        withModule<AddDependenciesRule>("org:baz") {
            params(listOf("com:example:1.0"))
        }
    }

    implementation("org:foo:1.0")
}
build-logic/src/main/groovy/my-plugin.gradle
@CacheableRule
abstract class AddDependenciesRule implements ComponentMetadataRule {

    List<String> dependencies

    @Inject
    AddDependenciesRule(List<String> dependencies) {
        this.dependencies = dependencies
    }

    @Override
    void execute(ComponentMetadataContext context) {
        ["compile", "runtime"].each { base ->
            context.details.withVariant(base) {
                withDependencies {
                    dependencies.each {
                        add(it)
                    }
                }
            }
        }
    }
}
build.gradle
dependencies {
    components {
        withModule("org:foo", AddDependenciesRule) {
            params([
                "org:bar:1.0",
                "org:baz:1.0"
            ])
        }
        withModule("org:baz", AddDependenciesRule) {
            params(["com:example:1.0"])
        }
    }

    implementation "org:foo:1.0"
}

最早支持的 Develocity 插件版本为 3.13.1

从 Gradle 9.0 开始,最早支持的 Develocity 插件版本为 3.13.1。应用时将忽略 3.0 至 3.13 的插件版本。

升级到 Develocity 插件的 3.13.1 或更高版本。您可以在 Gradle 插件门户 上找到 最新可用版本。有关兼容性的更多信息,请参阅 此处

从 8.1 及更早版本升级

潜在的重大更改

升级到 Kotlin 1.8.20

已将嵌入式 Kotlin 更新到 Kotlin 1.8.20。有关更多信息,请参阅 Kotlin 1.8.20 的新增功能

请注意,Kotlin 编译避免存在一个已知问题,如果编译类路径包含非常大的 JAR 文件,则可能导致 compileKotlin 任务中出现 OutOfMemory 异常。这适用于应用 Kotlin 插件 v1.8.20 或 kotlin-dsl 插件的构建。

您可以在 gradle.properties 文件中禁用 Kotlin 编译避免来解决此问题

kotlin.incremental.useClasspathSnapshot=false

有关更多信息,请参阅 KT-57757

升级到 Groovy 3.0.17

Groovy 已更新到 Groovy 3.0.17

由于上一个版本是 3.0.15,因此还包括 3.0.16 更改。

升级到 Ant 1.10.13

Ant 已更新到 Ant 1.10.13

由于上一个版本是 1.10.11,因此还包括 1.10.12 更改。

升级到 CodeNarc 3.2.0

CodeNarc 的默认版本已更新到 CodeNarc 3.2.0

升级到 PMD 6.55.0

PMD 已更新到 PMD 6.55.0

由于上一个版本是 6.48.0,因此包括自那时以来的所有更改。

升级到 JaCoCo 0.8.9

JaCoCo 已更新到 0.8.9

插件兼容性更改

使用 Kotlin DSL 函数 Project.the<T>()Project.the(KClass)Project.configure<T> {} 编译的 Gradle >= 8.2 插件无法在 Gradle ⇐ 6.1 上运行。

某些任务的配置延迟或避免

在执行依赖项解析时,Gradle 会创建可用的 Configuration 的内部表示形式。这需要检查所有配置和工件。处理由任务创建的工件会导致这些任务实现并配置。

此内部表示形式现在创建得更加懒惰,这可能会改变任务配置的顺序。某些任务可能永远不会配置。

此更改可能会导致依赖于特定顺序的代码路径不再起作用,例如根据某些属性的存在有条件地向配置添加属性。

这影响了 bnd 插件和 JUnit5 构建

我们建议不要修改其他可能未配置的领域对象的配置块中的领域对象(配置、源集、任务等)。

例如,避免执行类似以下操作

    configurations {
        val myConfig = create("myConfig")
    }

    tasks.register("myTask") {
            // This is not safe, as the execution of this block may not occur, or may not occur in the order expected
          configurations["myConfig"].attributes {
              attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage::class.java, Usage.JAVA_RUNTIME))
          }
    }

弃用

CompileOptions 方法弃用

CompileOptions 上的以下方法已弃用

  • getAnnotationProcessorGeneratedSourcesDirectory()

  • setAnnotationProcessorGeneratedSourcesDirectory(File)

  • setAnnotationProcessorGeneratedSourcesDirectory(Provider<File>)

这些方法的当前用法应迁移到 DirectoryProperty getGeneratedSourceOutputDirectory()

错误使用配置

Configuration 的方法与配置的预期用法不一致时,Gradle 现在将在运行时发出警告。

此更改是持续进行的更大努力的一部分,旨在使配置的预期行为更加一致和可预测,并释放进一步的速度和内存改进。

目前,仅应使用这些列出的允许用法调用以下方法

  • resolve() - 仅限 RESOLVABLE 配置

  • files(Closure)files(Spec)files(Dependency…)fileCollection(Spec)fileCollection(Closure)fileCollection(Dependency…) - 仅限 RESOLVABLE 配置

  • getResolvedConfigurations() - 仅限 RESOLVABLE 配置

  • defaultDependencies(Action) - 仅限 DECLARABLE 配置

  • shouldResolveConsistentlyWith(Configuration) - 仅限 RESOLVABLE 配置

  • disableConsistentResolution() - 仅限 RESOLVABLE 配置

  • getDependencyConstraints() - 仅限 DECLARABLE 配置

  • copy()copy(Spec)copy(Closure)copyRecursive()copyRecursive(Spec)copyRecursive(Closure) - 仅限 RESOLVABLE 配置

预期用法在 Configuration 接口的 Javadoc 中有说明。此列表在未来版本中可能会增长。

从 Gradle 9.0 开始,禁止与预期用法不一致地使用配置。

另请注意,尽管目前没有限制,但 getDependencies() 方法实际上仅适用于 DECLARABLE 配置。getAllDependencies() 方法(它检索配置及其任何超配置上声明的所有依赖项)不会被限制为任何特定用法。

对插件约定已弃用的访问

约定的概念已过时,并被 扩展 所取代,以提供自定义 DSL。

为了在 Gradle API 中反映这一点,以下元素已弃用

Gradle Core 插件仍会注册其约定以及其扩展,以保持向后兼容性。

访问这些约定及其属性已弃用。这样做现在会发出弃用警告。这将在 Gradle 9.0 中成为一个错误。您应该优先访问扩展及其属性。

有关具体示例,请参阅下一部分。

著名的社区插件已迁移到使用扩展来提供自定义 DSL。其中一些仍然注册约定以保持向后兼容性。注册约定尚未发出弃用警告,以提供迁移窗口。未来的 Gradle 版本将这样做。

另请注意,使用 Kotlin DSL 函数 Project.the<T>()Project.the(KClass)Project.configure<T> {} 编译的 Gradle ⇐ 8.1 插件在 Gradle >= 8.2 上运行时将发出弃用警告。要修复此问题,应使用 Gradle >= 8.2 重新编译这些插件,或使用 extensions.getByType<T>() 直接访问扩展。

已弃用的 base 插件约定

base 插件提供的约定属性已弃用,并计划在 Gradle 9.0 中移除。有关更广泛的背景,请参阅 关于插件约定弃用的部分

这些约定由 BasePluginExtension 支持的 base { } 配置块替换。旧约定对象使用简单的 getter 和 setter 方法定义 distsDirNamelibsDirNamearchivesBaseName 属性。这些方法仅在扩展中可用,以保持向后兼容性。构建脚本应仅使用 Property 类型的属性

build.gradle.kts
plugins {
    base
}

base {
    archivesName.set("gradle")
    distsDirectory.set(layout.buildDirectory.dir("custom-dist"))
    libsDirectory.set(layout.buildDirectory.dir("custom-libs"))
}
build.gradle
plugins {
    id 'base'
}

base {
    archivesName = "gradle"
    distsDirectory = layout.buildDirectory.dir('custom-dist')
    libsDirectory = layout.buildDirectory.dir('custom-libs')
}

已弃用的 application 插件约定

application 插件提供的约定属性已弃用,并计划在 Gradle 9.0 中移除。有关更广泛的背景,请参阅 关于插件约定弃用的部分

以下代码现在将发出弃用警告

build.gradle.kts
plugins {
    application
}

applicationDefaultJvmArgs = listOf("-Dgreeting.language=en") // Accessing a convention
build.gradle
plugins {
    id 'application'
}

applicationDefaultJvmArgs = ['-Dgreeting.language=en'] // Accessing a convention

应改为使用由 JavaApplication 支持的 application { } 配置块

build.gradle.kts
plugins {
    application
}

application {
    applicationDefaultJvmArgs = listOf("-Dgreeting.language=en")
}
build.gradle
plugins {
    id 'application'
}

application {
    applicationDefaultJvmArgs = ['-Dgreeting.language=en']
}

已弃用的 java 插件约定

java 插件提供的约定属性已弃用,并计划在 Gradle 9.0 中移除。有关更广泛的背景,请参阅 关于插件约定弃用的部分

以下代码现在将发出弃用警告

build.gradle.kts
plugins {
    id("java")
}

configure<JavaPluginConvention> { // Accessing a convention
    sourceCompatibility = JavaVersion.VERSION_18
}
build.gradle
plugins {
    id 'java'
}

sourceCompatibility = 18 // Accessing a convention

应改为使用由 JavaPluginExtension 支持的 java { } 配置块

build.gradle.kts
plugins {
    id("java")
}

java {
    sourceCompatibility = JavaVersion.VERSION_18
}
build.gradle
plugins {
    id 'java'
}

java {
    sourceCompatibility = JavaVersion.VERSION_18
}

已弃用的 war 插件约定

war 插件提供的约定属性已弃用,并计划在 Gradle 9.0 中移除。有关更广泛的背景,请参阅 关于插件约定弃用的部分

以下代码现在将发出弃用警告

build.gradle.kts
plugins {
    id("war")
}

configure<WarPluginConvention> { // Accessing a convention
    webAppDirName = "src/main/webapp"
}
build.gradle
plugins {
    id 'war'
}

webAppDirName = 'src/main/webapp' // Accessing a convention

客户端应直接配置war任务。此外,tasks.withType(War.class).configureEach(…​)可用于配置每个类型为War的任务。

build.gradle.kts
plugins {
    id("war")
}

tasks.war {
    webAppDirectory.set(file("src/main/webapp"))
}
build.gradle
plugins {
    id 'war'
}

war {
    webAppDirectory = file('src/main/webapp')
}

已弃用的ear插件约定

ear插件提供的约定属性已弃用,并计划在 Gradle 9.0 中移除。有关更广泛的背景,请参阅有关插件约定弃用的部分

以下代码现在将发出弃用警告

build.gradle.kts
plugins {
    id("ear")
}

configure<EarPluginConvention> { // Accessing a convention
    appDirName = "src/main/app"
}
build.gradle
plugins {
    id 'ear'
}

appDirName = 'src/main/app' // Accessing a convention

客户端应直接配置ear任务。此外,tasks.withType(Ear.class).configureEach(…​)可用于配置每个类型为Ear的任务。

build.gradle.kts
plugins {
    id("ear")
}

tasks.ear {
    appDirectory.set(file("src/main/app"))
}
build.gradle
plugins {
    id 'ear'
}

ear {
    appDirectory = file('src/main/app')  // use application metadata found in this folder
}

已弃用的project-report插件约定

project-reports插件提供的约定属性已弃用,并计划在 Gradle 9.0 中移除。有关更广泛的背景,请参阅有关插件约定弃用的部分

以下代码现在将发出弃用警告

build.gradle.kts
plugins {
    `project-report`
}

configure<ProjectReportsPluginConvention> {
    projectReportDirName = "custom" // Accessing a convention
}
build.gradle
plugins {
    id 'project-report'
}

projectReportDirName = "custom" // Accessing a convention

改为配置报告任务

build.gradle.kts
plugins {
    `project-report`
}

tasks.withType<HtmlDependencyReportTask>() {
    projectReportDirectory.set(project.layout.buildDirectory.dir("reports/custom"))
}
build.gradle
plugins {
    id 'project-report'
}

tasks.withType(HtmlDependencyReportTask) {
    projectReportDirectory = project.layout.buildDirectory.dir("reports/custom")
}

冗余配置使用激活

对已允许该用法的配置调用setCanBeConsumed(boolean)setCanBeResolved(boolean)已弃用。

此弃用旨在帮助用户识别不必要的配置使用修改。

Configuration方法弃用

Configuration上的以下方法已弃用,计划移除

  • getAll()

改为从项目的configurations容器获取所有配置的集合。

依赖于自动测试框架实现依赖项

在某些情况下,Gradle 会从 Gradle 发行版加载 JVM 测试框架依赖项以执行测试。此现有行为可能导致测试类路径上的测试框架依赖项版本冲突。为了避免这些冲突,此行为已弃用,并将在 Gradle 9.0 中移除。使用 TestNG 的测试不受影响。

为了为行为的此更改做好准备,请显式声明必需的依赖项,或迁移到测试套件,其中这些依赖项会自动管理。

测试套件

使用测试套件的构建不会受到此更改的影响。测试套件会自动管理测试框架依赖项,无需显式声明依赖项。有关迁移到测试套件的更多信息,请参见用户手册

手动声明依赖项

在没有测试套件的情况下,必须在测试运行时类路径上手动声明依赖项

  • 如果使用 JUnit 5,则除了对测试引擎的现有 implementation 依赖项之外,还需要对 junit-platform-launcher 声明一个显式的 runtimeOnly 依赖项。

  • 如果使用 JUnit 4,则只需要对 junit 4 的现有 implementation 依赖项。

  • 如果使用 JUnit 3,则除了对 junit 3 的 compileOnly 依赖项之外,还需要对 junit 4 声明一个测试 runtimeOnly 依赖项。

build.gradle.kts
dependencies {
    // If using JUnit Jupiter
    testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    // If using JUnit Vintage
    testCompileOnly("junit:junit:4.13.2")
    testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.9.2")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    // If using JUnit 4
    testImplementation("junit:junit:4.13.2")

    // If using JUnit 3
    testCompileOnly("junit:junit:3.8.2")
    testRuntimeOnly("junit:junit:4.13.2")
}
build.gradle
dependencies {
    // If using JUnit Jupiter
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    // If using JUnit Vintage
    testCompileOnly 'junit:junit:4.13.2'
    testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.9.2'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    // If using JUnit 4
    testImplementation 'junit:junit:4.13.2'

    // If using JUnit 3
    testCompileOnly 'junit:junit:3.8.2'
    testRuntimeOnly 'junit:junit:4.13.2'
}

BuildIdentifierProjectComponentSelector 方法弃用

BuildIdentifier 上的以下方法已弃用

  • getName()

  • isCurrentBuild()

您可以使用这些方法来区分具有相同名称但来自不同构建的不同项目组件。但是,对于某些复合构建设置,这些方法提供的用于保证唯一性的信息不足。

这些方法的当前用法应迁移到 BuildIdentifier.getBuildPath()

类似地,方法 ProjectComponentSelector.getBuildName() 已弃用。改为使用 ProjectComponentSelector.getBuildPath()

从 8.0 及更早版本升级

CACHEDIR.TAG 文件在全局缓存目录中创建

Gradle 现在在一些全局缓存目录中发出 CACHEDIR.TAG 文件,如 directory_layout.html 中所述。

这可能导致某些工具不再搜索或备份这些目录。要禁用它,请在 Gradle 用户主目录中使用以下代码放在初始化脚本

init.gradle.kts
beforeSettings {
    caches {
        // Disable cache marking for all caches
        markingStrategy.set(MarkingStrategy.NONE)
    }
}
init.gradle
beforeSettings { settings ->
    settings.caches {
        // Disable cache marking for all caches
        markingStrategy = MarkingStrategy.NONE
    }
}

配置缓存选项已重命名

在此版本中,配置缓存功能已从孵化版提升到稳定版,因此,功能文档中最初提到的所有属性(其名称中带有 unsafe 部分,例如 org.gradle.unsafe.configuration-cache)已重命名,在某些情况下,只需删除 unsafe 部分即可。

孵化版属性 最终版属性

org.gradle.unsafe.configuration-cache

org.gradle.configuration-cache

org.gradle.unsafe.configuration-cache-problems

org.gradle.configuration-cache.problems*

org.gradle.unsafe.configuration-cache.max-problems

org.gradle.configuration-cache.max-problems

请注意,原始 org.gradle.unsafe.configuration-cache…​ 属性在此版本中仍然有效,如果使用它们,不会产生任何警告,但它们将在未来版本中弃用并删除。

潜在的重大更改

Kotlin DSL 脚本会发出编译警告

来自 Kotlin DSL 脚本的编译警告会打印到控制台输出。例如,在 Kotlin DSL 中使用已弃用的 API 会在每次编译脚本时发出警告。

如果您正在使用 Gradle 构建的控制台输出,则这是一个潜在的重大更改。

在应用 kotlin-dsl 插件的情况下配置 Kotlin 编译器选项

如果您在应用了 kotlin-dsl 插件的项目上配置自定义 Kotlin 编译器选项,则可能会遇到重大更改。

在以前的 Gradle 版本中,kotlin-dsl 插件会在 afterEvaluate {} 上添加必需的编译器参数。现在,Kotlin Gradle 插件提供了 延迟配置 属性,我们的 kotlin-dsl 插件已切换为直接向延迟属性添加必需的编译器参数。因此,如果您正在设置 freeCompilerArgs,则 kotlin-dsl 插件现在会使构建失败,因为其必需的编译器参数会被您的配置覆盖。

build.gradle.kts
plugins {
    `kotlin-dsl`
}

tasks.withType(KotlinCompile::class).configureEach {
    kotlinOptions { // Deprecated non-lazy configuration options
        freeCompilerArgs = listOf("-Xcontext-receivers")
    }
}

使用上述配置,您将收到以下构建失败

* What went wrong
Execution failed for task ':compileKotlin'.
> Kotlin compiler arguments of task ':compileKotlin' do not work for the `kotlin-dsl` plugin. The 'freeCompilerArgs' property has been reassigned. It must instead be appended to. Please use 'freeCompilerArgs.addAll(\"your\", \"args\")' to fix this.

您必须将其更改为将自定义编译器参数添加到 Kotlin Gradle 插件的延迟配置属性,以便将它们附加到 kotlin-dsl 插件所需的属性上

build.gradle.kts
plugins {
    `kotlin-dsl`
}

tasks.withType(KotlinCompile::class).configureEach {
    compilerOptions { // New lazy configuration options
        freeCompilerArgs.addAll("-Xcontext-receivers")
    }
}

如果您已经向 freeCompilerArgs 添加内容,而不是设置其值,那么您不应该遇到构建失败。

引入的新 API 可能会与现有的 Gradle DSL 代码冲突

当向 Gradle DSL 中的现有类型添加新属性或方法时,它可能会与用户代码中已使用的名称冲突。

当名称冲突发生时,一种解决方案是重命名用户代码中的元素。

以下是在 8.1 中添加的 API,可能会导致与现有用户代码的名称冲突(此列表并不详尽)。

在启用配置缓存的情况下,不再允许使用不受支持的 API 在配置时启动外部进程

自 Gradle 7.5 起,如果启用了功能预览 STABLE_CONFIGURATION_CACHE,则使用 Project.execProject.javaexec 以及标准 Java 和 Groovy API 在配置时运行外部进程被视为错误。随着 Gradle 8.1 中配置缓存提升为稳定功能,无论功能预览状态如何,都会检测到此错误。配置缓存章节 提供了更多详细信息,以帮助迁移到新的基于提供程序的 API,以便在配置时执行外部进程。

不使用配置缓存或仅在执行时启动外部进程的构建不受此更改影响。

弃用

修改核心插件配置用法

配置的允许用法在创建后应不可变。修改 Gradle 核心插件创建的配置上的允许用法已被弃用。这包括调用以下任何 Configuration 方法

  • setCanBeConsumed(boolean)

  • setCanBeResolved(boolean)

这些方法现在会在这些配置上发出弃用警告,但某些特殊情况除外,这些情况允许流行插件的现有行为。此规则尚未应用于构建脚本和第三方插件中创建的配置或分离的配置。为了避免在使用某些流行的第三方插件时发出的警告,尚未弃用对 apiElementsruntimeElements 调用 setCanBeConsumed(false)

此更改是更大范围持续努力的一部分,旨在使配置的预期行为更加一致且可预测,并在此 Gradle 领域释放进一步的速度和内存改进。

在 Gradle 9.0 中,将移除创建配置后更改允许使用情况的能力。

保留的配置名称

创建分离配置时,配置名称“detachedConfiguration”和“detachedConfigurationX”(其中 X 为任意整数)保留供内部使用。

在 Gradle 9.0 中,将移除创建具有这些名称的非分离配置的能力。

在没有 JavaPluginExtension 的情况下调用 java 组件上的选择方法

从 Gradle 8.1 开始,在没有默认 java 组件的情况下调用 JavaPluginExtension 上的以下任何方法都已弃用

  • withJavadocJar()

  • withSourcesJar()

  • consistentResolution(Action)

java 组件由 JavaPlugin 添加,而 JavaPlugin 由包括以下内容在内的任何 Gradle JVM 插件应用

  • java-library

  • application

  • groovy

  • scala

从 Gradle 9.0 开始,在没有默认 java 组件的情况下调用上述任何列出的方法都将成为一个错误。

WarPlugin#configureConfiguration(ConfigurationContainer)

从 Gradle 8.1 开始,调用 WarPlugin#configureConfiguration(ConfigurationContainer) 已弃用。此方法旨在供内部使用,从未打算用作公共接口的一部分。

从 Gradle 9.0 开始,此方法将被移除,且不会替换。

依赖于自定义测试任务的约定

默认情况下,在应用 java 插件时,所有 Test 任务的 testClassesDirs`和 `classpath 具有相同的约定。除非另行更改,否则默认行为是通过使用 test 套件的 classpathtestClassesDirs 配置任务来从默认 test TestSuite 执行测试。此行为将在 Gradle 9.0 中移除。

虽然此现有默认行为对于在不同环境下执行默认单元测试套件的用例是正确的,但它不支持执行完全独立的一组测试的用例。

如果您希望继续包含这些测试,请使用以下代码避免 8.1 中的弃用警告,并为 9.0 中的行为更改做好准备。或者,考虑迁移到测试套件。

build.gradle.kts
val test by testing.suites.existing(JvmTestSuite::class)
tasks.named<Test>("myTestTask") {
    testClassesDirs = files(test.map { it.sources.output.classesDirs })
    classpath = files(test.map { it.sources.runtimeClasspath })
}
build.gradle
tasks.myTestTask {
    testClassesDirs = testing.suites.test.sources.output.classesDirs
    classpath = testing.suites.test.sources.runtimeClasspath
}

在填充发布后修改 Gradle 模块元数据

在从 Maven 或 Ivy 发布中填充了 GMM(例如,更改组件配置变体)之后,现在已弃用。此功能将在 Gradle 9.0 中删除。

如果调用以下方法,则可以立即填充发布

以前,以下代码不会生成警告,但会在已发布工件之间创建不一致

build.gradle.kts
publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["java"])
        }
        create<IvyPublication>("ivy") {
            from(components["java"])
        }
    }
}

// These calls eagerly populate the Maven and Ivy publications

(publishing.publications["maven"] as MavenPublication).artifacts
(publishing.publications["ivy"] as IvyPublication).artifacts

val javaComponent = components["java"] as AdhocComponentWithVariants
javaComponent.withVariantsFromConfiguration(configurations["apiElements"]) { skip() }
javaComponent.withVariantsFromConfiguration(configurations["runtimeElements"]) { skip() }
build.gradle
publishing {
    publications {
        maven(MavenPublication) {
            from components.java
        }
        ivy(IvyPublication) {
            from components.java
        }
    }
}

// These calls eagerly populate the Maven and Ivy publications

publishing.publications.maven.artifacts
publishing.publications.ivy.artifacts

components.java.withVariantsFromConfiguration(configurations.apiElements) { skip() }
components.java.withVariantsFromConfiguration(configurations.runtimeElements) { skip() }

在此示例中,Maven 和 Ivy 发布将包含项目的 JAR 主工件,而 GMM 模块文件 将省略它们。

在 JVM 版本 6 和 7 上运行测试

在低于 8 的 JVM 版本上运行 JVM 测试已弃用。在这些版本上进行测试将在 Gradle 9.0 中变成一个错误

应用使用 Gradle < 6.0 发布的 Kotlin DSL 预编译脚本

应用使用 Gradle < 6.0 发布的 Kotlin DSL 预编译脚本已弃用。请使用使用 Gradle >= 6.0 发布的插件版本。

kotlin-dsl 与 Kotlin Gradle 插件 < 1.8.0 一起应用

kotlin-dsl 与 Kotlin Gradle 插件 < 1.8.0 一起应用已弃用。请让 Gradle 通过从构建逻辑中删除任何显式 kotlin-dsl 版本约束来控制 kotlin-dsl 的版本。这将让 kotlin-dsl 插件决定使用哪个版本的 Kotlin Gradle 插件。如果您明确声明在构建逻辑中使用哪个版本的 Kotlin Gradle 插件,请将其更新到 >= 1.8.0。

在 Kotlin 脚本的 plugins {} 块中从依赖项版本目录访问 librariesbundles

在 Kotlin 脚本的 plugins {} 块中从依赖项版本目录访问 librariesbundles 已弃用。请仅在 plugins {} 块中从依赖项版本目录使用 versionsplugins

在没有 Java 工具链的情况下使用 ValidatePlugins 任务

在不应用 Java 工具链 插件的情况下使用 ValidatePlugins 类型的任务已弃用,并且将在 Gradle 9.0 中成为错误。

为避免此警告,请将插件应用到您的项目

build.gradle.kts
plugins {
    id("jvm-toolchains")
}
build.gradle
plugins {
    id 'jvm-toolchains'
}

Java 工具链插件由 Java 库插件 或其他 JVM 插件自动应用。因此,您可以将其中任何一个应用到您的项目,它将修复警告。

org.gradle.util 包的弃用成员现在报告其弃用

这些成员将在 Gradle 9.0 中删除。

  • WrapUtil.toDomainObjectSet(…​)

  • GUtil.toCamelCase(…​)

  • GUtil.toLowerCase(…​)

  • ConfigureUtil

弃用的 JVM 供应商 IBM Semeru

枚举常量 JvmVendorSpec.IBM_SEMERU 现已弃用,并将在 Gradle 9.0 中删除。

请用其等效项 JvmVendorSpec.IBM 替换它,以避免在下一个主要版本发布中出现警告和潜在错误。

StartParameterGradleBuild 上设置自定义构建布局

Gradle 7.1 中相关先前弃用 的行为之后,现在还弃用了使用相关的 StartParameterGradleBuild 属性。这些属性将在 Gradle 9.0 中删除。

GradleBuild 任务中使用 buildFile 属性设置自定义构建文件已弃用。

请改用 dir 属性来指定嵌套构建的根目录。或者,考虑使用 GradleBuild 任务的推荐替代方案之一,如 避免使用 GradleBuild 任务类型 部分中所建议的。

使用 StartParameter 方法 setBuildFile(File)setSettingsFile(File) 以及对应的 getter getBuildFile()getSettingsFile() 设置自定义构建布局已弃用。

请为设置和构建文件使用标准位置

  • 构建根目录中的设置文件

  • 每个子项目的根目录中的构建文件

已弃用的 org.gradle.cache.cleanup 属性

Gradle 用户主目录下 gradle.properties 中的 org.gradle.cache.cleanup 属性已弃用。请改用 缓存清理 DSL 来禁用或修改清理配置。

由于较旧版本的 Gradle 可能仍需要 org.gradle.cache.cleanup 属性,因此该属性可能仍然存在,并且只要通过 DSL 配置了该属性,就不会打印弃用警告。DSL 值始终优先于 org.gradle.cache.cleanup 属性。如果所需的配置是禁用较旧版本的 Gradle 的清理(使用 org.gradle.cache.cleanup),但要为 Gradle 8 或更高版本的 Gradle 启用具有默认值的清理,则应将清理配置为使用 Cleanup.DEFAULT

cache-settings.gradle
if (GradleVersion.current() >= GradleVersion.version('8.0')) {
    apply from: "gradle8/cache-settings.gradle"
}
cache-settings.gradle.kts
if (GradleVersion.current() >= GradleVersion.version("8.0")) {
    apply(from = "gradle8/cache-settings.gradle")
}
gradle8/cache-settings.gradle
beforeSettings { settings ->
    settings.caches {
        cleanup = Cleanup.DEFAULT
    }
}
gradle8/cache-settings.gradle.kts
beforeSettings {
    caches {
        cleanup.set(Cleanup.DEFAULT)
    }
}

已弃用使用相对路径指定 Java 可执行文件

使用相对文件路径指向 Java 可执行文件现已弃用,并且将在 Gradle 9 中成为错误。这样做是为了减少对此类相对路径应解析为什么的困惑。

从任务操作中调用 Task.getConvention()Task.getExtensions()

在执行时从任务操作中调用 Task.getConvention()Task.getExtensions() 现已弃用,并且将在 Gradle 9.0 中成为错误。

有关如何将这些用法迁移到配置缓存支持的 API 的详细信息,请参阅 配置缓存章节

已弃用在未执行任何测试时成功运行测试任务

在未执行任何测试时成功运行 Test 任务现已弃用,并且将在 Gradle 9 中成为错误。请注意,当没有测试源时,这不是错误,在这种情况下,test 任务将被简单地跳过。只有在存在测试源但未选择任何测试执行时,这才是错误。此更改是为了避免由于错误配置而导致意外的成功测试运行。

IDE 集成的更改

不再需要使用版本目录时,在 Kotlin DSL plugins {} 块中显示的误报错误的解决方法

plugins {} 块中插件别名的版本目录访问器不再显示为 IntelliJ IDEA 和 Android Studio Kotlin 脚本编辑器中的错误。

如果您使用 @Suppress("DSL_SCOPE_VIOLATION") 注解作为解决方法,现在可以将其删除。

如果您使用的是 Gradle Libs Error Suppressor IntelliJ IDEA 插件,现在可以将其卸载。

将 Gradle 升级到 8.1 后,您需要清除 IDE 缓存并重新启动。