本章提供了将 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.14 将项目更新到 8.14。

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

从 7.6 及更早版本升级

现已成为错误的警告

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

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

  • finalizedBy

  • mustRunAfter

  • shouldRunAfter

从没有 backing files 的资源创建 TAR 树

不再支持从没有 backing file 的资源创建 TAR 树。请改为将资源转换为文件,并在文件上使用 project.tarTree()。更多信息请参见从没有 backing files 的资源创建 TAR 树

使用无效的 Java toolchain 规范

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

在未配置仓库的情况下使用自动 toolchain 下载

不再支持在未明确提供要使用的仓库的情况下进行自动 toolchain 下载。更多信息请参见用户手册

设置测试框架选项后更改测试框架现已成为错误

在配置 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 的 Artifact 转换

遗留 IncrementalTaskInputs API

遗留的 IncrementalTaskInputs API 已被移除。更多信息请参见IncrementalTaskInputs 类型已弃用。此更改也影响 Kotlin Gradle Plugin 和 Android Gradle Plugin。使用 Gradle 8.0 时,您应该使用 Kotlin Gradle Plugin 1.6.10 或更高版本,以及带有 android.experimental.legacyTransform.forceNonIncremental=true 属性的 Android Gradle Plugin 7.3.0 或更高版本。

遗留 AntlrSourceVirtualDirectory API

遗留的 AntlrSourceVirtualDirectory API 已被移除。此更改影响 antlr 插件。在 Gradle 8.0 及以上版本中,请改用 AntlrSourceDirectorySet source set 扩展。

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 清理

已弃用的 JacocoPluginExtensionreportsDir 属性已移除。请改为使用 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 清理

已弃用的 AbstractArchiveTask 任务类型的 appendixarchiveNamearchivePathbaseNameclassifierdestinationDirextensionversion 属性已移除。请改为使用 archiveAppendixarchiveFileNamearchiveFilearchiveBaseNamearchiveClassifierdestinationDirectoryarchiveExtensionarchiveVersion 属性。

IdeaModule API 清理

已弃用的 IdeaModule 类型的 testSourceDirstestResourceDirs 属性已移除。这影响 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 方法

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

Kotlin DSL 中已移除 Configuration 扩展方法

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 中的方法。

潜在的破坏性变更

JavaForkOptionsgetJvmArgs()getAllJvmArgs() 返回不可变列表

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

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

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

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

一个特别的例子是从 Provider#mapProvider#flatMap 返回 null。在这两个 API 中,Gradle 都允许返回 null,但在 Kotlin DSL 中这被认为是无效的。

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

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

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

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

Wrapper 任务配置

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

AbstractCodeQualityPlugin 类中的变更

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

移除 Gradle worker 的隐式 --add-opens

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

这影响所有内部 Gradle worker,它们用于多种任务

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

  • ScalaDoc

  • AntlrTask

  • JVM 编译器守护进程

  • 通过Worker API 使用进程隔离执行的任务

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

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

  • 代码质量工具

  • 注解处理器

  • 任何使用 worker API 的 Gradle 插件

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

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

在 Gradle 8.0 之前,SourceSetOutput.classesDirs 的任务依赖包含了不生成 class 文件的任务。这意味着依赖于 classesDirs 的任务也会依赖于 classesprocessResources 以及添加到 SourceSetOutput 的任何其他任务依赖。这种行为可能是一个错误,因为 classesDirs 属性不包含 processResources 的输出。从 8.0 开始,这种隐式依赖被移除。现在,依赖于 classesDirs 只会执行直接在 classes 目录中生成文件的任务。

考虑以下构建脚本

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。现在,listClassFiles 的任务依赖仅为 compileJava

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

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

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

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

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

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

