本章提供了将 Gradle 7.x 构建迁移到 Gradle 8.0 所需的信息。要从 Gradle 6.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. 尝试运行项目并使用故障排除指南调试任何错误。

从 7.6 及更早版本升级

现在是错误的警告

使用 finalizedBymustRunAftershouldRunAfter 引用包含构建中的任务

现在,使用以下任何方法引用包含构建中包含的任务都会导致执行时错误

  • finalizedBy

  • mustRunAfter

  • shouldRunAfter

从没有后备文件的资源创建 TAR 树

从没有后备文件的资源创建 TAR 树不再受支持。相反,将资源转换为文件,并在该文件上使用 project.tarTree()。有关更多信息,请参阅 没有后备文件的资源的 TAR 树

使用无效的 Java 工具链规范

不再支持使用无效的 Java 工具链规范。通过确保在所有工具链规范上都设置了语言版本,可以避免相关的构建错误。有关更多信息,请参阅 用户手册

在未配置存储库的情况下使用自动工具链下载

不再支持在未明确提供要使用的存储库的情况下进行自动工具链下载。有关更多信息,请参阅 用户手册

在设置测试框架选项后更改测试框架现在是一个错误

在为 Java、Groovy 和 Scala 项目配置内置测试任务时,Gradle 不再允许你在配置选项后更改 Test 任务使用的测试框架。这已被弃用,因为它在某些情况下会静默丢弃配置。

以下代码示例现在会产生错误

test {
   options {
   }

   useJUnitPlatform()
}

相反,你可以

test {
   // select test framework before configuring options
   useJUnitPlatform()
   options {
   }
}

此外,将测试框架多次设置为相同框架现在会累积可能在框架上设置的任何选项。以前,每次设置框架时,都会导致框架选项被覆盖。

以下代码现在会导致 test 任务包含“foo”和“bar”这两个标记

test {
   useJUnitPlatform {
        includeTags("foo")
   }
}
tasks.withType(Test).configureEach {
   // previously, this would overwrite the included tags to only include "bar"
   useJUnitPlatform {
        includeTags("bar")
   }
}

已删除的 API

旧版 ArtifactTransform API

旧版 ArtifactTransform API 已被删除。有关更多信息,请参阅 注册扩展 ArtifactTransform 的工件转换

旧版 IncrementalTaskInputs API

旧版 IncrementalTaskInputs API 已被删除。有关更多信息,请参阅 IncrementalTaskInputs 类型已弃用。此更改还影响 Kotlin Gradle 插件和 Android Gradle 插件。使用 Gradle 8.0,你应该使用 Kotlin Gradle 插件 1.6.10 或更高版本以及 Android Gradle 插件 7.3.0 及更高版本,其中包含 android.experimental.legacyTransform.forceNonIncremental=true 属性。

旧版 AntlrSourceVirtualDirectory API

旧版 AntlrSourceVirtualDirectory API 已被移除。此更改会影响 antlr 插件。在 Gradle 8.0 及更高版本中,请改用 AntlrSourceDirectorySet 源集扩展。

JvmPluginsHelper

JvmPluginsHelper 类的弃用方法 configureDocumentationVariantWithArtifact(不需要 FileResolver)已移除。这是一个内部 API,但插件可能已访问过它。请向此方法的重载版本提供 FileResolver

Groovydoc API 清理

Groovydoc 任务类型的弃用属性 isIncludePrivate 已移除。请改用 access 属性和 GroovydocAccess#PRIVATE 常量。

JavaApplication API 清理

JavaApplication 接口的弃用属性 mainClassName 已移除。请改用 mainClass 属性。

DefaultDomainObjectSet API 清理

弃用构造函数 DefaultDomainObjectSet(Class) 已移除。这是一个内部 API,但插件可能已使用过它。

JacocoPluginExtension API 清理

JacocoPluginExtension 的弃用属性 reportsDir 已移除。请改用 reportsDirectory 属性。

DependencyInsightReportTask API 清理

DependencyInsightReportTask 任务类型的弃用属性 legacyShowSinglePathToDependnecy 已移除。请改用 showSinglePathToDependency 属性。

Report 和 TestReport API 清理

Report 类型的弃用属性 destinationenabled 已移除。请改用 outputLocationrequired 属性。

TestReport 任务类型的弃用属性 testResultDirs 已移除。请改用 testResults 属性。

JacocoMerge 任务已移除

已弃用的 JacocoMerge 任务类型已删除。JacocoReport 任务中也提供相同的功能。

JavaExec API 清理

JavaExec 任务类型的已弃用 main 属性已删除。请改用 mainClass 属性。

AbstractExecTask API 清理

AbstractExecTask 任务类型的已弃用 execResult getter 属性已删除。请改用 executionResult getter 属性。

AbstractTestTask API 清理

AbstractTestTask 任务类型的已弃用 binResultsDir 属性已删除。请改用 binaryResultsDirectory 属性。

SourceDirectorySet API 清理

SourceDirectorySet 类型的已弃用 outputDir 属性已删除。请改用 destinationDirectory 属性。

VersionCatalog API 清理

VersionCatalog 类型的已弃用 findDependency(String) 方法和 dependencyAliases 属性已删除。请改用 findLibrary(String) 方法和 libraryAliases 属性。

VersionCatalogBuilder 类型的已弃用 alias(String) 方法已删除。请改用 library(String, String, String)plugin(String, String) 方法。

WorkerExecutor API 清理

WorkerExecutor 接口的已弃用 submit(Class, Action) 方法已删除。请改用通过 noIsolation()classLoaderIsolation()processIsolation() 方法获取 WorkQueue,然后改用 WorkQueue 上的 submit(Class, Action) 方法。

DependencySubstitution API 清理

DependencySubstitution 类型的内部 Substitution 类型的已弃用 with(ComponentSelector) 方法已删除。请改用 using(ComponentSelector) 方法。

AbstractArchiveTask API 清理

appendixarchiveNamearchivePathbaseNameclassifierdestinationDirextensionversion 属性已从 AbstractArchiveTask 任务类型中移除。请改用 archiveAppendixarchiveFileNamearchiveFilearchiveBaseNamearchiveClassifierdestinationDirectoryarchiveExtensionarchiveVersion 属性。

IdeaModule API 清理

testSourceDirstestResourceDirs 属性已从 IdeaModule 类型中移除。这会影响 org.gradle.plugins.ide.idea.model.IdeaModule 类型,而不是 org.gradle.tooling.model.idea.IdeaModule 类型。请改用 testSourcestestResources 属性。

AbstractCompile API 弃用

AbstractCompiledestinationDir 属性已弃用,在使用时会发出弃用警告。它现在计划在 Gradle 9.0 中移除。请改用 destinationDirectory 属性。

ResolvedComponentResult API 清理

ResolvedComponentResult 接口的 getVariant 方法已移除。请改用 getVariants 方法。

代码质量插件 API 清理

CheckstyleCodeNarcPmd 任务类型的 antBuilder 属性已移除。请改用 Project 类型的 ant 属性。

Usage API 清理

Usage 类型的 JAVA_API_CLASSESJAVA_API_JARSJAVA_RUNTIME_CLASSESJAVA_RUNTIME_JARSJAVA_RUNTIME_RESOURCES 公共字段已移除。这些值在 内部 JavaEcosystemSupport 类中提供,以兼容以前发布的模块,但不应用于任何新发布。

ExternalDependency API 清理

ExternalDependency 接口的 setForce(boolean) 方法已移除。请改用 version(Action) 方法配置严格版本。

从 Kotlin DSL 中移除构建扫描方法

build-scan 插件应用方法已从 Kotlin DSL 中移除。请改用 gradle-enterprise 方法。

