從 Gradle 8.x 升級您的建置到最新版本
本章節提供您將 Gradle 8.x 建置遷移到最新 Gradle 版本所需的資訊。若要從 Gradle 4.x、5.x、6.x 或 7.x 遷移,請先參閱較舊的遷移指南。
我們建議所有使用者遵循以下步驟
-
嘗試執行
gradle help --scan
並檢視產生的建置掃描的棄用檢視。這可讓您查看任何適用於您建置的棄用警告。
或者,您可以執行
gradle help --warning-mode=all
以在主控台中查看棄用,但它可能不會報告那麼詳細的資訊。 -
更新您的外掛。
某些外掛程式會因為使用已被移除或變更的內部 API 而在新版本的 Gradle 中中斷。先前的步驟將透過在外掛程式嘗試使用已棄用的 API 部分時發出棄用警告,來協助您識別潛在的問題。
-
執行
gradle wrapper --gradle-version 8.13
以將專案更新至 8.13。 -
嘗試執行專案並使用疑難排解指南偵錯任何錯誤。
從 8.12 及更早版本升級
潛在的重大變更
JvmTestSuite 的變更
testType
屬性已從 JvmTestSuite 中移除,且 TestSuiteTargetName
和 TestSuiteType
屬性皆已移除。現在可以透過在目標專案中指定要聚合的測試套件名稱,在專案之間聚合測試報告和 JaCoCo 報告。
請參閱下方以取得更多詳細資訊。
測試報告聚合和 Jacoco 聚合的變更
針對正在孵化中的測試報告聚合和JaCoCo 報告聚合外掛程式進行了數項變更。
現在,這些外掛程式為每個測試套件建立單一測試結果變體,其中包含整個套件的所有測試結果,而不是每個測試目標一個變體。此變更允許聚合外掛程式聚合具有多個目標的測試套件,而先前這會導致不明確的變體選擇錯誤。
在未來,隨著我們繼續開發這些外掛程式,我們計劃再次為每個測試套件目標建立一個結果變體,允許明確地聚合來自特定目標的測試結果。
JacocoCoverageReport 和 AggregateTestReport 上的 testType
屬性已移除,並替換為新的 testSuiteName
屬性
先前
reporting {
reports {
val testCodeCoverageReport by creating(JacocoCoverageReport::class) {
testType = TestSuiteType.UNIT_TEST
}
}
}
現在
reporting {
reports {
val testCodeCoverageReport by creating(JacocoCoverageReport::class) {
testSuiteName = "test"
}
}
}
呼叫 BuildLauncher.addJvmArguments
時的變更行為
修正了 Issue (#31426),該問題導致 BuildLauncher.addJvmArguments
覆寫來自 org.gradle.jvmargs
系統屬性的旗標。升級到 Gradle 8.13 時,請確保您未依賴此行為。如果需要覆寫系統屬性,則應改用 BuildLauncher.setJvmArguments
。
val buildLauncher: BuildLauncher = connector.connect().newBuild()
buildLauncher.setJvmArguments("-Xmx2048m", "-Dmy.custom.property=value")
升級到 ASM 9.7.1
ASM 從 9.6 升級到 9.7.1,以確保更早版本的 Java 24 相容性。
Project.task 方法的原始碼層級棄用
Project
介面上的預先任務建立方法已標記為 @Deprecated
,並且在建置腳本或外掛程式碼中使用時會產生編譯器和 IDE 警告。目前尚未使用 Gradle 棄用警告來發出其使用訊息。
但是,如果建置配置為在 Kotlin 腳本或外掛程式碼編譯期間於警告時失敗,則此變更可能會導致建置失敗。
當這些方法在未來版本中完全棄用時,使用時將會印出標準的 Gradle 棄用警告。
棄用
在延遲提供者中遞迴查詢 AttributeContainer
在 Gradle 9.0 中,從同一容器的屬性值提供者內查詢 AttributeContainer
的內容將會變成錯誤。
以下範例展示了禁止的行為
AttributeContainer container = getAttributeContainer();
Attribute<String> firstAttribute = Attribute.of("first", String.class);
Attribute<String> secondAttribute = Attribute.of("second", String.class);
container.attributeProvider(firstAttribute, project.getProviders().provider(() -> {
// Querying the contents of the container within an attribute value provider
// will become an error.
container.getAttribute(secondAttribute);
return "first";
}));
已棄用的 org.gradle.api.artifacts.transform.VariantTransformConfigurationException
此例外狀況沒有良好的公開使用案例,並且不打算由使用者擲回。在 Gradle 9.0 中,它將被 org.gradle.api.internal.artifacts.transform.VariantTransformConfigurationException
取代,僅供內部使用。
已棄用正在孵化中的 UpdateDaemonJvm
中的屬性
UpdateDaemonJvm
的以下屬性現在已棄用
-
jvmVersion
-
jvmVendor
它們分別被 languageVersion
和 vendor
取代。這允許 Java 工具鏈規格的配置和 UpdateDaemonJvm
任務可互換。
請注意,由於 vendor 屬性的類型變更,使用 jvmVendor
屬性執行 updateDaemonJvm
將導致任務失敗。請參閱文件以取得新的配置選項。
使用 is
字首和 Boolean
類型宣告布林屬性
Gradle 屬性名稱是透過遵循 Java Bean 規範(有一個例外)而衍生的。Gradle 將具有 Boolean
傳回類型和 is
字首的方法識別為布林屬性。這是最初從 Groovy 繼承的行為。Groovy 4 更緊密地遵循 Java Bean 規範,並且 不再支援此例外。
當 Gradle 偵測到布林屬性是從具有 Boolean
傳回類型和 is
字首的方法衍生而來時,將會發出棄用警告。在 Gradle 9.0 中,這些方法將不再被視為定義 Gradle 屬性。即使 Boolean
屬性似乎是輸入,這也可能導致任務被視為最新狀態。
有兩種選項可以修正此問題
-
引入一個新的方法,以
get
而非is
開頭,且具有相同的行為。舊方法不需要移除(為了保持二進制相容性),但可能需要進行如下所示的調整。-
建議棄用
is-
方法,然後在未來的主要版本中移除它。
-
-
將屬性(get 和 set)的類型變更為
boolean
。這是一個重大變更。
對於使用第一個選項的任務輸入屬性,您也應該使用 @Deprecated
和 @ReplacedBy
註釋舊的 is-
方法,以確保 Gradle 不會使用它。例如,此程式碼
class MyValue {
private Boolean property = Boolean.TRUE;
@Input
Boolean isProperty() { return property; }
}
應替換為以下內容
class MyValue {
private Boolean property = Boolean.TRUE;
@Deprecated
@ReplacedBy("getProperty")
Boolean isProperty() { return property; }
@Input
Boolean getProperty() { return property; }
}
從 8.11 及更早版本升級
潛在的重大變更
升級到 Kotlin 2.0.21
嵌入式 Kotlin 已從 2.0.20 更新到 Kotlin 2.0.21。
升級到 Ant 1.10.15
Ant 已更新到 Ant 1.10.15。
升級到 Zinc 1.10.4
Zinc 已更新到 1.10.4。
Swift SDK 探索
為了判斷 Swift 的 Mac OS X SDK 位置,Gradle 現在將 --sdk macosx
引數傳遞給 xcrun
。這是必要的,因為如果沒有此引數,SDK 在不同環境中可能會以不一致的方式探索到。
TaskContainer.create 方法的原始碼層級棄用
TaskContainer
介面上的預先任務建立方法已標記為 @Deprecated
,並且在建置腳本或外掛程式碼中使用時會產生編譯器和 IDE 警告。目前尚未使用 Gradle 棄用警告來發出其使用訊息。
但是,如果建置配置為在 Kotlin 腳本或外掛程式碼編譯期間於警告時失敗,則此行為可能會導致建置失敗。
當這些方法在未來版本中完全棄用時,使用時將會印出標準的 Gradle 棄用警告。
棄用
已棄用不明確的轉換鏈
先前,當至少有兩個等長的產出物轉換鏈可用時,它們會產生相容的變體,並且每個變體都會滿足解析請求,Gradle 會任意且靜默地選擇其中一個。
現在,Gradle 會發出棄用警告,說明此情況
There are multiple distinct artifact transformation chains of the same length that would satisfy this request. This behavior has been deprecated. This will fail with an error in Gradle 9.0.
Found multiple transformation chains that produce a variant of 'root project :' with requested attributes:
- color 'red'
- texture 'smooth'
Found the following transformation chains:
- From configuration ':squareBlueSmoothElements':
- With source attributes:
- artifactType 'txt'
- color 'blue'
- shape 'square'
- texture 'smooth'
- Candidate transformation chains:
- Transformation chain: 'ColorTransform':
- 'BrokenColorTransform':
- Converts from attributes:
- color 'blue'
- texture 'smooth'
- To attributes:
- color 'red'
- Transformation chain: 'ColorTransform2':
- 'BrokenColorTransform2':
- Converts from attributes:
- color 'blue'
- texture 'smooth'
- To attributes:
- color 'red'
Remove one or more registered transforms, or add additional attributes to them to ensure only a single valid transformation chain exists.
在這種情況下,Gradle 無法知道應該使用兩個(或更多)可能的轉換鏈中的哪一個。當看似不相關的建置部分被修改時,選擇任意鏈可能會導致效能降低或發生意外的行為變更。這可能是一個非常複雜的情況,訊息現在透過印出所有已註冊的轉換(依序排列),以及每個候選鏈的來源(輸入)變體,來完整說明情況。
當遇到此類型的失敗時,建置作者應執行以下操作之一
-
在註冊鏈中存在的轉換時新增額外的區分屬性,以確保僅選擇單一鏈來滿足請求
-
請求額外的屬性以消除所選鏈的歧義(如果它們產生非相同的最終屬性)
-
從建置中移除不必要的已註冊轉換
這將在 Gradle 9.0 中變成錯誤。
init
必須單獨執行
init
任務必須單獨執行。此任務不應與單一 Gradle 調用中的其他任務組合。
在與其他任務相同的調用中執行 init
將在 Gradle 9.0 中變成錯誤。
例如,這將不被允許
> gradlew init tasks
從任務動作中呼叫 Task.getProject()
現在已棄用在執行時從任務動作中呼叫 Task.getProject(),並且在 Gradle 10.0 中將會變成錯誤。此方法仍然可以在配置時使用。
僅當未啟用配置快取時,才會發出棄用。啟用配置快取時,呼叫 Task.getProject() 會回報為配置快取問題。
此棄用最初在 Gradle 7.4 中引入,但僅在啟用 STABLE_CONFIGURATION_CACHE
功能旗標時發出。該功能旗標不再控制此棄用。這是讓使用者遠離與配置快取不相容的慣用語的另一步,配置快取將成為未來版本中 Gradle 支援的唯一模式。
請參閱配置快取文件,以取得在執行時調用 Task.getProject()
的替代方案,這些替代方案與配置快取相容。
Groovy「空格賦值」語法
目前,有多種使用 Groovy DSL 語法設定屬性的方法
---
propertyName = value
setPropertyName(value)
setPropertyName value
propertyName(value)
propertyName value
---
後者「空格賦值」是 Gradle 特有的功能,不是 Groovy 語言的一部分。在常規 Groovy 中,這只是一個方法呼叫:propertyName(value)
,如果 propertyName
方法尚不存在,Gradle 會在運行時產生該方法。此功能可能會造成混淆(尤其是對於新使用者),並為使用者和 Gradle 程式碼庫增加額外的複雜性,而沒有提供任何顯著的價值。有時,類別會宣告具有相同名稱的方法,而這些方法甚至可能具有與純賦值不同的語意。
這些產生的方法現在已棄用,並將在 Gradle 10.0 中移除,並且 propertyName value
和 propertyName(value)
都將停止運作,除非定義了明確的方法 propertyName
。請改用明確的賦值 propertyName = value
。
對於明確的方法,請考慮使用 propertyName(value)
語法而不是 propertyName value
以提高清晰度。例如,jvmArgs "some", "arg"
可以替換為 jvmArgs("some", "arg")
或 jvmArgs = ["some", "arg"]
(對於 Test
任務)。
如果您有一個大型專案,要替換空格賦值語法的出現次數,您可以使用例如以下 sed
命令
---
find . -name 'build.gradle' -type f -exec sed -i.bak -E 's/([^A-Za-z]|^)(replaceme)[ \t]*([^= \t{])/\1\2 = \3/g' {} +
---
您應該將 replaceme
替換為您要替換的一個或多個屬性名稱,以 |
分隔,例如 (url|group)
。
DependencyInsightReportTask.getDependencySpec
該方法已棄用,因為它不打算在建置腳本中公開使用。
ReportingExtension.baseDir
ReportingExtension.getBaseDir()
、ReportingExtension.setBaseDir(File)
和 ReportingExtension.setBaseDir(Object)
已棄用。它們應替換為 ReportingExtension.getBaseDirectory()
屬性。
從 8.10 及更早版本升級
潛在的重大變更
升級到 Kotlin 2.0.20
嵌入式 Kotlin 已從 1.9.24 更新到 Kotlin 2.0.20。另請參閱 Kotlin 2.0.10 和 Kotlin 2.0.0 發行說明。
JVM 測試套件中的預設 kotlin-test
版本也已升級到 2.0.20。
Kotlin DSL 腳本仍然使用 Kotlin 語言版本 1.8 編譯,以實現向後相容性。
透過工具鏈的 Gradle daemon JVM 配置
屬性 UpdateDaemonJvm.jvmVersion
的類型現在為 Property<JavaLanguageVersion>
。
如果您在建置腳本中配置了任務,則需要替換
jvmVersion = JavaVersion.VERSION_17
為
jvmVersion = JavaLanguageVersion.of(17)
使用 CLI 選項來配置要用於 Gradle Daemon 的 JVM 版本沒有影響。
名稱比對變更
名稱比對邏輯已更新,將數字視為 camelCase 名稱的單字邊界。先前,類似 unique
的請求會同時比對 uniqueA
和 unique1
。現在,由於不明確,此類請求將會失敗。為了避免問題,請使用確切的名稱而不是縮短的版本。
此變更會影響
-
任務選擇
-
專案選擇
-
依賴報告任務中的配置選擇
棄用
已棄用 ForkOptions 的 JavaHome 屬性
ForkOptions
類型的 JavaHome 屬性已棄用,並將在 Gradle 9.0 中移除。
請改用 JVM 工具鏈,或 executable 屬性。
已棄用變更 buildscript 配置
從 Gradle 9.0 開始,變更腳本 buildscript 區塊中的配置將會導致錯誤。這適用於專案、設定、初始化和獨立腳本。
buildscript 配置區塊僅用於控制 buildscript 類別路徑解析。
請考慮以下腳本,該腳本在設定腳本中建立新的 buildscript 配置並解析它
buildscript {
configurations {
create("myConfig")
}
dependencies {
"myConfig"("org:foo:1.0")
}
}
val files = buildscript.configurations["myConfig"].files
此模式有時用於解析設定中的依賴,因為沒有其他方法可以取得 Configuration。不建議在此內容中解析依賴。使用分離的配置是一種可能的但不建議的替代方案。
可以修改以上範例以使用分離的配置
val myConfig = buildscript.configurations.detachedConfiguration(
buildscript.dependencies.create("org:foo:1.0")
)
val files = myConfig.files
依配置名稱選擇 Maven 變體
從 Gradle 9.0 開始,將禁止從非 Ivy 外部組件中依名稱選擇變體。
仍然允許從本機組件中依名稱選擇變體;但是,不建議使用此模式。對於本機組件,應優先使用變體感知依賴解析,而不是依名稱選擇變體。
當目標是非 Ivy 外部組件時,以下依賴將無法解析
dependencies {
implementation(group: "com.example", name: "example", version: "1.0", configuration: "conf")
implementation("com.example:example:1.0") {
targetConfiguration = "conf"
}
}
已棄用手動新增至配置容器
從 Gradle 9.0 開始,手動將配置實例新增至配置容器將會導致錯誤。配置應僅透過預先或延遲工廠方法新增至容器。分離的配置和複製的配置不應新增至容器。
將禁止在 ConfigurationContainer 上呼叫以下方法:- add(Configuration) - addAll(Collection) - addLater(Provider) - addAllLater(Provider)
已棄用 ProjectDependency#getDependencyProject()
ProjectDependency#getDependencyProject()
方法已棄用,並將在 Gradle 9.0 中移除。
應避免存取其他專案的可變專案實例。
若要探索解析中包含的所有專案的詳細資訊,請檢查完整的 ResolutionResult。專案依賴關係在 DependencyResult 中公開。請參閱使用者指南中關於程式化依賴解析的章節,以取得有關此 API 的更多詳細資訊。這是尋找解析中使用的所有專案的唯一可靠方法。僅檢查宣告的 `ProjectDependency` 可能會遺漏傳遞或替換的專案依賴關係。
若要取得目標專案的識別,請使用新的隔離專案安全專案路徑方法:ProjectDependency#getPath()
。
若要存取或配置目標專案,請考慮此直接替換
val projectDependency: ProjectDependency = getSomeProjectDependency()
// Old way:
val someProject = projectDependency.dependencyProject
// New way:
val someProject = project.project(projectDependency.path)
此方法不會從不同的建置中提取專案實例。
已棄用 ResolvedConfiguration.getFiles()
和 LenientConfiguration.getFiles()
ResolvedConfiguration.getFiles() 和 LenientConfiguration.getFiles() 方法已棄用,並將在 Gradle 9.0 中移除。
這些已棄用的方法不追蹤任務依賴關係,這與它們的替代方法不同。
val deprecated: Set<File> = conf.resolvedConfiguration.files
val replacement: FileCollection = conf.incoming.files
val lenientDeprecated: Set<File> = conf.resolvedConfiguration.lenientConfiguration.files
val lenientReplacement: FileCollection = conf.incoming.artifactView {
isLenient = true
}.files
已棄用 AbstractOptions
AbstractOptions
類別已棄用,並將在 Gradle 9.0 中移除。所有擴展 AbstractOptions
的類別將不再擴展它。
因此,AbstractOptions#define(Map)
方法將不再存在。此方法公開了非類型安全 API,並且不必要地依賴反射。它可以透過直接設定地圖中指定的屬性來取代。
此外,依賴於 define
的 CompileOptions#fork(Map)
、CompileOptions#debug(Map)
和 GroovyCompileOptions#fork(Map)
也已棄用,將在 Gradle 9.0 中移除。
請考慮以下已棄用行為及其替代方案的範例
tasks.withType(JavaCompile) {
// Deprecated behavior
options.define(encoding: 'UTF-8')
options.fork(memoryMaximumSize: '1G')
options.debug(debugLevel: 'lines')
// Can be replaced by
options.encoding = 'UTF-8'
options.fork = true
options.forkOptions.memoryMaximumSize = '1G'
options.debug = true
options.debugOptions.debugLevel = 'lines'
}
已棄用 Dependency#contentEquals(Dependency)
Dependency#contentEquals(Dependency) 方法已棄用,並將在 Gradle 9.0 中移除。
該方法最初旨在根據依賴關係的實際目標組件來比較依賴關係,無論它們是否屬於不同的依賴關係類型。現有的方法的行為與其 Javadoc 指定的不同,我們不計劃引入替代方法。
潛在的遷移包括直接使用 Object.equals(Object)
,或手動比較依賴關係的欄位。
已棄用 Project#exec
和 Project#javaexec
Project#exec(Closure)、Project#exec(Action)、Project#javaexec(Closure)、Project#javaexec(Action) 方法已棄用,並將在 Gradle 9.0 中移除。
計劃移除這些方法,作為讓編寫與配置快取相容的程式碼更容易的持續努力的一部分。沒有辦法在不違反配置快取要求的情況下使用這些方法,因此建議遷移到相容的替代方案。您的使用案例的適當替代方案取決於先前呼叫該方法的內容。
在執行時,例如在 @TaskAction
或 doFirst
/doLast
回呼中,啟用配置快取時不允許使用 Project
實例。若要執行外部處理程序,任務應使用注入的 ExecOperation
服務,該服務具有相同的 API,並且可以充當直接替換。標準 Java/Groovy/Kotlin 處理程序 API,例如 java.lang.ProcessBuilder
也可以使用。
在配置時,啟用配置快取時,必須僅使用特殊的基於 Provider 的 API 來執行外部處理程序。您可以使用 ProviderFactory.exec
和 ProviderFactory.javaexec
來取得處理程序的輸出。自訂 ValueSource
實作可用於更複雜的場景。配置快取指南提供了一個更詳細的使用這些 API 的範例。
分離的配置不應使用 extendsFrom
分離的配置不應使用 extendsFrom
擴展其他配置。
此行為已棄用,並將在 Gradle 9.0 中變成錯誤。
若要在配置之間建立擴展關係,您應該變更為使用透過專案 ConfigurationContainer
中存在的其他工廠方法建立的非分離配置。
已棄用自訂 Gradle 日誌記錄
Gradle#useLogger(Object) 方法已棄用,並將在 Gradle 9.0 中移除。
此方法最初旨在自訂 Gradle 印出的日誌。但是,它僅允許攔截日誌的子集,並且無法與 配置快取 一起運作。我們不計劃為此功能引入替代方案。
編譯選項和文件任務上不必要的選項已棄用
Gradle 的 API 允許使用 setter 方法完全替換某些表示巢狀屬性群組的屬性。這樣做既笨拙又不尋常,有時還需要使用內部 API。這些屬性的 setter 將在 Gradle 9.0 中移除,以簡化 API 並確保一致的行為。這些屬性應透過呼叫 getter 並直接配置物件或使用方便的配置方法來配置,而不是使用 setter 方法。例如,在 CompileOptions
中,您可以呼叫 getForkOptions()
或 forkOptions(Action)
,而不是呼叫 setForkOptions
setter。
受影響的屬性為
已棄用 Javadoc.isVerbose()
和 Javadoc.setVerbose(boolean)
關於 Javadoc 的這些方法已被棄用,並將在 Gradle 9.0 中移除。
-
呼叫帶有
true
的 setVerbose(boolean) 已由 getOptions().verbose() 取代 -
呼叫
setVerbose(false)
不會執行任何操作。
從 8.9 和更早版本升級
潛在的重大變更
即使不需要編譯,使用 JRE 時,JavaCompile
任務也可能失敗
當使用 JRE 而非 JDK 時,JavaCompile
任務有時可能會失敗。這是由於工具鏈解析程式碼中的變更,該變更在請求編譯器時強制要求編譯器的存在。當未設定 sourceCompatibility
/targetCompatibility
或 release
時,java-base
外掛程式會使用其建立的 JavaCompile
任務來判斷預設的來源和目標相容性。透過新的強制執行,即使不需要編譯(例如,在沒有來源的專案中),當僅提供 JRE 時,缺少編譯器也會導致此操作失敗。
這可以透過在 java
擴充功能中明確設定 sourceCompatibility
/targetCompatibility
,或在相關任務中設定 sourceCompatibility
/targetCompatibility
或 release
來修正。
升級至 Kotlin 1.9.24
內嵌的 Kotlin 已從 1.9.23 更新至 Kotlin 1.9.24。
升級至 Ant 1.10.14
Ant 已更新至 Ant 1.10.14。
升級至 JaCoCo 0.8.12
JaCoCo 已更新至 0.8.12。
升級至 Groovy 3.0.22
Groovy 已更新至 Groovy 3.0.22。
棄用
在較舊的 JVM 上執行 Gradle
從 Gradle 9.0 開始,Gradle 將需要 JVM 17 或更高版本才能執行。大多數 Gradle API 將編譯為目標 JVM 17 位元組碼。
Gradle 仍將支援將 Java 程式碼編譯為目標 JVM 版本 6 或更高版本。編譯程式碼的目標 JVM 版本可以與用於執行 Gradle 的 JVM 版本分開設定。
所有 Gradle 用戶端(wrapper、launcher、Tooling API 和 TestKit)將保持與 JVM 8 相容,並將編譯為目標 JVM 8 位元組碼。只有 Gradle daemon 將需要 JVM 17 或更高版本。這些用戶端可以設定為使用與用於執行用戶端的 JVM 版本不同的 JVM 版本來執行 Gradle 建置
-
使用Daemon JVM 條件(正在孵化中的功能)
-
設定
org.gradle.java.home
Gradle 屬性 -
在 Tooling API 上使用 ConfigurableLauncher#setJavaHome 方法
或者,可以將 JAVA_HOME
環境變數設定為 JVM 17 或更新版本,這將使用相同版本的 JVM 執行用戶端和 daemon。
使用 --no-daemon 執行 Gradle 建置,或在測試中使用 ProjectBuilder 將需要 JVM 版本 17 或更高版本。worker API 將保持與 JVM 8 相容,而執行 JVM 測試將需要 JVM 8。
我們決定升級 Java 執行階段的最低版本,原因如下
-
相依性開始停止支援較舊版本,並且可能不會發布安全性修補程式。
-
Java 8 和 Java 17 之間顯著的語言改進在不升級的情況下無法使用。
-
某些最受歡迎的外掛程式已經需要 JVM 17 或更高版本。
-
Gradle 發行版本的下載指標顯示 JVM 17 已廣泛使用。
已棄用從 Ivy 組件取用不可取用的變體
在先前版本的 Gradle 中,可以使用已發布的 Ivy metadata 來取用專案的不可取用 configurations。Ivy 相依性有時可能會被專案相依性取代,可以是透過 DependencySubstitutions
API 明確取代,也可以透過包含的建置隱含取代。發生這種情況時,可以選取已取代專案中標記為不可取用的 configurations。
以這種方式取用不可取用的 configurations 已被棄用,並且將在 Gradle 9.0 中導致錯誤。
已棄用在同一專案中擴充 configurations
在先前版本的 Gradle 中,可以擴充不同專案中的 configuration。
專案 configurations 的階層結構不應受到其他專案中 configurations 的影響。當 configurations 以 configuration 的擁有者不想要的方式擴充時,跨專案階層結構可能會導致意外行為。
專案也不應存取另一個專案的可變狀態。由於 Configurations 是可變的,因此跨專案界限擴充 configurations 會限制 Gradle 可以應用的平行處理。
在不同專案中擴充 configurations 已被棄用,並且將在 Gradle 9.0 中導致錯誤。
從 8.8 和更早版本升級
潛在的重大變更
工具鏈佈建的變更
在先前版本的 Gradle 中,工具鏈佈建可能會將部分佈建的工具鏈留在原位,並帶有一個標記檔案,指示工具鏈已完全佈建。這可能會導致工具鏈出現奇怪的行為。在 Gradle 8.9 中,工具鏈在寫入標記檔案之前已完全佈建。但是,為了不偵測潛在損壞的工具鏈,使用了不同的標記檔案 (.ready
)。這表示您現有的所有工具鏈在第一次與 Gradle 8.9 一起使用時都將重新佈建。Gradle 8.9 也會寫入舊的標記檔案 (provisioned.ok
),以指示工具鏈已完全佈建。這表示如果您返回到較舊版本的 Gradle,則 8.9 佈建的工具鏈將不會重新佈建。
升級至 Kotlin 1.9.23
內嵌的 Kotlin 已從 1.9.22 更新至 Kotlin 1.9.23。
變更 daemon 記錄檔的編碼
在先前版本的 Gradle 中,位於 $GRADLE_USER_HOME/daemon/8.13/
的 daemon 記錄檔以預設 JVM 編碼進行編碼。此檔案現在始終以 UTF-8 編碼,以防止可能使用不同預設編碼的用戶端錯誤地讀取資料。此變更可能會影響嘗試讀取此檔案的協力廠商工具。
針對 Gradle 實作 classpath 進行編譯
在先前版本的 Gradle 中,沒有宣告相依性的 Java 專案可以隱含地針對 Gradle 的執行階段類別進行編譯。這表示即使某些專案參考了 Gradle 執行階段類別,它們也能夠在沒有任何宣告相依性的情況下進行編譯。這種情況不太可能在專案中出現,因為 IDE 整合和測試執行將會受到影響。但是,如果您需要使用 Gradle API,請宣告 gradleApi
相依性或套用 java-gradle-plugin
外掛程式。
Configuration cache 實作套件現在位於 org.gradle.internal
下
應避免參考不屬於公開 API 的 Gradle 類型,因為不支援直接使用它們。Gradle 內部實作類別可能會遭受重大變更(或被重新命名或移除),恕不另行通知。
使用者需要區分 Gradle 程式碼庫的 API 和內部部分。這通常是透過在實作套件名稱中包含 internal
來實現的。但是,在此版本之前,configuration cache 子系統未遵循此模式。
為了解決此問題,最初位於 org.gradle.configurationcache*
套件下的所有程式碼都已移至新的內部套件 (org.gradle.internal.*
)。
在 macOS 11 (Big Sur) 和更早版本上,檔案系統監看功能已停用
自 Gradle 8.8 以來,檔案系統監看功能僅在 macOS 12 (Monterey) 和更高版本上受支援。我們新增了一個檢查,以在 macOS 11 (Big Sur) 和更早版本上自動停用檔案系統監看功能。
當使用註解處理器時,JDK8 基礎編譯器輸出可能變更
Java 編譯基礎結構已更新為使用 Problems API。此變更將為 Tooling API 用戶端提供關於編譯問題的結構化、豐富資訊。
此功能不應對一般的建置輸出產生任何可見的影響,JDK8 除外。當在編譯器中使用註解處理器時,輸出訊息與先前的訊息略有不同。
變更主要體現在列印的類型名稱中。例如,Java 標準類型(如 java.lang.String
)將報告為 java.lang.String
而不是 String
。
從 8.7 和更早版本升級
棄用
棄用在觀察後變更 configuration
為了確保相依性解析的準確性,Gradle 會檢查 Configurations 在用作相依性圖表的一部分後是否未被變更。
-
可解析的 configurations 不應在其解析策略、相依性、階層結構等在解析後進行修改。
-
可取用的 configurations 不應在其相依性、階層結構、屬性等在發布或作為變體取用後進行修改。
-
相依性範圍 configurations 不應在其相依性、限制等在觀察到從它們擴充的 configuration 後進行修改。
在先前版本的 Gradle 中,許多這些情況都被偵測到並透過使建置失敗來處理。但是,某些情況未被偵測到或未觸發建置失敗。在 Gradle 9.0 中,一旦觀察到對 configuration 的所有變更,都將變成錯誤。在觀察到任何類型的 configuration 後,應將其視為不可變的。此驗證涵蓋 configuration 的以下屬性
-
解析策略
-
相依性
-
限制
-
排除規則
-
成品
-
角色(可取用、可解析、相依性範圍)
-
階層結構 (
extendsFrom
) -
其他(可傳遞、可見)
從 Gradle 8.8 開始,在尚未成為錯誤的情況下,將發出棄用警告。通常,此棄用是由於在 beforeResolve
hook 中變更 configuration 而引起的。此 hook 僅在 configuration 完全解析後執行,而不是在為了計算任務相依性而部分解析時執行。
考慮以下程式碼,展示了已棄用的行為
plugins {
id("java-library")
}
configurations.runtimeClasspath {
// `beforeResolve` is not called before the configuration is partially resolved for
// build dependencies, but only before a full graph resolution.
// Configurations should not be mutated in this hook
incoming.beforeResolve {
// Add a dependency on `com:foo` if not already present
if (allDependencies.none { it.group == "com" && it.name == "foo" }) {
configurations.implementation.get().dependencies.add(project.dependencies.create("com:foo:1.0"))
}
}
}
tasks.register("resolve") {
val conf: FileCollection = configurations["runtimeClasspath"]
// Wire build dependencies
dependsOn(conf)
// Resolve dependencies
doLast {
assert(conf.files.map { it.name } == listOf("foo-1.0.jar"))
}
}
對於以下使用案例,在取代 beforeResolve
hook 時,請考慮以下替代方案
-
新增相依性:在 DependencySet 上使用 DependencyFactory 和
addLater
或addAllLater
。 -
變更相依性版本:使用偏好版本限制。
-
新增排除:使用組件 Metadata 規則來調整相依性層級的排除,或使用 withDependencies 將排除新增至 configuration。
-
角色:Configuration 角色應在建立時設定,之後不應變更。
-
階層結構:Configuration 階層結構 (
extendsFrom
) 應在建立時設定。強烈建議不要在解析之前變更階層結構,但在 withDependencies hook 中允許變更。 -
解析策略:在
beforeResolve
hook 中仍然允許變更 configuration 的 ResolutionStrategy;但是,不建議這樣做。
已棄用篩選的 Configuration file
和 fileCollection
方法
為了簡化 Gradle API 的持續努力,以下支援基於宣告的相依性進行篩選的方法已被棄用
在 Configuration 上
-
files(Dependency…)
-
files(Spec)
-
files(Closure)
-
fileCollection(Dependency…)
-
fileCollection(Spec)
-
fileCollection(Closure)
-
getFiles(Spec)
-
getFirstLevelModuleDependencies(Spec)
-
getFirstLevelModuleDependencies(Spec)
-
getFiles(Spec)
-
getArtifacts(Spec)
為了減輕此棄用,請考慮以下範例,該範例利用 ArtifactView
API 以及 componentFilter
方法來選取 Configuration 成品的子集
val conf by configurations.creating
dependencies {
conf("com.thing:foo:1.0")
conf("org.example:bar:1.0")
}
tasks.register("filterDependencies") {
val files: FileCollection = conf.incoming.artifactView {
componentFilter {
when(it) {
is ModuleComponentIdentifier ->
it.group == "com.thing" && it.module == "foo"
else -> false
}
}
}.files
doLast {
assert(files.map { it.name } == listOf("foo-1.0.jar"))
}
}
configurations {
conf
}
dependencies {
conf "com.thing:foo:1.0"
conf "org.example:bar:1.0"
}
tasks.register("filterDependencies") {
FileCollection files = configurations.conf.incoming.artifactView {
componentFilter {
it instanceof ModuleComponentIdentifier
&& it.group == "com.thing"
&& it.module == "foo"
}
}.files
doLast {
assert files*.name == ["foo-1.0.jar"]
}
}
與已棄用的 Dependency
篩選方法相反,componentFilter
不考慮正在篩選的組件的傳遞相依性。這允許對選取哪些成品進行更精細的控制。
已棄用 Task
和 Configuration
的 Namer
Task
和 Configuration
具有 Namer
內部類別(也稱為 Namer
),可以用作擷取任務或 configuration 名稱的通用方式。現在這些類型實作了 Named
,這些類別不再必要,並且已被棄用。它們將在 Gradle 9.0 中移除。請改用 Named.Namer.INSTANCE
。
超級介面 Namer
未被棄用。
已棄用直接在本地建置快取上設定保留期限
在先前版本中,本地建置快取條目的清除每 24 小時執行一次,並且此間隔無法設定。保留期限是使用 buildCache.local.removeUnusedEntriesAfterDays
設定的。
在 Gradle 8.0 中,新增了一種新機制,用於設定 Gradle User Home 中各種資源的清除和保留期限。在 Gradle 8.8 中,此機制已擴充為允許本地建置快取條目的保留設定,從而提供改進的控制和一致性。
-
指定
Cleanup.DISABLED
或Cleanup.ALWAYS
現在將防止或強制清除本地建置快取 -
建置快取條目保留現在透過
init-script
進行設定,方式與其他快取相同。
如果您希望建置快取條目保留 30 天,請移除對已棄用方法的任何呼叫
buildCache {
local {
// Remove this line
removeUnusedEntriesAfterDays = 30
}
}
在 ~/.gradle/init.d
中新增如下檔案
beforeSettings {
caches {
buildCache.setRemoveUnusedEntriesAfterDays(30)
}
}
呼叫 buildCache.local.removeUnusedEntriesAfterDays 已被棄用,此方法將在 Gradle 9.0 中移除。如果設定為非預設值,則此已棄用的設定將優先於 Settings.caches.buildCache.setRemoveUnusedEntriesAfterDays()
。
已棄用 Kotlin DSL gradle-enterprise 外掛程式區塊擴充功能
在 settings.gradle.kts
(Kotlin DSL) 中,您可以使用外掛程式區塊中的 gradle-enterprise
來套用與 gradle --scan
相同版本的 Gradle Enterprise 外掛程式。
plugins {
`gradle-enterprise`
}
在 settings.gradle
(Groovy DSL) 中沒有與此等效的功能。
Gradle Enterprise 已重新命名為 Develocity,並且 com.gradle.enterprise
外掛程式已重新命名為 com.gradle.develocity
。因此,gradle-enterprise
外掛程式區塊擴充功能已被棄用,並將在 Gradle 9.0 中移除。
Develocity 外掛程式必須使用明確的外掛程式 ID 和版本套用。在外掛程式區塊中沒有可用的 develocity
簡寫
plugins {
id("com.gradle.develocity") version "3.17.3"
}
如果您想繼續使用 Gradle Enterprise 外掛程式,您可以指定已棄用的外掛程式 ID
plugins {
id("com.gradle.enterprise") version "3.17.3"
}
我們鼓勵您使用最新的已發布 Develocity 外掛程式版本,即使在使用較舊的 Gradle 版本時也是如此。
潛在的重大變更
Problems API 的變更
我們已實作 Problems API 的多項重構,包括問題定義和情境資訊處理方式的重大變更。完整的設計規格可以在此處找到。
在實作此規格時,我們對 ProblemSpec
介面引入了以下重大變更
-
label(String)
和description(String)
方法已由id(String, String)
方法及其多載變體取代。
集合屬性的變更
以下在 8.7 中引入的孵化 API 已移除
-
MapProperty.insert*(…)
-
HasMultipleValues.append*(…)
更好地處理慣例的替代方案正在考慮用於未來的 8.x 版本。
升級至 Groovy 3.0.21
Groovy 已更新至 Groovy 3.0.21。
靜態類型檢查中的一些變更已導致原始碼不相容。從 3.0.18 開始,如果您將 closure 轉換為沒有泛型的 Action
,則 closure 參數將為 Object
而不是任何指定的明確類型。這可以透過將適當的類型新增至轉換來修正,並且可以移除多餘的參數宣告
// Before
tasks.create("foo", { Task it -> it.description = "Foo task" } as Action)
// Fixed
tasks.create("foo", { it.description = "Foo task" } as Action<Task>)
升級至 ASM 9.7
ASM 從 9.6 升級到 9.7,以確保更早版本的 Java 23 相容性。
從 8.6 和更早版本升級
潛在的重大變更
升級至 Kotlin 1.9.22
內嵌的 Kotlin 已從 1.9.10 更新至 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。
這包括重新設計 Gradle 為 SSH 作業設定 JGit 的方式,從 JSch 移至 Apache SSHD。
升級至 Apache Commons Compress 1.25.0
Apache Commons Compress 已從 1.21 更新至 1.25.0。此變更可能會影響產生的 jar、zip 和其他封存類型的總和檢查碼,因為產生的成品的 metadata 可能會有所不同。
升級至 ASM 9.6
ASM 從 9.5 升級到 9.6,以更好地支援多版本 jar。
棄用
已棄用外掛程式慣例的註冊
自 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>
}
Gradle API 和 Groovy 建置腳本不受此影響。
已棄用無效 URL 解碼行為
在 Gradle 8.3 之前,Gradle 會使用一種演算法來解碼提供給 Project.uri(Object)
的 CharSequence
,該演算法接受無效 URL 並不正確地解碼其他 URL。Gradle 現在使用 URI
類別來剖析和解碼 URL,但在發生錯誤時會回退到舊版行為。
從 Gradle 9.0 開始,將移除回退,並改為擲回錯誤。
為了修正棄用警告,需要舊版行為的無效 URL 應重新編碼為有效 URL,例如在以下範例中
原始輸入 | 新輸入 | 原因 |
---|---|---|
|
|
|
|
|
在沒有方案的情況下,路徑按原樣採用,不進行解碼。 |
|
空格在 URL 中無效。 |
|
|
||
file::somepath |
somepath |
URI 應為階層式。 |
已棄用 SelfResolvingDependency
SelfResolvingDependency
介面已被棄用,將在 Gradle 9.0 中移除。此類型可追溯到 Gradle 的第一個版本,其中某些相依性可以獨立解析。現在,所有相依性都應作為相依性圖表的一部分使用 Configuration
進行解析。
目前,ProjectDependency
和 FileCollectionDependency
實作了此介面。在 Gradle 9.0 中,這些類型將不再實作 SelfResolvingDependency
。相反,它們都將直接實作 Dependency
。
因此,ProjectDependency
和 FileCollectionDependency
的以下方法將不再可用
-
resolve
-
resolve(boolean)
-
getBuildDependencies
請考慮以下腳本,展示了已棄用的介面及其取代項
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"))
}
}
從 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
來源集時,會建立新的 implementation
、compileOnly
、runtimeOnly
、api
和 compileOnlyApi
configurations,並且設定 main
來源集的編譯和執行階段 classpath 以擴充這些 configurations。
從 Gradle 9.0 開始,main
來源集將被視為任何其他來源集。在套用 java-library
外掛程式(或任何其他套用 java
外掛程式的外掛程式)的情況下,使用 main
來源集呼叫 usingSourceSet
將會擲回例外。這是因為 java
外掛程式已經設定了 main
功能。只有在未套用 java
外掛程式的情況下,才允許在使用 usingSourceSet
時使用 main
來源集。
目前使用 main 來源集註冊功能的程式碼,例如
plugins {
id("java-library")
}
java {
registerFeature("feature") {
usingSourceSet(sourceSets["main"])
}
}
plugins {
id("java-library")
}
java {
registerFeature("feature") {
usingSourceSet(sourceSets.main)
}
}
應該改為為功能建立單獨的來源集,並使用該來源集註冊功能
plugins {
id("java-library")
}
sourceSets {
create("feature")
}
java {
registerFeature("feature") {
usingSourceSet(sourceSets["feature"])
}
}
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
宣告的一樣
dependencies {
implementation("org:foo:1.0") {
artifact {
name = "notfoo"
}
}
}
dependencies {
implementation("org:foo:1.0") {
artifact {
name = "notfoo"
}
}
}
相反,此相依性應宣告為
dependencies {
implementation("org:notfoo:1.0")
}
dependencies {
implementation("org:notfoo:1.0")
}
已棄用 ArtifactIdentifier
ArtifactIdentifier
類別已被棄用,將在 Gradle 9.0 中移除。
棄用在觀察後變更 DependencyCollector
相依性
從 Gradle 9.0 開始,變更源自 DependencyCollector 的相依性,在觀察到這些相依性後,將導致錯誤。DependencyCollector
介面用於在測試套件 DSL 中宣告相依性。
考慮以下範例,其中測試套件的相依性在觀察到後被變更
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 版本限制取代了上述迭代
dependencies {
constraints {
testImplementation("com:foo") {
version {
prefer("2.0")
}
}
}
}
從 8.4 和更早版本升級
潛在的重大變更
升級至 Kotlin 1.9.20
嵌入式 Kotlin 已更新至 Kotlin 1.9.20。
Groovy 任務慣例的變更
現在由 groovy-base
外掛程式負責在所有 GroovyCompile
任務上設定來源和目標相容性版本慣例。
如果您在未套用 groovy-base
的情況下使用此任務,您將必須在這些任務上手動設定相容性版本。一般來說,每當使用 Groovy 語言任務時,都應套用 groovy-base
外掛程式。
Provider.filter
為了 API 更加一致,傳遞給 Provider.filter
的引數類型已從 Predicate
變更為 Spec
。此變更不應影響任何使用 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 將不會執行組建。如果您打算動態合成專案,請務必也為它們建立目錄
include("project-without-directory")
project(":project-without-directory").projectDir.mkdirs()
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 解析器的相依性。
如果您是 Android 使用者,請將您的 AGP 版本升級到 8.3.0 或更高版本,以修正 AGP 本身造成的問題。請參閱 Update XML parser used in AGP for Gradle 8.4 compatibility 以取得更多詳細資訊。
如果您無法升級來自組建邏輯相依性的 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
請參閱 CVE-2023-42445 諮詢文件,以取得更多詳細資訊以及在先前的 Gradle 版本上啟用安全 XML 處理的方法。
具有自訂 JEE 1.3 描述器的 EAR 外掛程式
Gradle 8.4 禁止在解析 XML 文件時使用外部 XML 實體。如果您使用 EAR 外掛程式,並透過 EAR 外掛程式的 DSL 設定 application.xml
描述器,並使用 withXml {}
自訂描述器,並在自訂區塊中使用 asElement{}
,則組建現在會因安全性原因而失敗。
plugins {
id("ear")
}
ear {
deploymentDescriptor {
version = "1.3"
withXml {
asElement()
}
}
}
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
介面是 Tooling API 的一部分,專門用於執行測試。它是 BuildLauncher
的邏輯擴充,只能啟動任務。已報告它們的行為存在差異:如果執行相同的失敗測試,BuildLauncher
將報告組建失敗,但 TestLauncher
不會。最初,這是一個設計決策,目的是繼續執行並在所有測試任務中執行測試,而不是在第一次失敗時停止。同時,此行為可能會讓使用者感到困惑,因為他們可能會在成功的組建中遇到失敗的測試。為了使兩個 API 更一致,我們也讓 TestLauncher
使組建失敗,這是一個潛在的重大變更。Tooling API 用戶端應明確將 --continue
傳遞給組建,即使測試任務失敗也繼續執行測試。
使用 ArtifactView
和 ArtifactCollection
修復變體選取行為
用於選取不同成品或檔案的相依性解析 API(Configuration.getIncoming().artifactView { }
和 Configuration.getIncoming().getArtifacts()
)擷取基礎 Configuration
屬性的不可變副本,以用於變體選取。如果在呼叫這些方法後變更了 Configuration
的屬性,則這些方法選取的成品可能會出乎意料。
考慮在建立 ArtifactView
後變更 Configuration
上的屬性集的情況
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
}
}
}
myTask
的 inputFiles
屬性使用成品檢視,從組態 classpath
中選取不同類型的成品。由於成品檢視是在將屬性新增至組態之前建立的,因此 Gradle 無法選取正確的成品。
某些組建可能透過也將其他屬性放入成品檢視中來解決此問題。現在已不再需要這樣做。
升級至 Kotlin 1.9.0
嵌入式 Kotlin 已從 1.8.20 更新至 Kotlin 1.9.0。Kotlin DSL 的 Kotlin 語言和 API 層級仍設定為 1.8 以保持回溯相容性。請參閱 Kotlin 1.8.22 和 Kotlin 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.libraryelements
和 org.gradle.jvm.version
屬性,使其在建立時就存在,而不是像以前那樣,僅在組態已解析或消耗後才存在。特別是,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 工具鏈。為了避免工具鏈過早最終確定,應更新屬性複製邏輯以延遲查詢來源組態的屬性
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)
}
}
}
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
內使用該屬性來展開它。相反,您應該利用 dir
和 file
方法來計算您想要的位置。
以下是一個建立檔案的範例,其中以下內容
// Returns a java.io.File
file("$buildDir/myOutput.txt")
// Returns a java.io.File
file("$buildDir/myOutput.txt")
應替換為
// 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 }
// 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 }
以下是另一個建立目錄的範例,其中以下內容
// Returns a java.io.File
file("$buildDir/outputLocation")
// Returns a java.io.File
file("$buildDir/outputLocation")
應替換為
// 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 }
// 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 中移除。
用戶端模組相依性最初旨在允許組建透過在本機定義中繼資料來覆寫外部相依性的不正確或遺失的元件中繼資料。此功能自此已被 元件中繼資料規則 取代。
考慮以下用戶端模組相依性範例
dependencies {
implementation(module("org:foo:1.0") {
dependency("org:bar:1.0")
module("org:baz:1.0") {
dependency("com:example:1.0")
}
})
}
dependencies {
implementation module("org:foo:1.0") {
dependency "org:bar:1.0"
module("org:baz:1.0") {
dependency "com:example:1.0"
}
}
}
這可以用以下元件中繼資料規則取代
@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)
}
}
}
}
}
}
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")
}
@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)
}
}
}
}
}
}
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 以取得更多資訊。
升級至 CodeNarc 3.2.0
CodeNarc 的預設版本已更新至 CodeNarc 3.2.0。
升級至 JaCoCo 0.8.9
JaCoCo 已更新至 0.8.9。
外掛程式相容性變更
使用 Gradle >= 8.2 編譯的外掛程式,如果使用 Kotlin DSL 函數 Project.the<T>()
、Project.the(KClass)
或 Project.configure<T> {}
,則無法在 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()
- 僅限可解析組態 -
files(Closure)
、files(Spec)
、files(Dependency…)
、fileCollection(Spec)
、fileCollection(Closure)
、fileCollection(Dependency…)
- 僅限可解析組態 -
getResolvedConfigurations()
- 僅限可解析組態 -
defaultDependencies(Action)
- 僅限可宣告組態 -
shouldResolveConsistentlyWith(Configuration)
- 僅限可解析組態 -
disableConsistentResolution()
- 僅限可解析組態 -
getDependencyConstraints()
- 僅限可宣告組態 -
copy()
、copy(Spec)
、copy(Closure)
、copyRecursive()
、copyRecursive(Spec)
、copyRecursive(Closure)
- 僅限可解析組態
預期用途已在 Configuration
介面的 Javadoc 中註明。此清單可能會在未來版本中擴大。
從 Gradle 9.0 開始,將禁止不一致地使用組態及其預期用途。
另請注意,儘管目前未受限制,但 getDependencies()
方法僅適用於可宣告組態。getAllDependencies()
方法(檢索組態及其任何超組態上的所有宣告相依性)將不受任何特定用途的限制。
已棄用的外掛程式慣例存取
慣例的概念已過時,並已被 擴充功能 取代,以提供自訂 DSL。
為了在 Gradle API 中反映這一點,以下元素已棄用
-
org.gradle.api.internal.HasConvention
Gradle Core 外掛程式仍然註冊其慣例以及其擴充功能,以實現回溯相容性。
存取任何這些慣例及其屬性已被棄用。現在執行此操作將發出棄用警告。這將在 Gradle 9.0 中變成錯誤。您應該改為偏好存取擴充功能及其屬性。
有關具體範例,請參閱下一節。
著名的社群外掛程式已經遷移到使用擴充功能來提供自訂 DSL。其中一些外掛程式仍然註冊慣例以實現回溯相容性。註冊慣例尚不會發出棄用警告,以提供遷移窗口。未來的 Gradle 版本將會這樣做。
另請注意,使用 Gradle ⇐ 8.1 編譯的外掛程式,如果使用 Kotlin DSL 函數 Project.the<T>()
、Project.the(KClass)
或 Project.configure<T> {}
,在 Gradle >= 8.2 上執行時將發出棄用警告。為了修正此問題,應使用 Gradle >= 8.2 重新編譯這些外掛程式,或變更為直接使用 extensions.getByType<T>()
存取擴充功能。
已棄用的 base
外掛程式慣例
由 base
外掛程式貢獻的慣例屬性已棄用,並計劃在 Gradle 9.0 中移除。如需更多背景資訊,請參閱有關 外掛程式慣例棄用的章節。
慣例已由 base { }
組態區塊取代,後者由 BasePluginExtension 支援。舊的慣例物件定義了具有簡單 getter 和 setter 方法的 distsDirName,
libsDirName
和 archivesBaseName
屬性。這些方法僅在擴充功能中可用,以維持回溯相容性。組建指令碼應僅使用 Property
類型的屬性
plugins {
base
}
base {
archivesName.set("gradle")
distsDirectory.set(layout.buildDirectory.dir("custom-dist"))
libsDirectory.set(layout.buildDirectory.dir("custom-libs"))
}
plugins {
id 'base'
}
base {
archivesName = "gradle"
distsDirectory = layout.buildDirectory.dir('custom-dist')
libsDirectory = layout.buildDirectory.dir('custom-libs')
}
已棄用的 application
外掛程式慣例
application
外掛程式貢獻的慣例屬性已棄用,並計劃在 Gradle 9.0 中移除。如需更多背景資訊,請參閱有關 外掛程式慣例棄用的章節。
以下程式碼現在將發出棄用警告
plugins {
application
}
applicationDefaultJvmArgs = listOf("-Dgreeting.language=en") // Accessing a convention
plugins {
id 'application'
}
applicationDefaultJvmArgs = ['-Dgreeting.language=en'] // Accessing a convention
應將其變更為使用 application { }
組態區塊,後者由 JavaApplication 支援,而是
plugins {
application
}
application {
applicationDefaultJvmArgs = listOf("-Dgreeting.language=en")
}
plugins {
id 'application'
}
application {
applicationDefaultJvmArgs = ['-Dgreeting.language=en']
}
已棄用的 java
外掛程式慣例
java
外掛程式貢獻的慣例屬性已棄用,並計劃在 Gradle 9.0 中移除。如需更多背景資訊,請參閱有關 外掛程式慣例棄用的章節。
以下程式碼現在將發出棄用警告
plugins {
id("java")
}
configure<JavaPluginConvention> { // Accessing a convention
sourceCompatibility = JavaVersion.VERSION_18
}
plugins {
id 'java'
}
sourceCompatibility = 18 // Accessing a convention
應將其變更為使用 java { }
組態區塊,後者由 JavaPluginExtension 支援,而是
plugins {
id("java")
}
java {
sourceCompatibility = JavaVersion.VERSION_18
}
plugins {
id 'java'
}
java {
sourceCompatibility = JavaVersion.VERSION_18
}
已棄用的 war
外掛程式慣例
由 war
外掛程式貢獻的慣例屬性已棄用,並計劃在 Gradle 9.0 中移除。如需更多背景資訊,請參閱有關 外掛程式慣例棄用的章節。
以下程式碼現在將發出棄用警告
plugins {
id("war")
}
configure<WarPluginConvention> { // Accessing a convention
webAppDirName = "src/main/webapp"
}
plugins {
id 'war'
}
webAppDirName = 'src/main/webapp' // Accessing a convention
用戶端應直接組態 war
任務。此外,tasks.withType(War.class).configureEach(…) 可用於組態 War
類型的每個任務。
plugins {
id("war")
}
tasks.war {
webAppDirectory.set(file("src/main/webapp"))
}
plugins {
id 'war'
}
war {
webAppDirectory = file('src/main/webapp')
}
已棄用的 ear
外掛程式慣例
由 ear
外掛程式貢獻的慣例屬性已棄用,並計劃在 Gradle 9.0 中移除。如需更多背景資訊,請參閱有關 外掛程式慣例棄用的章節。
以下程式碼現在將發出棄用警告
plugins {
id("ear")
}
configure<EarPluginConvention> { // Accessing a convention
appDirName = "src/main/app"
}
plugins {
id 'ear'
}
appDirName = 'src/main/app' // Accessing a convention
用戶端應直接組態 ear
任務。此外,tasks.withType(Ear.class).configureEach(…) 可用於組態 Ear
類型的每個任務。
plugins {
id("ear")
}
tasks.ear {
appDirectory.set(file("src/main/app"))
}
plugins {
id 'ear'
}
ear {
appDirectory = file('src/main/app') // use application metadata found in this folder
}
已棄用的 project-report
外掛程式慣例
由 project-reports
外掛程式貢獻的慣例屬性已棄用,並計劃在 Gradle 9.0 中移除。如需更多背景資訊,請參閱有關 外掛程式慣例棄用的章節。
以下程式碼現在將發出棄用警告
plugins {
`project-report`
}
configure<ProjectReportsPluginConvention> {
projectReportDirName = "custom" // Accessing a convention
}
plugins {
id 'project-report'
}
projectReportDirName = "custom" // Accessing a convention
請改為組態您的報告任務
plugins {
`project-report`
}
tasks.withType<HtmlDependencyReportTask>() {
projectReportDirectory.set(project.layout.buildDirectory.dir("reports/custom"))
}
plugins {
id 'project-report'
}
tasks.withType(HtmlDependencyReportTask) {
projectReportDirectory = project.layout.buildDirectory.dir("reports/custom")
}
依賴自動測試框架實作相依性
在某些情況下,Gradle 將從 Gradle 發行版本載入 JVM 測試框架相依性以執行測試。這種現有行為可能會導致測試類別路徑上的測試框架相依性版本衝突。為了避免這些衝突,此行為已棄用,並將在 Gradle 9.0 中移除。使用 TestNG 的測試不受影響。
為了準備此行為的變更,請明確宣告所需的相依性,或遷移到 Test Suites,在其中自動管理這些相依性。
Test Suites
使用測試套件的組建將不受此變更的影響。測試套件會自動管理測試框架相依性,並且不需要明確宣告相依性。請參閱 使用者手冊 以取得有關遷移到測試套件的更多資訊。
手動宣告相依性
在沒有測試套件的情況下,必須在測試執行階段類別路徑上手動宣告相依性
-
如果使用 JUnit 5,除了現有的測試引擎
implementation
相依性之外,還需要對junit-platform-launcher
進行明確的runtimeOnly
相依性。 -
如果使用 JUnit 4,則只需要現有的
junit
4 的implementation
相依性。 -
如果使用 JUnit 3,除了
junit
3 的compileOnly
相依性之外,還需要對junit
4 進行測試runtimeOnly
相依性。
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")
}
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'
}
BuildIdentifier
和 ProjectComponentSelector
方法棄用
BuildIdentifier
上的以下方法已棄用
-
getName()
-
isCurrentBuild()
您可以使用這些方法來區分來自不同組建但具有相同名稱的不同專案元件。但是,對於某些複合組建設定,這些方法無法提供足夠的資訊來保證唯一性。
目前對這些方法的使用應遷移至 BuildIdentifier.getBuildPath()
。
同樣,方法 ProjectComponentSelector.getBuildName()
已棄用。請改用 ProjectComponentSelector.getBuildPath()
。
從 8.0 及更早版本升級
CACHEDIR.TAG 檔案在全域快取目錄中建立
Gradle 現在在某些全域快取目錄中發出 CACHEDIR.TAG
檔案,如 directory_layout.html 中所指定。
這可能會導致某些工具不再搜尋或備份這些目錄。若要停用它,請在 Gradle 使用者首頁的 init 指令碼中使用以下程式碼
beforeSettings {
caches {
// Disable cache marking for all caches
markingStrategy.set(MarkingStrategy.NONE)
}
}
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…
屬性在此版本中繼續受到尊重,如果使用它們,將不會產生任何警告,但它們將被棄用並在未來版本中移除。
潛在的重大變更
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
外掛程式現在會讓建置失敗,因為其必要的編譯器引數已被您的組態覆寫。
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
外掛程式所需的引數中
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 起,使用 Project.exec
、Project.javaexec
以及標準 Java 和 Groovy API 在組態時間執行外部程序,只有在啟用功能預覽 STABLE_CONFIGURATION_CACHE
時才被視為錯誤。隨著組態快取在 Gradle 8.1 中升級為穩定功能,無論功能預覽狀態如何,都會偵測到此錯誤。組態快取章節提供了更多詳細資訊,以協助遷移到新的基於供應器的 API,以便在組態時間執行外部程序。
不使用組態快取或僅在執行時間啟動外部程序的建置不受此變更影響。
棄用
變更核心外掛程式組態的允許用法
組態的允許用法在建立後應為不可變更的。變更 Gradle 核心外掛程式建立的組態的允許用法已被棄用。這包括呼叫以下任何 Configuration
方法
-
setCanBeConsumed(boolean)
-
setCanBeResolved(boolean)
這些方法現在會在這些組態上發出棄用警告,但某些特殊情況除外,這些特殊情況允許熱門外掛程式的現有行為。此規則尚不適用於分離的組態或在建置腳本和協力廠商外掛程式中建立的組態。為了避免在使用精選熱門協力廠商外掛程式時發出的警告,在 apiElements
或 runtimeElements
上呼叫 setCanBeConsumed(false)
尚未棄用。
此變更是為了使組態的預期行為更加一致和可預測,並在此 Gradle 領域中解鎖更多速度和記憶體改進的更大規模的持續努力的一部分。
在建立後變更組態的允許用法的能力將在 Gradle 9.0 中移除。
保留的組態名稱
組態名稱 "detachedConfiguration" 和 "detachedConfigurationX"(其中 X 為任何整數)保留供內部使用,用於建立分離的組態。
在 Gradle 9.0 中,將移除使用這些名稱建立非分離組態的能力。
在沒有 java
組件的情況下,在 JavaPluginExtension
上呼叫 select 方法
從 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 開始,此方法將被移除,不提供替代方案。
依賴自訂 Test 任務的慣例
預設情況下,當套用 java
外掛程式時,所有 Test
任務的 testClassesDirs`和 `classpath
都具有相同的慣例。除非另行變更,否則預設行為是透過使用來自 test
套件的 classpath
和 testClassesDirs
組態任務,從預設 test
TestSuite
執行測試。此行為將在 Gradle 9.0 中移除。
雖然此現有預設行為對於在不同環境下執行預設單元測試套件的使用案例是正確的,但它不支援執行完全獨立的測試集的使用案例。
如果您希望繼續包含這些測試,請使用以下程式碼以避免 8.1 中的棄用警告,並為 9.0 中的行為變更做好準備。或者,考慮遷移到測試套件。
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 })
}
tasks.myTestTask {
testClassesDirs = testing.suites.test.sources.output.classesDirs
classpath = testing.suites.test.sources.runtimeClasspath
}
在發佈已填入後修改 Gradle 模組中繼資料
在從元件填入 Maven 或 Ivy 發佈之後,變更 GMM(例如,變更元件組態變體)現在已被棄用。此功能將在 Gradle 9.0 中移除。
如果呼叫以下方法,可能會發生發佈的急切填入
-
Maven
-
Ivy
先前,以下程式碼不會產生警告,但會在發佈的成品之間建立不一致
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() }
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 {}
區塊中,從相依性版本目錄存取 libraries
或 bundles
在 Kotlin 腳本的 plugins {}
區塊中,從相依性版本目錄存取 libraries
或 bundles
已被棄用。請僅在 plugins {}
區塊中使用相依性版本目錄中的 versions
或 plugins
。
在沒有 Java Toolchain 的情況下使用 ValidatePlugins
任務
在沒有套用 Java Toolchains 外掛程式的情況下使用 ValidatePlugins 類型的任務已被棄用,並且在 Gradle 9.0 中將會變成錯誤。
為了避免此警告,請將外掛程式套用到您的專案
plugins {
id("jvm-toolchains")
}
plugins {
id 'jvm-toolchains'
}
Java Toolchains 外掛程式由 Java library 外掛程式或其他 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
,以避免在下一個主要版本中發出警告和潛在錯誤。
在 StartParameter
和 GradleBuild
上設定自訂建置版面配置
繼 Gradle 7.1 中相關的先前棄用行為之後,現在也棄用了使用相關的 StartParameter 和 GradleBuild 屬性。這些屬性將在 Gradle 9.0 中移除。
在 GradleBuild 任務中,使用 buildFile 屬性設定自訂建置檔案已被棄用。
請改用 dir 屬性來指定巢狀建置的根目錄。或者,考慮使用 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
if (GradleVersion.current() >= GradleVersion.version('8.0')) {
apply from: "gradle8/cache-settings.gradle"
}
if (GradleVersion.current() >= GradleVersion.version("8.0")) {
apply(from = "gradle8/cache-settings.gradle")
}
beforeSettings { settings ->
settings.caches {
cleanup = Cleanup.DEFAULT
}
}
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 {}
區塊中使用版本目錄顯示誤報錯誤的解決方法已不再需要
IntelliJ IDEA 和 Android Studio Kotlin 腳本編輯器中不再將 plugins {}
區塊中外掛程式別名的版本目錄存取器顯示為錯誤。
如果您使用 @Suppress("DSL_SCOPE_VIOLATION")
註解作為解決方法,您現在可以移除它。
如果您使用 Gradle Libs Error Suppressor IntelliJ IDEA 外掛程式,您現在可以解除安裝它。
升級 Gradle 至 8.1 後,您將需要清除 IDE 快取並重新啟動。