Gradle 7.x 支持 Android Gradle Plugin (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 在 7.x 系列中引入了额外的任务和 artifact 转换验证警告。这些警告在 Gradle 8.0 中现已成为错误,并将导致构建失败。

已成为错误的警告

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

以前,Gradle 会检测用 @SkipWhenEmpty 标注的输入文件集合是否仅包含文件树,然后自动忽略目录。在 Gradle 8.0 及更高版本中,要忽略目录,需要用 @IgnoreEmptyDirectories 明确标注输入属性。更多信息请参见文件树和空目录处理

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

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 系统属性启用此行为。此行为现已成为默认设置。此属性已弃用,应移除其用法。您可以在下方找到有关此属性的更多信息。

Init 脚本应用于 buildSrc 构建

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

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

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

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

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

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

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

buildSrcbuildFinished { } hook 在所有任务执行完成后运行

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

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

包含的构建路径变更

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

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

.
├── 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 设置为非空值会隐式忽略默认规则。

Report getOutputLocation 返回类型从 Provider 更改为 Property

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

此更改使得 Report 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 Level 1.8

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

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

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

另请注意,Kotlin Gradle Plugin 1.8.0 引入了支持延迟配置属性的 compilerOptions 作为不支持延迟配置的 kotlinOptions 的替代方案。建议您使用 compilerOptions 配置 Kotlin 编译,而不是使用 kotlinOptions

kotlinDslPluginOptions.jvmTarget 已弃用

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

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

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

Java Base Plugin 现在设置了 Jar、War 和 Ear 目标目录的默认值

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

不应再使用 Upload 任务

Upload 任务仍然弃用,现计划在 Gradle 9.0 中移除。尽管此类型仍然存在,但它不再起作用,运行它将抛出异常。保留它仅是为了避免破坏插件。请改用 maven-publishivy-publish 插件中的任务。

不再允许将 Configurations 用作 Dependencies

dependencies DSL 块中将 Configuration 添加为依赖项,或以编程方式使用 DependencyHandler 类的 doAdd(Configuration, Object, Closure) 方法,现已不再允许,并会抛出异常失败。要复制此行为的许多方面,请改用 Configuration 上的 extendsFrom(Configuration) 方法来扩展 configuration。

现已弃用的用于消费的 configuration 不再可消费

以下 configuration 从未打算被消费

  • AntlrPlugin 创建的 antlr configuration

  • ScalaBasePlugin 创建的 zinc configuration

  • WarPlugin 创建的 providedCompileprovidedRuntime configuration

这些 configuration 已弃用用于消费,现在不再可消费。尝试消费它们将导致错误。

相同的可消费 configuration 现在会导致错误

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

outgoingVariants 报告 将对此受影响的 configuration 发出警告。

JVM 项目基于工具链的任务

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

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

Scala 编译目标

随着上述工具链更改,Scala 编译任务现在始终提供 targetrelease 参数。具体的参数和值取决于是否使用工具链以及 Scala 版本。

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

Plugin Publish 插件中移除了 pluginBundle

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

从 7.5 及更早版本升级

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

Strict Kotlin DSL 预编译脚本插件 Accessors 生成

对于预编译脚本插件,如果此类预编译脚本中请求的插件未能应用,则类型安全的 Kotlin DSL accessors 生成在默认情况下不会导致构建失败。由于原因可能是环境因素,并且为了向后兼容,此行为尚未更改。

早在 Gradle 7.1 中,负责 accessors 生成的 :generatePrecompiledScriptPluginAccessors 任务已被默认标记为不可缓存。引入了 org.gradle.kotlin.dsl.precompiled.accessors.strict 系统属性,以提供一种选择加入更严格操作模式的方式,即当插件应用失败时会导致构建失败,并为该任务启用构建缓存。

从 Gradle 7.6 开始,Kotlin DSL 预编译脚本插件的非严格 accessors 生成已被弃用。此行为将在 Gradle 8.0 中更改。严格的 accessors 生成将成为默认设置。要选择加入严格行为,请将 '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 执行。

Test Suites 中依赖项声明的更改

作为 Test Suites 不断演进的一部分,Test Suites dependencies 块中的依赖项声明现在是强类型的。这将有助于使这个孵化中的 API 更易于发现,并在 IDE 中更易于使用。

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

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 的依赖项声明。

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

更多信息请参阅用户指南 JVM Test Suite Plugin 部分中更新的声明附加 Test Suite 示例,以及 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

Internal 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 类型。有关更多详细信息,请参阅关于实现增量任务的用户手册部分

潜在的破坏性更改

Version catalog 仅接受单个 TOML 导入文件

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

默认工具集成版本的更新

eclipse 插件生成的 Classpath 文件已更改

在测试 configuration 中定义的项目依赖项获取 test=true classpath 属性。JVM Test Suite 插件定义的所有源集和依赖项也默认标记为测试代码。您现在可以通过 eclipse 插件 DSL 自定义测试源集和依赖项

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

另外,您可以在 eclipse.classpath.file.whenMerged { } 块中调整或移除 classpath 属性。

使用 GPG 命令时,Signing 插件默认使用 gpg 而非 gpg2

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

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

signing.gnupg.executable=gpg2

mustRunAfter 约束不再因 finalizedBy 依赖项而被违反

在以前的 Gradle 版本中,常规任务和 finalizer 任务依赖项之间的 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 的一个 finalizer,因此它必须在 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 版本已更新到最新可用版本,以受益于最近的所有 bug 修复。因此,如果您使用 zincVersion 设置,建议将其移除并仅使用默认版本,因为 Gradle 只能使用 Zinc 版本设置为 1.6.x 或更高版本来编译 Scala 代码。

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

在 Gradle 7.5 之前,通过传递 --add-opens CLI 参数,JDK 模块 java.base/java.utiljava.base/java.lang 在 JDK9+ 上的测试工作进程中会自动打开。这意味着任何测试都可以对 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.langjava.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 worker 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

弃用项

将文件转换为包含文件分隔符路径的 classpath

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

dependencyInsight --singlepath 选项已废弃

为了保持一致性,此选项已更改为 --single-path。API 方法保持不变,这只影响 CLI。

Groovydoc includePrivate 属性已废弃

新增了一个 access 属性,允许对 Groovydoc 中包含的内容进行更精细的控制。

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

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

从 7.3 及更早版本升级

废弃项

AdoptOpenJDK 工具链下载

随着 AdoptOpenJDK 迁移到 Eclipse Foundation 下的 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 集的所有其他配置中必须是唯一的。

这将在配置 variant 配置结束时检查,因为它们将被锁定以防止进一步修改。

如果属性集在配置之间共享,请考虑在一个 variant 中添加一个附加属性,其唯一目的是进行区分。

Provider#forUseAtConfigurationTime() 已废弃

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

在使用配置缓存功能时,对于计划在配置时使用的外部值(例如 系统属性环境变量Gradle 属性文件内容)的 provider,此调用曾经是强制性的。

从 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 的详细信息,请参阅 配置缓存章节

从任务 action 中调用 Task.getProject()

在执行时从任务 action 中调用 Task.getProject() 现已废弃,并将在 Gradle 8.0 中成为错误。此方法可以在配置时使用,但不推荐这样做。

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

从任务 action 中调用 Task.getTaskDependencies()

在执行时从任务 action 中调用 Task.getTaskDependencies() 现已废弃,并将在 Gradle 8.0 中成为错误。此方法可以在配置时使用,但不推荐这样做。

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

从任务中使用构建服务而未明确声明用法

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

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

这可以通过使用 @ServiceReference 属性(自 8.0 起)或在任务上调用 usesService()(自 6.1 起)来使用服务来实现。

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

VersionCatalog 和 VersionCatalogBuilder 废弃项

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

这些方法已更改,以提高 libs.versions.toml 文件与 API 类之间的一致性。

从 7.2 及更早版本升级

潜在的破坏性更改

捆绑的 Gradle 依赖项的更新

plugins 块中插件的应用顺序

plugins 块中插件实际应用顺序不一致,取决于插件如何添加到类路径。

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

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

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

版本目录

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

Scala 中的工具链支持

在 Scala 中使用 工具链 时,Scala 编译器的 -target 选项将自动设置。这意味着使用某个版本的 Java,如果该版本不能被某个版本的 Scala 定位,将导致错误。在编译器选项中提供此标志将禁用此行为,并允许使用更高的 Java 版本为较低的字节码目标进行编译。

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

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

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

从 7.1 及更早版本升级

潜在的破坏性更改

应用程序启动脚本和 Gradle wrapper 脚本的安全更改

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

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

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

捆绑的 Gradle 依赖项的更新

废弃项

将 Java lambdas 用作任务 actions

当使用 Java lambda 实现任务 action 时,Gradle 无法跟踪实现,任务将永远不会是最新的,也无法从构建缓存提供服务。由于很容易添加这样的任务 action,因此使用由 Java lambdas 实现的任务 action 现已废弃。有关如何解决此问题的更多详细信息,请参阅 验证问题

依赖 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 插件已经将其视为公共 API。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

  • Swapper

  • StdInSwapper

  • IncubationLogger

  • RedirectStdIn

  • MultithreadedTestRule

  • DisconnectableInputStream

  • BulkReadInputStream

  • MockExecutor

  • FailsWithMessage

  • FailsWithMessageExtension

  • TreeVisitor

  • AntUtil

  • JarUtil

最后一组类没有任何外部或内部用法,因此已被删除:
  • DiffUtil

  • NoopChangeListener

  • EnumWithClassBody

  • AlwaysTrue

  • ReflectionEqualsMatcher

  • DynamicDelegate

  • IncubationLogger

  • NoOpChangeListener

  • DeferredUtil

  • ChangeListener

source set 扩展的返回类型已更改

以下 source set 通过具有自定义类型的扩展贡献:

“惯用”的 DSL 声明向后兼容

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

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

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

启动脚本需要 bash shell

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

废弃项

将 convention mapping 与 Provider 类型的属性一起使用已废弃

Convention mapping 是一个内部功能,已被 Provider API 取代。当 convention mapping 与 Provider API 混合使用时,可能会出现意外行为。当任务、扩展或其他域对象中的属性使用 convention mapping 与 Provider API 时,Gradle 会发出废弃警告。

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

设置自定义构建布局

命令行选项

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

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

已废弃。

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

请改用 dir 属性来指定嵌套构建的根目录。

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

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

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

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

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

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

您可以使用 gradle -Dprofile=customprofile 系统属性传递给 Gradle,以执行 custom profile 分支中的代码。

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 task

Gradle 以前有两种发布 artifact 的方式。现在情况已经明确,所有构建都应使用 maven-publish 插件。旧发布方式的最后一个遗留物是 Upload 任务,它已被废弃,并计划在 Gradle 8.0 中移除。现有客户端应迁移到 maven-publish 插件

废弃的 conventions

conventions 的概念已过时,已被 extensions 取代。为了在 Gradle API 中反映这一点,以下元素现已废弃

conventions 的内部用法也已清理(参见下面的废弃项)。

如果插件作者复制了我们内部所做的更改,请迁移到 extensions。这里有一些示例

废弃的内部插件配置的消费

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

以下插件配置已废弃用于消费

plugin 废弃用于消费的配置

codenarc

codenarc

pmd

pmd

checkstyle

checkstyle

antlr

antlr

jacoco

jacocoAnt, jacocoAgent

scala

zinc

war

providedCompile, providedRuntime

如果您的用例需要在另一个项目中消费上述任何配置,请创建一个从内部配置继承的单独的可消费配置。例如

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));
        }
    }
}

ScalaSourceSet

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

例如,这是如何从插件配置 groovy 源的