Kotlin DSL 中已移除的配置扩展方法

Kotlin DSL 为 NamedDomainObjectProvider<Configuration> 添加了专门的扩展方法,这些方法在按名称查找配置时可用。这些扩展允许构建在直接使用 NamedDomainObjectProvider<Configuration> 实例时访问 Configuration 的某些属性

configurations.compileClasspath.files // equivalent to configurations.compileClasspath.get().files
configurations.compileClasspath.singleFile // equivalent to configurations.compileClasspath.get().singleFile

所有这些扩展都已从 API 中移除,但这些方法仍然可供针对较旧版本的 Gradle 编译的插件使用。

  • NamedDomainObjectProvider<Configuration>.addToAntBuilder

  • NamedDomainObjectProvider<Configuration>.all

  • NamedDomainObjectProvider<Configuration>.allArtifacts

  • NamedDomainObjectProvider<Configuration>.allDependencies

  • NamedDomainObjectProvider<Configuration>.allDependencyConstraints

  • NamedDomainObjectProvider<Configuration>.artifacts

  • NamedDomainObjectProvider<Configuration>.asFileTree

  • NamedDomainObjectProvider<Configuration>.asPath

  • NamedDomainObjectProvider<Configuration>.attributes

  • NamedDomainObjectProvider<Configuration>.buildDependencies

  • NamedDomainObjectProvider<Configuration>.contains

  • NamedDomainObjectProvider<Configuration>.copy

  • NamedDomainObjectProvider<Configuration>.copyRecursive

  • NamedDomainObjectProvider<Configuration>.defaultDependencies

  • NamedDomainObjectProvider<Configuration>.dependencies

  • NamedDomainObjectProvider<Configuration>.dependencyConstraints

  • NamedDomainObjectProvider<Configuration>.description

  • NamedDomainObjectProvider<Configuration>.exclude

  • NamedDomainObjectProvider<Configuration>.excludeRules

  • NamedDomainObjectProvider<Configuration>.extendsFrom

  • NamedDomainObjectProvider<Configuration>.fileCollection

  • NamedDomainObjectProvider<Configuration>.files

  • NamedDomainObjectProvider<Configuration>.filter

  • NamedDomainObjectProvider<Configuration>.getTaskDependencyFromProjectDependency

  • NamedDomainObjectProvider<Configuration>.hierarchy

  • NamedDomainObjectProvider<Configuration>.incoming

  • NamedDomainObjectProvider<Configuration>.isCanBeConsumed

  • NamedDomainObjectProvider<Configuration>.isCanBeResolved

  • NamedDomainObjectProvider<Configuration>.isEmpty

  • NamedDomainObjectProvider<Configuration>.isTransitive

  • NamedDomainObjectProvider<Configuration>.isVisible

  • NamedDomainObjectProvider<Configuration>.minus

  • NamedDomainObjectProvider<Configuration>.outgoing

  • NamedDomainObjectProvider<Configuration>.plus

  • NamedDomainObjectProvider<Configuration>.resolutionStrategy

  • NamedDomainObjectProvider<Configuration>.resolve

  • NamedDomainObjectProvider<Configuration>.resolvedConfiguration

  • NamedDomainObjectProvider<Configuration>.setDescription

  • NamedDomainObjectProvider<Configuration>.setExtendsFrom

  • NamedDomainObjectProvider<Configuration>.setTransitive

  • NamedDomainObjectProvider<Configuration>.singleFile

  • NamedDomainObjectProvider<Configuration>.state

  • NamedDomainObjectProvider<Configuration>.withDependencies

您应该优先直接引用 Configuration 中的方法。

潜在的重大更改

JavaForkOptions getJvmArgs()getAllJvmArgs() 返回不可变列表

JavaForkOptions 接口检索的 JVM 参数列表现在不可变。

以前,对返回列表的修改会被静默忽略。

可空注释更好地反映 API 的实际可空性

在某些 API 中,可空性未正确注释,而允许空值或返回空值的 API 被标记为非空。在 Java 或 Groovy 中,此不匹配不会在编译时导致问题。在 Kotlin 中,此不匹配使得编写有效代码变得困难,因为该语言不允许您传递空值。

一个特别的示例是从 Provider#mapProvider#flatMap 返回 null。在这两个 API 中,Gradle 允许您返回 null,但在 Kotlin DSL 中,这被认为是非法的。

此更正可能会导致预期非空值的代码出现编译错误。

插件、任务和扩展类是抽象的

大多数用于插件、任务和扩展的公共类已变为抽象类。这样做是为了更轻松地从 Gradle 的实现中移除样板代码。

受此更改影响的插件也应使其类变为抽象类。只要对象是通过 ObjectFactory 或其他自动机制(如 托管属性)实例化的,Gradle 便会使用运行时类装饰来实现抽象方法。这些方法不应直接实现。

包装器任务配置

如果 gradle-wrapper.properties 包含 distributionSha256Sum 属性,则必须指定一个和值。可以在包装任务配置中或使用 --gradle-distribution-sha256-sum 任务选项指定和值。

AbstractCodeQualityPlugin 类中的更改

已弃用的 AbstractCodeQualityPlugin.getJavaPluginConvention() 方法已在 Gradle 8.0 中移除。您应该改用 JavaPluginExtension

移除 Gradle 工作程序的隐式 --add-opens

在 Gradle 8.0 之前,JDK9+ 上的 Gradle 工作程序通过传递 --add-opens CLI 参数自动打开了 JDK 模块 java.base/java.utiljava.base/java.lang。这使在 Gradle 工作程序中执行的代码能够对 JDK 内部进行深度反射,而不会发出警告或失败。工作程序不再使用这些隐式参数。

这会影响所有内部 Gradle 工作程序,这些工作程序用于各种任务

  • 代码质量插件(Checkstyle、CodeNarc、Pmd)

  • ScalaDoc

  • AntlrTask

  • JVM 编译器守护进程

  • 使用 工作程序 API 通过进程隔离执行的任务

在任何使用工作程序 API 对 JDK 内部进行深度反射的工具、扩展或插件中都可能会出现新的警告和错误。

可以通过更新违规代码或依赖项来解决这些错误。更新可能包括

  • 代码质量工具

  • 注释处理器

  • 任何使用工作程序 API 的 Gradle 插件

有关由于此更改可能出现的可能错误或警告输出的一些示例,请参阅 移除测试工作程序的隐式 --add-opens

SourceSet classesDirs 不再依赖于整个 SourceSet 作为任务依赖项

在 Gradle 8.0 之前,SourceSetOutput.classesDirs 的任务依赖项包括不生成类文件的任务。这意味着依赖于 classesDirs 的任务还将依赖于 classesprocessResources 以及添加到 SourceSetOutput 的任何其他任务依赖项。此行为可能是一个错误,因为 classesDirs 属性不包含 processResources 的输出。从 8.0 开始,此隐式依赖项已删除。现在,依赖于 classesDirs 仅执行在类目录中直接生成文件的任务。

考虑以下构建脚本

plugins {
    id 'java-library'
}
// Task lists all files in the given classFiles FileCollection
tasks.register("listClassFiles", ListClassFiles) {
    classFiles.from(java.sourceSets.main.output.classesDirs)
}

以前,listClassFiles 任务依赖于 compileJavaprocessResourcesclasses。现在,只有 compileJavalistClassFiles 的任务依赖项。

如果构建中的任务依赖于以前的行为,则可以改用整个 SourceSetOutput 作为输入,其中包含所有类和资源。

如果不可行,则可以通过向 classesDirs 添加更多任务依赖项来恢复以前的行为

java {
    sourceSets {
        main {
            output.classesDirs.builtBy(output)
        }
    }
}

最低支持的 Kotlin Gradle 插件版本已更改

Gradle 7.x 支持 Kotlin Gradle 插件 1.3.72 及更高版本。Kotlin Gradle 插件 1.6.21 以上的版本未通过 Gradle 7.x 测试。Gradle 8.x 支持 Kotlin Gradle 插件 1.6.10 及更高版本。你可以通过修改 Kotlin 编译任务中的语言版本和 API 版本设置来使用较低的 Kotlin 语言版本。

最低支持的 Android Gradle 插件版本已更改

Gradle 7.x 支持 Android Gradle 插件 (AGP) 4.1 及更高版本。AGP 7.3 以上的版本未通过 Gradle 7.x 测试。Gradle 8.x 支持 AGP 8 及更高版本。如果你配置以下属性,Gradle 8.x 支持 AGP 7.3 及更高版本

android.experimental.legacyTransform.forceNonIncremental=true

更改为 AntBuilder 父类

以前,org.gradle.api.AntBuilder 扩展了已弃用的 groovy.util.AntBuilder 类。现在,它扩展了 groovy.ant.AntBuilder

PluginDeclaration 不可序列化

org.gradle.plugin.devel.PluginDeclaration 不再可序列化。如果你需要序列化它,可以将其转换为你自己的可序列化类。

Gradle 不在最新检查中对序列化值使用 equals

Gradle 现在不会尝试在最新检查中比较序列化值时使用 equals。有关更多信息,请参阅 依赖 equals 进行最新检查已弃用

Gradle 7.x 中引入的任务和转换验证警告现在是错误

Gradle 在 Gradle 7.x 系列中引入了其他任务和工件转换验证警告。这些警告现在是 Gradle 8.0 中的错误,并且将导致构建失败。

变为错误的警告

Gradle 不会忽略带有 @SkipWhenEmpty 的文件树的空目录

以前,Gradle 用于检测带有 @SkipWhenEmpty 注释的输入文件集合是否仅由文件树组成,然后自动忽略目录。要在 Gradle 8.0 及更高版本中忽略目录,需要使用 @IgnoreEmptyDirectories 显式注释输入属性。有关更多信息,请参阅 文件树和空目录处理

JavaVersion 的格式已针对 Java 9 和 Java 10 更改

JavaVersion 的字符串格式已更改为与官方 Java 版本控制相匹配。从 Java 9 开始,语言版本不得包含 1. 前缀。这会影响 JavaCompile 任务和 JavaExtension 上的 sourceCompatiblitytargetCompatibility 属性的格式。从字符串解析 JavaVersion 时,仍支持旧格式。

Gradle 7.6

Gradle 8.0

1.8

1.8

1.9

9

1.10

10

11

11

预编译脚本插件默认使用严格的 Kotlin DSL 访问器生成

在预编译脚本插件中,如果插件无法应用,类型安全的 Kotlin DSL 访问器生成现在会使构建失败。

从 Gradle 7.6 开始,构建可以使用 org.gradle.kotlin.dsl.precompiled.accessors.strict 系统属性启用此行为。此行为现在是默认行为。该属性已弃用,应删除其用法。您可以在下方找到有关此属性的更多信息。

初始化脚本应用于 buildSrc 构建

现在使用 --init-script 指定的初始化脚本应用于 buildSrc 构建。在以前的版本中,这些脚本应用于包含的构建,但不应用于 buildSrc 构建。

此行为现在对于 buildSrc 和包含的构建是一致的。

Gradle 不再为 buildSrc 构建运行 build 任务

当 Gradle 构建 buildSrc 的输出时,它只运行生成该输出的任务,该任务通常是 jar 任务。在以前的版本中,Gradle 会运行 build 任务。

这意味着 buildSrc 及其子项目的测试不会自动构建和执行,现在必须显式请求。

此行为现在对于 buildSrc 和包含的构建是一致的。

您可以像包含构建中的项目一样运行 buildSrc 的测试,例如通过运行 gradle buildSrc:build

buildFinished { } 钩子在所有任务执行后为 buildSrc 运行

buildSrcbuildFinished {} 钩子现在在所有任务完成后运行。在以前的版本中,此钩子会在 buildSrc 的任务完成后立即运行,并且在任何请求的任务开始之前运行。

此行为现在对于 buildSrc 和包含的构建是一致的。

包含的构建的路径更改

为了更好地处理嵌套的包含构建名称之间的冲突,Gradle 现在使用包含构建的目录层次结构来分配构建路径。如果您在嵌套的包含构建中从命令行运行任务,则可能需要调整您的调用。

例如,如果您有以下层次结构

.
├── settings.gradle.kts
└── nested
    ├── settings.gradle.kts
    └── nestedNested
        └── settings.gradle.kts
settings.gradle.kts
includeBuild("nested")
nested/settings.gradle.kts
includeBuild("nestedNested")
.
├── settings.gradle
└── nested
    ├── settings.gradle
    └── nestedNested
        └── settings.gradle
settings.gradle
includeBuild("nested")
nested/settings.gradle
includeBuild("nestedNested")

在 Gradle 8.0 之前,你运行了 gradle :nestedNested:compileJava。在 Gradle 8.0 中,调用更改为 gradle :nested:nestedNested:compileJava

使用 eclipse wtp 插件添加 jst.ejb 现在会移除 jst.utility 构面

eclipse wtp 插件会向 Java 项目添加 jst.utility 构面。现在,添加 jst.ejb 构面会隐式移除 jst.utility 构面

eclipse {
    wtp {
        facet {
            facet name: 'jst.ejb', version: '3.2'
        }
    }
}

简化 PMD 自定义规则配置

以前,你必须使用 ruleSets = [] 显式配置 PMD 以忽略默认规则。在 Gradle 8.0 中,将 ruleSetConfigruleSetFiles 设置为非空值会隐式忽略默认规则。

报告 getOutputLocation 返回类型从 Provider 更改为 Property

报告outputLocation 属性现在返回类型为 Property<? extends FileSystemLocation> 的值。以前,outputLocation 返回类型为 Provider<? extends FileSystemLocation> 的值。

此更改使报告 API 在内部更加一致,并允许对报告任务进行更惯用的配置。

以前,现在 @Deprecated 用法

tasks.named('test') {
    reports.junitXml.setDestination(layout.buildDirectory.file('reports/my-report-old').get().asFile) // DEPRECATED
}

可以用以下内容替换

tasks.named('test') {
    reports.junitXml.outputLocation = layout.buildDirectory.dir('reports/my-report')
}

许多内置和自定义报告(例如 JUnit 使用的报告)都实现了此接口。针对包含先前方法签名的早期 Gradle 版本编译的插件可能需要重新编译才能与包含新签名的较新 Gradle 版本一起使用。

已移除外部插件验证插件

孵化插件 ExternalPluginValidationPlugin 已被移除。使用 java-gradle-pluginvalidatePlugins 任务来验证正在开发的插件。

与过去版本相比,可再现存档可能会发生变化

Gradle 将用于创建存档的压缩库从基于 Ant 的库更改为 Apache Commons Compress™。因此,由相同内容创建的存档不太可能与使用旧库创建的旧版本逐字节完全相同。

升级到 Kotlin 1.8.10

已将嵌入式 Kotlin 更新到 Kotlin 1.8.10。另请参阅 Kotlin 1.8.0 发行说明。有关更多信息,请参阅 Kotlin 的发行说明

将 Kotlin DSL 更新到 Kotlin API 级别 1.8

以前,Kotlin DSL 使用 Kotlin API 级别 1.4。从 Gradle 8.0 开始,Kotlin DSL 使用 Kotlin API 级别 1.8。此更改带来了自 Kotlin 1.4.0 以来对 Kotlin 语言和标准库所做的所有改进。

有关此升级中中断和非中断更改的信息,请参阅以下链接以获取 Kotlin 文档

请注意,Kotlin Gradle 插件 1.8.0 已开始使用 Java 工具链。建议您配置工具链,而不是在 Kotlin 项目中定义 Java sourceCompatibility/targetCompatibility

另请注意,Kotlin Gradle 插件 1.8.0 引入了带有惰性配置属性的 compilerOptions,以替换不支持惰性配置的 kotlinOptions。建议您使用 compilerOptions 而不是 kotlinOptions 来配置 Kotlin 编译。

kotlinDslPluginOptions.jvmTarget 已弃用

以前,您可以在使用 kotlin-dsl 插件时使用 kotlinDslPluginOptions.jvmTarget 来配置用于编译代码的 JVM 目标。

从 Gradle 8.0 开始,kotlinDslPluginOptions.jvmTarget 已弃用。您应该改为 配置 Java 工具链

如果您已经配置了 Java 工具链并且未设置 kotlinDslPluginOptions.jvmTarget,那么 Gradle 8.0 现在将使用 Java 工具链作为 JVM 目标,而不是以前的默认目标 (1.8)。

Java Base 插件现在设置 Jar、War 和 Ear 目标目录默认值

以前,base 插件将 destinationDirectoryJarWarEar 任务配置为 BasePluginExtension#getLibsDirectory 指定的目录。在 Gradle 8.0 中,java-base 处理此配置。对于已经直接或通过 javaapplicationjava-library 或其他 JVM 生态系统插件间接应用 java-base 插件的项目,无需进行任何更改。

不应使用上传任务

Upload 任务仍然已弃用,现已计划在 Gradle 9.0 中移除。尽管此类型仍然存在,但它不再具有功能,并且在运行时会抛出异常。它仅保留下来以避免破坏插件。请改用 maven-publishivy-publish 插件中的任务。

不再允许将配置作为依赖项

dependencies DSL 块中将配置添加为依赖项,或使用 DependencyHandler 类的 doAdd(Configuration, Object, Closure) 方法以编程方式添加,不再被允许,并且会引发异常。若要复制此行为的许多方面,请改用 Configuration 上的 extendsFrom(Configuration) 方法扩展配置。

已弃用的供消耗配置现在不可消耗

以下配置从不打算被消耗

  • AntlrPlugin 创建的 antlr 配置

  • ScalaBasePlugin 创建的 zinc 配置

  • WarPlugin 创建的 providedCompileprovidedRuntime 配置

这些配置已被弃用以供消耗,现在不再可消耗。尝试消耗它们将导致错误。

相同的可消耗配置现在是一个错误

如果一个项目有多个可消耗配置共享相同的属性和功能声明,则在发布或解析为依赖项时,项目构建将失败。这 以前已弃用

outgoingVariants 报告将针对受影响的配置发出警告。

面向 JVM 项目的基于工具链的任务

从 Gradle 8.0 开始,所有具有工具链支持的核心 Java 任务现在无条件地使用工具链。如果应用了 JavaBasePlugin,则任务上工具属性的约定值由 java 扩展上配置的工具链定义。如果没有明确配置任何工具链,则使用与运行 Gradle 的 JVM 相对应的工具链。

类似地,Groovy 和 Scala 插件中的任务也依赖于工具链来确定在哪个 JVM 上执行它们。

Scala 编译目标

随着上面描述的工具链更改,Scala 编译任务现在始终提供 targetrelease 参数。确切的参数和值取决于工具链的使用情况(或不使用)和 Scala 版本。

有关详细信息,请参阅Scala 插件文档

pluginBundle 已从 Plugin Publish 插件中删除

Gradle 8 不再支持 pluginBundle 扩展。其功能已合并到 gradlePlugin 块中。这些更改需要较新版本的 Plugin Publish 插件 (1.0.+)。有关配置插件发布的文档可在 Portal用户手册 中找到。

从 7.5 及更早版本升级

AttributeSchema.setAttributeDisambiguationPrecedence(List)AttributeSchema.getAttributeDisambiguationPrecedence() 方法现在接受并返回 List 而不是 Collection,以更好地表明这些集合中元素的顺序很重要。

严格 Kotlin DSL 预编译脚本访问器生成

对于预编译脚本插件,类型安全的 Kotlin DSL 访问器生成在默认情况下不会使构建失败,即使在这些预编译脚本中请求的插件无法应用。由于原因可能是环境因素,并且出于向后兼容性的考虑,此行为尚未更改。

回到 Gradle 7.1,负责访问器生成的 :generatePrecompiledScriptPluginAccessors 任务默认情况下已标记为不可缓存。引入了 org.gradle.kotlin.dsl.precompiled.accessors.strict 系统属性,以便选择更严格的操作模式,即在插件应用失败时使构建失败,并为该任务启用构建缓存。

从 Gradle 7.6 开始,Kotlin DSL 预编译脚本插件的非严格访问器生成已弃用。这将在 Gradle 8.0 中发生更改。严格访问器生成将成为默认设置。若要选择严格行为,请将“org.gradle.kotlin.dsl.precompiled.accessors.strict”系统属性设置为 true

这可以在构建根目录中的 gradle.properties 文件中永久实现

systemProp.org.gradle.kotlin.dsl.precompiled.accessors.strict=true

潜在的破坏性更改

升级到 Kotlin 1.7.10

嵌入式 Kotlin 已更新到 Kotlin 1.7.10

Gradle 不附带 kotlin-gradle-plugin,但升级到 1.7.10 可以带来新版本。例如,当您使用 kotlin-dsl 插件时。

kotlin-gradle-plugin 版本 1.7.10 更改了 KotlinCompile 任务类型的类型层次结构。它不再从 AbstractCompile 扩展。如果您过去通过 AbstractCompile 选择 Kotlin 编译任务,则需要将其更改为 KotlinCompile

例如,此

tasks.named<AbstractCompile>("compileKotlin")

需要更改为

tasks.named<KotlinCompile>("compileKotlin")

同样,如果您过去通过 AbstractCompile 过滤任务,您将不再获得 Kotlin 编译任务

tasks.withType<AbstractCompile>().configureEach {
    // ...
}

需要更改为

tasks.withType<AbstractCompile>().configureEach {
    // ...
}
tasks.withType<KotlinCompile>().configureEach {
    // ...
}

升级到 Groovy 3.0.13

Groovy 已更新到 Groovy 3.0.13

由于之前的版本是 3.0.10,因此 3.0.113.0.12 更改也包括在内。

升级到 CodeNarc 3.1.0

CodeNarc 的默认版本已更新到 3.1.0

升级到 PMD 6.48.0

PMD 已更新到 PMD 6.48.0

配置不存在的可执行文件现在会失败

当为 JavaCompileTest 任务明确配置可执行文件时,如果此可执行文件不存在,Gradle 现在将发出错误。过去,该任务将使用运行构建的默认工具链或 JVM 执行。

测试套件中依赖项声明的更改

作为不断发展测试套件的一部分,测试套件 dependencies 块中的依赖项声明现在是强类型。这将有助于使此孵化 API 在 IDE 中更易于发现和使用。

在某些情况下,这需要语法更改。例如,以前使用以下语法添加测试套件依赖项的构建脚本

testing {
  suites {
    register<JvmTestSuite>("integrationTest") {
      dependencies {
        implementation(project)
      }
    }
  }
}

现在将无法编译,并显示类似以下内容的消息

None of the following functions can be called with the arguments supplied:
public operator fun DependencyAdder.invoke(dependencyNotation: CharSequence): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(dependency: Dependency): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(files: FileCollection): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(dependency: Provider<out Dependency>): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(externalModule: ProviderConvertible<out MinimalExternalModuleDependency>): Unit defined in org.gradle.kotlin.dsl

要解决此问题,请将对 project 的引用替换为对 project() 的调用

testing {
  suites {
    register<JvmTestSuite>("integrationTest") {
      dependencies {
        implementation(project())
      }
    }
  }
}

受此更改影响的其他语法包括

  • 您不能将 Provider<String> 用作依赖项声明。

  • 您不能将 Map 用作 Kotlin 或 Java 的依赖项声明。

  • 您不能直接将包用作依赖项声明(implementation(libs.bundles.testing))。请改用 implementation.bundle(libs.bundles.testing)

有关更多信息,请参见用户指南的 JVM 测试套件插件部分中更新的 声明附加测试套件 示例以及 DSL 参考中的 DependencyAdder 页面。

弃用

现在已弃用无效 Java 工具链规范的使用

除了 Java 语言版本之外,Java 工具链 DSL 允许配置其他条件,例如特定供应商或 VM 实现。从 Gradle 7.6 开始,在未指定语言版本的情况下配置其他属性的工具链规范被视为无效。无效规范已弃用,并且将在 Gradle 8.0 中变为构建错误。

有关工具链配置的更多详细信息,请参见 用户手册

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

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

  • ClosureBackedAction

  • CollectionUtils

  • ConfigureUtil

  • DistributionLocator

  • GFileUtils

  • GradleVersion.getBuildTime()

  • GradleVersion.getNextMajor()

  • GradleVersion.getRevision()

  • GradleVersion.isValid()

  • GUtil

  • NameMatcher

  • NameValidator

  • RelativePathUtil

  • TextUtil

  • SingleMessageLogger

  • VersionNumber

  • WrapUtil

内部 DependencyFactory 已重命名

内部 org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory 类型已重命名为 org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactoryInternal。作为内部类型,不应使用它,但出于兼容性原因,内部 ClassPathNotation 类型仍然可用。此类型的名称已弃用,并且将在 Gradle 8.0 中删除。此功能的公共 API 在 DependencyHandler 上,其中 localGroovy() 等方法提供了相同的功能。

org.gradle.plugins.ide.idea.model.IdeaModule 中的替换集合

testResourcesDirstestSourcesDirs 字段及其 getter 和 setter 已弃用。请使用现在稳定的 getTestSources()getTestResources() 方法及其各自的 setter 替换用法。这些新方法返回并由 ConfigurableFileCollection 实例支持,以提高使用灵活性。Gradle 现在会在使用这些弃用方法时发出警告。它们将在 Gradle 的未来版本中删除。

org.gradle.api.tasks.testing.TestReport 中的替换方法

getDestinationDir()setDestinationDir(File)getTestResultDirs()setTestResultDirs(Iterable) 方法已弃用。请使用现在稳定的 getDestinationDirectory()getTestResults() 方法及其关联的 setter 替换用法。这些弃用元素将在 Gradle 的未来版本中删除。

在某些配置块中弃用对外部作用域方法的隐式引用

在 Gradle 7.6 之前,Groovy 脚本允许在抛出 `MissingMethodException` 的命名容器配置方法中访问根项目配置方法。请考虑以下代码段以了解此行为的示例

当提供的闭包对于 Configuration 而言是无效的配置闭包时,Gradle 允许从 configurations 块中访问顶级 repositories 块。在这种情况下,repositories 闭包执行就像在脚本级别调用一样,并创建一个未配置的 repositories Configuration

configurations {
    repositories {
        mavenCentral()
    }
    someConf {
        canBeConsumed = false
        canBeResolved = false
    }
}

此行为也适用于不会立即执行的闭包。在这种情况下,afterResolve 仅在 resolve 任务运行时执行。distributions 闭包是一个有效的顶级脚本闭包。但它对于 Configuration 而言是一个无效的配置闭包。此示例立即创建 conf Configuration。在 resolve 任务执行期间,distributions 块执行就像在脚本级别声明一样

configurations {
    conf.incoming.afterResolve {
        distributions {
            myDist {
                contents {}
            }
        }
    }
}

task resolve {
    dependsOn configurations.conf
    doFirst {
        configurations.conf.files() // Trigger `afterResolve`
    }
}

从 Gradle 7.6 开始,此行为已弃用。从 Gradle 8.0 开始,此行为将被删除。相反,Gradle 将抛出基础 MissingMethodException。为了缓解此更改,请考虑以下解决方案

configurations {
    conf.incoming.afterResolve {
        // Fully qualify the reference.
        project.distributions {
            myDist {
                contents {}
            }
        }
    }
}
configurations {
    conf
}

// Extract the script-level closure to the script root scope.
configurations.conf.incoming.afterResolve {
    distributions {
        myDist {
            contents {}
        }
    }
}

从 7.4 及更早版本升级

IncrementalTaskInputs 类型已弃用

IncrementalTaskInputs 类型用于实现增量任务,也就是说,可以针对已更改输入的子集而不是整个输入进行优化以运行的任务。此类型有一些缺点。特别是使用此类型无法确定更改与哪个输入相关联。

现在,您应该改用 InputChanges 类型。有关更多详细信息,请参阅关于实现增量任务的用户指南部分

潜在的重大变更

版本目录仅接受一个 TOML 导入文件

使用 from 导入方法时,将只接受一个文件。这意味着解析为多个文件(例如 Project.files(java.lang.Object…​) 方法,当传递多个文件时)的符号将导致构建失败。

默认工具集成版本的更新

eclipse 插件生成的类路径文件已更改

在测试配置中定义的项目依赖关系获取 test=true 类路径属性。JVM 测试套件插件定义的所有源集和依赖关系在默认情况下也标记为测试代码。现在,您可以通过 eclipse 插件 DSL 自定义测试源集和依赖关系。

eclipse {
    classpath {
        testSourceSets = [sourcesSets.test, sourceSets.myTestSourceSet]
        testConfigurations = [configuration.myTestConfiguration]
    }
}

或者,您可以在 eclipse.classpath.file.whenMerged { } 块中调整或删除类路径属性。

使用 GPG 命令时,签名插件默认为 gpg,而不是 gpg2

签名插件的默认可执行文件 在使用 GPG 命令时 已从 gpg2 更改为 gpg。此更改的动机是 GPG 2.x 已变得稳定,并且发行版已开始迁移,不再链接 gpg2 可执行文件。

为了设置旧默认值,可以在 gradle.properties 中手动定义可执行文件

signing.gnupg.executable=gpg2

mustRunAfter 约束不再受 finalizedBy 依赖关系的违反

在之前的 Gradle 版本中,常规任务和最终器任务依赖项之间的 mustRunAfter 约束不会得到遵守。

对于一个具体的示例,请考虑以下任务图定义

tasks {
    register("dockerTest") {
        dependsOn("dockerUp")     // dependsOn createContainer mustRunAfter removeContainer
        finalizedBy("dockerStop") // dependsOn removeContainer
    }

    register("dockerUp") {
        dependsOn("createContainer")
    }

    register("dockerStop") {
        dependsOn("removeContainer")
    }

    register("createContainer") {
        mustRunAfter("removeContainer")
    }

    register("removeContainer") {
    }
}

相关的约束是

  • dockerStopdockerTest 的最终器,因此它必须在 dockerTest 之后运行;

  • removeContainerdockerStop 的依赖项,因此它必须在 dockerStop 之前运行;

  • createContainer 必须在 removeContainer 之后运行;

在 Gradle 7.5 之前,gradle dockerTest 会产生以下执行顺序,违反了 :createContainer:removeContainer 之间的 mustRunAfter 约束

> Task :createContainer UP-TO-DATE
> Task :dockerUp UP-TO-DATE
> Task :dockerTest UP-TO-DATE
> Task :removeContainer UP-TO-DATE
> Task :dockerStop UP-TO-DATE

从 Gradle 7.5 开始,mustRunAfter 约束得到完全遵守,产生以下执行顺序

> Task :removeContainer UP-TO-DATE
> Task :createContainer UP-TO-DATE
> Task :dockerUp UP-TO-DATE
> Task :dockerTest UP-TO-DATE
> Task :dockerStop UP-TO-DATE

Scala Zinc 版本更新到 1.6.1

Zinc 是 Scala 增量编译器,它允许 Gradle 始终编译当前文件更改所需的最小文件集。它会考虑正在使用哪些方法以及哪些方法已更改,这意味着它比仅仅考虑文件间依赖关系要精细得多。

Zinc 版本已更新到最新的可用版本,以便从所有最近的错误修复中受益。因此,如果你使用 zincVersion 设置,建议将其删除并仅使用默认版本,因为 Gradle 将只能使用设置为 1.6.x 或更高版本的 Zinc 编译 Scala 代码。

移除测试工作者的隐式 --add-opens

在 Gradle 7.5 之前,JDK 模块 java.base/java.utiljava.base/java.lang 在 JDK9+ 中的测试工作者中通过传递 --add-opens CLI 参数自动打开。这意味着任何测试都可以对 JDK 内部进行深度反射,而无需警告或失败。这导致测试不可靠,因为它允许代码在生产环境中失败时通过。

这些隐式参数已删除,不再默认添加。如果你的代码或任何依赖项在测试执行期间对 JDK 内部执行深度反射,你可能会看到以下行为更改

在 Java 16 之前,将显示新的构建警告。这些新警告将打印到 stderr,并且不会导致构建失败

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.ReflectUtils$2 (file:/.../testng-5.12.1.jar) to <method>
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.ReflectUtils$2
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

在 Java 16 或更高版本中,将抛出导致构建失败的异常

// Thrown by TestNG
java.lang.reflect.InaccessibleObjectException: Unable to make <method> accessible: module java.base does not "opens java.lang" to unnamed module @1e92bd61
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
    ...

// Thrown by ProjectBuilder
org.gradle.api.GradleException: Could not inject synthetic classes.
	at org.gradle.initialization.DefaultLegacyTypesSupport.injectEmptyInterfacesIntoClassLoader(DefaultLegacyTypesSupport.java:91)
	at org.gradle.testfixtures.internal.ProjectBuilderImpl.getGlobalServices(ProjectBuilderImpl.java:182)
	at org.gradle.testfixtures.internal.ProjectBuilderImpl.createProject(ProjectBuilderImpl.java:111)
	at org.gradle.testfixtures.ProjectBuilder.build(ProjectBuilder.java:120)
	...
Caused by: java.lang.RuntimeException: java.lang.IllegalAccessException: module java.base does not open java.lang to unnamed module @1e92bd61

在大多数情况下,可以通过更新执行非法访问的代码或依赖项来解决这些错误。如果待测代码或有问题的依赖项的最新版本按设计执行非法访问,则可以通过使用 --add-opens 手动打开 java.base/java.lang 和 java.base/java.util 模块来恢复旧行为

tasks.withType(Test).configureEach {
    jvmArgs(["--add-opens=java.base/java.lang=ALL-UNNAMED",
             "--add-opens=java.base/java.util=ALL-UNNAMED"]
}

如果你正在开发 Gradle 插件,则 ProjectBuilder 依赖于 java.base/java.lang 模块中的反射。当应用 java-gradle-plugin 插件时,Gradle 会自动将适当的 --add-opens 标志添加到测试中。

如果你正在使用 TestNG,则 5.14.6 之前的版本执行非法反射。更新到至少 5.14.6 应该可以修复不兼容性。

Checkstyle 任务默认情况下使用工具链并并行执行

Checkstyle 插件 现在使用 Gradle 工作器 API 将 Checkstyle 作为外部工作器进程运行。现在,多个 Checkstyle 任务可以在项目中并行运行。

一些项目需要增加可供 Checkstyle 使用的内存量,以避免内存不足错误。你可以通过为 Checkstyle 任务设置 maxHeapSize 来增加 Checkstyle 进程的最大内存。默认情况下,进程将以 512MB 的最大堆大小启动。

我们还建议将 Checkstyle 更新到 9.3 或更高版本。

在运行 Checkstyle 时缺少使用相对路径指定的文件

Gradle 7.5 始终将 Checkstyle 任务的当前工作目录设置为 $GRADLE_USER_HOME/workers。这可能会导致自定义 Checkstyle 任务或假设相对路径的目录不同的 Checkstyle 配置文件出现问题。

以前,Gradle 根据你运行 Gradle 的目录选择当前工作目录。如果你在以下位置运行 Gradle:

  • 项目的根目录:Gradle 使用根目录作为当前工作目录。

  • 项目的嵌套目录:Gradle 使用子项目的根目录作为当前工作目录。

在 7.5 及更高版本中,Gradle 始终将 Checkstyle 任务的当前工作目录设置为 $GRADLE_USER_HOME/workers。

弃用

将文件转换为类路径,其中路径包含文件分隔符

Java 有路径分隔符的概念,用于分隔路径列表中的各个路径,例如在类路径字符串中。各个路径不得包含路径分隔符。因此,对包含路径分隔符的路径使用 @FileCollection.getAsPath() 已被弃用,并且在 Gradle 8.0 及更高版本中将成为错误。使用包含路径分隔符的路径的文件集合可能会导致构建不正确,因为 Gradle 找不到文件作为输入,甚至在包含路径分隔符的路径在操作系统上非法时导致构建失败。

dependencyInsight --singlepath 选项已弃用

为了一致性,已将其更改为 --single-path。API 方法保持不变,这仅影响 CLI。

Groovydoc includePrivate 属性已弃用

有一个新的 access 属性,它允许更精细地控制 Groovydoc 中包含的内容。

必须使用基于提供程序的 API 在配置时运行外部进程

在启用配置缓存时,使用 Project.execProject.javaexec 以及标准 Java 和 Groovy API 在配置时运行外部进程现在已弃用。在 Gradle 8.0 及更高版本中将成为错误。Gradle 7.5 引入了与配置缓存兼容的方式,可以使用 基于提供程序的 APIValueSource 接口的自定义实现来执行和获取外部进程的输出。配置缓存章节 有更多详细信息,以帮助迁移到新 API。

从 7.3 及更早版本升级

弃用

AdoptOpenJDK 工具链下载

随着从 AdoptOpenJDK 转移到 Eclipse 基金会旗下的 Adoptium,不再可能从其端点下载 AdoptOpenJDK 构建。相反,将返回 Eclipse Temurin 或 IBM Semeru 构建。

当在 工具链规范 中指定 AdoptOpenJDK 供应商并且自动配置使用它时,Gradle 7.4+ 现在会发出弃用警告。如果你必须使用 AdoptOpenJDK,则应该关闭自动下载。如果 Eclipse Temurin 或 IBM Semeru 构建对你有用,请指定 JvmVendorSpec.ADOPTIUMJvmVendorSpec.IBM 作为供应商,或不指定供应商。

文件树和空目录处理

在输入文件集合上使用 @SkipWhenEmpty 时,Gradle 会在确定输入为空时跳过任务。如果输入文件集合仅包含文件树,则 Gradle 会在空检查中忽略目录。不过,在检查输入文件集合的更改时,Gradle 仅在存在 @IgnoreEmptyDirectories 注释时才忽略目录。

现在,Gradle 会在 @SkipWhenEmpty 检查和确定更改时忽略目录,以保持一致性。在 Gradle 8.0 之前,Gradle 会检测用 @SkipWhenEmpty 注释的输入文件集合是否仅包含文件树,然后自动忽略目录。此外,Gradle 会发出弃用警告,建议用户在 Gradle 8.0 中更改行为,并且应该用 @IgnoreEmptyDirectories 注释输入属性。要在 Gradle 8.0 及更高版本中忽略目录,需要用 @IgnoreEmptyDirectories 注释输入属性。

最后,使用 @InputDirectory 暗示 @IgnoreEmptyDirectories,因此在使用此注释时无需进行任何更改。通过运行时 API 注册输入目录时,对于 inputs.dir() 也是如此。

不使用 FileResolver 而使用 LazyPublishArtifact 已弃用

在不使用 FileResolver 而使用 LazyPublishArtifact 时,会使用不同的文件解析策略,该策略会复制 FileResolver 中的一些逻辑。

为了提高一致性,应该将 LazyPublishArtifact 与 FileResolver 一起使用,并且将来需要它。

这也影响了使用 LazyPublishArtifact 的其他内部 API,现在这些 API 在需要时也会有弃用警告。

没有后备文件的资源中的 TAR 树

可以从任意资源创建 TAR 树。如果资源不是通过 project.resources 创建的,则它可能没有后备文件。已弃用从没有后备文件的资源创建 TAR 树。相反,将资源转换为文件,并在该文件上使用 project.tarTree()。要将资源转换为文件,可以使用自定义任务或使用依赖项管理通过 URL 下载文件。这样,Gradle 能够应用优化,例如最新检查,而不是每次都重新运行逻辑来创建资源。

唯一属性集

与项目中可消耗配置关联的 Attribute 集在该项目中所有其他配置中必须是唯一的,这些配置共享相同的 Capability 集。

这将在配置变体配置的末尾进行检查,因为它们被锁定以防止进一步的更改。

如果属性集在配置之间共享,请考虑为其中一个变体添加一个附加属性,其唯一目的是消除歧义。

Provider#forUseAtConfigurationTime() 已弃用

Provider#forUseAtConfigurationTime 现已弃用,并计划在 Gradle 9.0 中移除。客户端应直接移除调用。

对于外部值的提供程序(例如 系统属性环境变量Gradle 属性文件内容)的调用是强制性的,这些值旨在与配置缓存功能一起在配置时使用。

从 7.4 版开始,Gradle 将隐式地将配置时使用的外部值视为配置缓存输入。

客户端还可以自由使用标准 Java API(例如 System#getenv)来读取环境变量,使用 System#getProperty 来读取系统属性以及 Gradle API(例如 Project#property(String)Project#findProperty(String))来在配置时读取 Gradle 属性。基于 Provider 的 API 仍然是将外部值连接到任务输入以最大程度地重用配置缓存的推荐方式。

任务执行侦听器和事件

Gradle 配置缓存不支持直接访问 TaskProject 实例的侦听器和事件,这允许 Gradle 并行执行任务并在配置缓存中存储最少量的数据。为了实现一个在启用或不启用配置缓存时都一致的 API,以下 API 已弃用,将在 Gradle 8.0 中移除或变为错误

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

构建完成事件

Gradle 配置缓存不支持构建完成侦听器。因此,以下 API 已弃用,将在 Gradle 8.0 中移除

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

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

在执行时从任务操作中调用 Task.getProject() 已弃用,并且将在 Gradle 8.0 中变成错误。此方法可以在配置期间使用,但建议避免这样做。

请参阅 配置缓存章节,了解如何将这些用法迁移到配置缓存支持的 API。

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

在执行时从任务操作中调用 Task.getTaskDependencies() 已弃用,并且将在 Gradle 8.0 中变成错误。此方法可以在配置期间使用,但建议避免这样做。

请参阅 配置缓存章节,了解如何将这些用法迁移到配置缓存支持的 API。

在没有相应的 Task.usesService 声明的情况下从任务中使用构建服务

Gradle 需要这些信息,以便它可以正确遵守构建服务的生命周期及其使用约束。

这将在未来的 Gradle 版本中变成错误。

请查看 共享构建服务文档 了解更多信息。

VersionCatalog 和 VersionCatalogBuilder 弃用

VersionCatalogVersionCatalogBuilder 中的一些方法现已弃用,并计划在 Gradle 8.0 中移除。可以在受影响方法的 JavaDoc 中找到具体的替换方法。

这些方法的更改是为了提高 libs.versions.toml 文件和 API 类之间的一致性。

从 7.2 及更早版本升级

潜在的重大更改

捆绑的 Gradle 依赖项更新

plugins 块中插件的应用顺序

plugins 块中插件的实际应用顺序不一致,并且取决于插件添加到类路径的方式。

现在,插件始终按照在 plugins 块中声明的顺序应用,在极少数情况下,这可能会改变现有构建的行为。

依赖项解析中排除对替换依赖项的影响

在此版本之前,无法从依赖项图中排除依赖项替换目标。这是由于在执行替换之前检查排除项造成的。现在,Gradle 还将检查替换结果中的排除项。

版本目录

生成的访问器不再提供对类型不安全 API 的访问。您必须改用 版本目录扩展

Scala 中的工具链支持

Scala 中使用工具链 时,现在将自动设置 Scala 编译器的 -target 选项。这意味着使用 Scala 版本无法针对的 Java 版本将导致错误。在编译器选项中提供此标志将禁用此行为,并允许使用更高版本的 Java 来编译较低字节码目标。

声明包含不可读内容的输入或输出目录

对于最新的检查,Gradle 依赖于跟踪任务的输入和输出状态。尽管 Gradle 无法跟踪不可读文件的状态,但它过去常常忽略输入或输出中的不可读文件以支持某些用例。在包含不可读内容的任务上声明输入或输出目录已被弃用,现在通过声明任务为未跟踪来支持这些用例。使用 @UntrackedTask 注释或 Task.doNotTrackState() 方法将任务声明为未跟踪。

当您使用Copy任务将单个文件复制到包含不可读文件的目录中时,请使用Task.doNotTrackState()方法。

从 7.1 及更早版本升级

潜在的重大更改

对应用程序启动脚本和 Gradle wrapper 脚本进行安全更改

由于CVE-2021-32751gradlegradlew和 Gradle 的应用程序插件生成的启动脚本已更新,以避免在攻击者能够更改环境变量时,这些脚本可用于执行任意代码的情况。

您可以使用最新版本的 Gradle 生成gradlew脚本,并使用它来执行较旧版本的 Gradle。

对于大多数用户来说,这应该是透明的;但是,对于依赖环境变量JAVA_OPTSGRADLE_OPTS来传递参数并带有复杂引号转义的 Gradle 构建,可能会发生更改。如果您怀疑某些内容破坏了您的构建,并且找不到解决方案,请联系我们。

更新捆绑的 Gradle 依赖项

弃用

使用 Java lambda 作为任务操作

当使用 Java lambda 来实现任务操作时,Gradle 无法跟踪该实现,并且该任务将永远不会是最新的或从构建缓存中提供。由于添加此类任务操作很容易,因此现在不赞成使用由 Java lambda 实现的任务操作。有关如何解决此问题的更多详细信息,请参见验证问题

依赖 equals 进行最新检查已弃用

当任务输入使用 @Input 进行注释,并且不是 Gradle 直接理解的类型(例如 String)时,Gradle 会使用输入的序列化形式进行最新检查和构建缓存密钥。从历史上看,Gradle 还会从上次执行中加载序列化值,然后使用 equals() 将其与当前值进行比较以进行最新检查。这样做容易出错,无法与构建缓存一起使用,并且会影响性能,因此已被弃用。不要在 Gradle 无法直接理解的类型上使用 @Input,而是使用 @Nested 并相应地注释类型的属性。

从 7.0 及更早版本升级

潜在破坏性更改

默认工具集成版本的更新

  • JaCoCo 已更新至 0.8.7

org.gradle.util 包现在是公共 API

正式来说,org.gradle.util 包不属于公共 API。但是,由于此包名不包含单词 internal,因此许多 Gradle 插件已经将其视为一个包。Gradle 7.1 解决此问题,并将该包标记为公共包。根据外部用法,意外公开的类会被弃用或移除。

以下类现在被正式视为公共 API:
  • GradleVersion

  • Path

  • Configurable

以下类在外部插件中已知有使用,现已弃用,并已设置为在 Gradle 8.0 中移除:
  • VersionNumber

  • TextUtil

  • WrapUtil

  • RelativePathUtil

  • DistributionLocator

  • SingleMessageLogger

  • ConfigureUtil

ConfigureUtil 正在被移除,且没有替代品。插件可以通过遵循 我们的示例 来避免使用 ConfigureUtil

以下类仅供内部使用,已从 org.gradle.util 移至 org.gradle.util.internal 包:
  • Resources

  • RedirectStdOutAndErr

  • 交换器

  • 标准输入交换器

  • 孵化日志记录器

  • 重定向标准输入

  • 多线程测试规则

  • 可断开输入流

  • 批量读取输入流

  • 模拟执行器

  • 失败并显示消息

  • 失败并显示消息扩展

  • 树访问器

  • Ant 实用工具

  • Jar 实用工具

最后一组类没有外部或内部用法,因此已删除:
  • 差异实用工具

  • 无操作更改监听器

  • 带类体的枚举

  • 始终为真

  • 反射相等匹配器

  • 动态委托

  • 孵化日志记录器

  • 无操作更改监听器

  • 延迟实用工具

  • 更改监听器

源集扩展的返回类型已更改

以下源集通过具有自定义类型的扩展进行贡献

“惯用”DSL 声明向后兼容

sourceSets {
    main {
        groovy {
            // ...
        }
    }
}

但是,groovy 块的返回类型已更改为扩展类型。这意味着以下代码段在 Gradle 7.1 中不再起作用

 sourceSets {
     main {
         GroovySourceSet sourceSet = groovy {
             // ...
         }
     }
 }

启动脚本需要 bash shell

用于启动 Gradle、Gradle 封装以及由 application 插件生成的脚本的命令现在需要 bash shell。

弃用

使用类型为 Provider 的属性进行约定映射已弃用

约定映射是一项内部功能,已被 Provider API 替代。将约定映射与 Provider API 混合使用时,可能会出现意外行为。当任务、扩展或其他域对象中的属性使用 Provider API 进行约定映射时,Gradle 会发出弃用警告。

要解决此问题,需要将为任务、扩展或域对象配置约定映射的插件更改为仅使用 Provider API。

设置自定义构建布局

命令行选项

  • -c--settings-file 用于指定自定义设置文件位置

  • -b--build-file 用于指定自定义构建文件位置

已弃用。

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

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

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

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

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

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

对于使用自定义设置或构建文件来模拟不同行为(类似于 Maven 配置文件)的用例,请考虑使用带有条件逻辑的 系统属性。例如,在设置或构建文件中的代码段中

if (System.getProperty("profile") == "custom") {
    println("custom profile")
} else {
    println("default profile")
}

您可以使用 gradle -Dprofile=custom 向 Gradle 传递 profile 系统属性,以在 custom 配置文件分支中执行代码。

Substitution.with 已替换为 Substitution.using

使用 with 方法的 依赖项替换 已弃用,并替换为 using 方法,后者还允许链接。例如,依赖项替换规则 substitute(project(':a')).with(project(':b')) 应替换为 substitute(project(':a')).using(project(':b'))。通过链接,您可以添加替换原因,如下所示:substitute(project(':a')).using(project(':b')).because("a reason")

JavaExec 任务中已弃用的属性

非分层项目布局

Gradle 7.1 弃用了子项目位于项目根目录之外的项目布局。但是,根据 社区反馈,我们决定在 Gradle 7.4 中回滚并取消弃用。因此,Settings.includeFlat() 方法仅在 Gradle 7.1、7.2 和 7.3 中弃用。

已弃用的 Upload 任务

Gradle 以前有两种发布工件的方法。现在,情况已经明朗,所有构建都应该使用 maven-publish 插件。旧版发布方式的最后一个剩余工件是 Upload 任务,该任务已弃用,并计划在 Gradle 8.0 中移除。现有客户端应迁移到 maven-publish 插件

已弃用的约定

约定的概念已过时,已被扩展取代。为了在 Gradle API 中反映这一点,以下元素现在已弃用

约定内部用法也已清理(请参阅以下已弃用项)。

如果插件作者复制我们内部所做的更改,请迁移到扩展。以下是一些示例

已弃用内部插件配置的消耗

一些核心 Gradle 插件声明了插件本身使用的配置,并且不打算直接发布或由另一个子项目使用。Gradle 没有明确禁止这一点。Gradle 7.1 弃用了对这些配置的消耗,这将在 Gradle 8.0 中成为一个错误。

以下插件配置已弃用,不再使用

插件 不再使用的配置

codenarc

codenarc

pmd

pmd

checkstyle

checkstyle

antlr

antlr

jacoco

jacocoAntjacocoAgent

scala

zinc

war

providedCompileprovidedRuntime

如果你的用例需要在另一个项目中使用上述任何配置,请创建一个单独的可使用配置,该配置从内部配置中扩展。例如

plugins {
    id("codenarc")
}
configurations {
    codenarc {
        // because currently this is consumable until Gradle 8.0 and can clash with the configuration below depending on the attributes set
        canBeConsumed = false
    }
    codenarcConsumable {
        extendsFrom(codenarc)
        canBeConsumed = true
        canBeResolved = false
        // the attributes below make this configuration consumable by a `java-library` project using `implementation` configuration
        attributes {
            attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME))
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.LIBRARY))
            attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.JAR))
            attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.EXTERNAL))
            attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objects.named(TargetJvmEnvironment, TargetJvmEnvironment.STANDARD_JVM));
        }
    }
}

已弃用的自定义源集接口

以下源集接口现已弃用,并计划在 Gradle 8.0 中移除

客户端应使用其插件特定配置来配置源

例如,以下是如何从插件配置 groovy 源

GroovySourceDirectorySet groovySources = sourceSet.getExtensions().getByType(GroovySourceDirectorySet.class);
groovySources.setSrcDirs(Arrays.asList("sources/groovy"));

注册扩展 ArtifactTransform 的工件转换

当 Gradle 首次引入工件转换时,它使用基类 ArtifactTransform 来实现它们。Gradle 5.3 引入了接口 TransformAction 来实现工件转换,取代了之前的类 ArtifactTransform 并解决了各种缺点。使用注册方法 DependencyHandler.registerTransform(Action) 适用于 ArtifactTransform 已弃用。迁移你的工件转换以使用 TransformAction,并改用 DependencyHandler.registerTransform(Class, Action)。有关实现 TransformAction 的更多信息,请参阅用户手册