// Copyright (C) 2023 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[upgrading_version_8]]
= Upgrading your build from Gradle 8.x to the latest

This chapter provides the information you need to migrate your Gradle 8.x builds to the latest Gradle release.
For migrating from Gradle 4.x, 5.x, 6.x, or 7.x, see the <<upgrading_version_7.adoc#upgrading_version_7, older migration guide>> first.

We recommend the following steps for all users:

. Try running `gradle help --scan` and view the https://gradle.com/enterprise/releases/2018.4/#identify-usages-of-deprecated-gradle-functionality[deprecations view] of the generated build scan.
+
image::deprecations.png[Deprecations View of a Gradle Build Scan]
+
This is so you can see any deprecation warnings that apply to your build.
+
Alternatively, you can run `gradle help --warning-mode=all` to see the deprecations in the console, though it may not report as much detailed information.
. Update your plugins.
+
Some plugins will break with this new version of Gradle, for example because they use internal APIs that have been removed or changed.
The previous step will help you identify potential problems by issuing deprecation warnings when a plugin does try to use a deprecated part of the API.
+
. Run `gradle wrapper --gradle-version {gradleVersion}` to update the project to {gradleVersion}.
. Try to run the project and debug any errors using the <<troubleshooting.adoc#troubleshooting, Troubleshooting Guide>>.

[[changes_8.7]]
== Upgrading from 8.6 and earlier

=== Potential breaking changes

==== Upgrade to Kotlin 1.9.22

The embedded Kotlin has been updated to link:https://github.com/JetBrains/kotlin/releases/tag/v1.9.22[Kotlin 1.9.22].

==== Upgrade to Apache SSHD 2.10.0

Apache SSHD has been updated from 2.0.0 to https://mina.apache.org/sshd-project/download_2.10.0.html[2.10.0].

==== Replacement and upgrade of JSch

http://www.jcraft.com/jsch/[JSch] has been replaced by https://github.com/mwiede/jsch[`com.github.mwiede:jsch`] and updated from 0.1.55 to https://github.com/mwiede/jsch/releases/tag/jsch-0.2.16[0.2.16]

==== Upgrade to Eclipse JGit 5.13.3

Eclipse JGit has been updated from 5.7.0 to https://projects.eclipse.org/projects/technology.jgit/releases/5.13.3[5.13.3].

This includes reworking the way that Gradle configures JGit for SSH operations by moving from JSch to Apache SSHD.

==== Upgrade to Apache Commons Compress 1.25.0

Apache Commons Compress has been updated from 1.21 to https://commons.apache.org/proper/commons-compress/changes-report.html#a1.25.0[1.25.0].
This change may affect the checksums of the produced jars, zips, and other archive types because the metadata of the produced artifacts may differ.

==== Upgrade to ASM 9.6

ASM was upgraded from 9.5 to https://asm.ow2.io/versions.html[9.6] for better support of multi-release jars.

==== Upgrade of the version catalog parser

The version catalog parser has been upgraded and is now compliant with https://toml.io/en/v1.0.0[version 1.0.0 of the TOML spec].

This should not impact catalogs that use the <<platforms.adoc#sub::toml-dependencies-format,recommended syntax>> or were generated by Gradle for publication.

=== Deprecations

==== Deprecated registration of plugin conventions

Using plugin conventions has been emitting warnings since Gradle 8.2.
Now, registering plugin conventions will also trigger deprecation warnings.
For more information, see the <<deprecated_access_to_conventions, section about plugin convention deprecation>>.

[[string_invoke]]
==== Referencing tasks and domain objects by `"name"()` in Kotlin DSL

In Kotlin DSL, it is possible to reference a task or other domain object by its name using the `"name"()` notation.

There are several ways to look up an element in a container by 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
    }
}
```

The first notation is deprecated and will be removed in Gradle 9.0.
Instead of using `"name"()` to reference a task or domain object, use `named("name")` or one of the other supported notations.

The above example would be written:
```
tasks {
    named("wrapper") // returns TaskProvider<Task>
}
```

Groovy DSL build scripts and the Gradle API are not impacted by this.

[[deprecated_invalid_url_decoding]]
==== Deprecated invalid URL decoding behavior
Prior to Gradle 8.3, Gradle would decode a `CharSequence` given to `link:{groovyDslPath}/org.gradle.api.Project.html#org.gradle.api.Project:uri(java.lang.Object)[Project.uri(Object)]` using an algorithm that accepted invalid URLs and improperly decoded others.
Gradle now uses the `URI` class to parse and decode URLs, but with a fallback to the legacy behavior in the event of an error.

Starting in Gradle 9.0, the fallback will be removed, and an error will be thrown instead.

To fix a deprecation warning, invalid URLs that require the legacy behavior should be re-encoded to be valid URLs, such as in the following examples:

.Legacy URL Conversions
|===
| Original Input | New Input | Reasoning

| `file:relative/path` | `relative/path` | The `file` scheme does not support relative paths.
| `file:relative/path%21` | `relative/path!` | Without a scheme, the path is taken as-is, without decoding.
| `https://example.com/my folder/` | `https://example.com/my%20folder/` | Spaces are not valid in URLs.
| `https://example.com/my%%badly%encoded%path` | `https://example.com/my%25%25badly%25encoded%25path` | `%` must be encoded as `%25` in URLs, and no `%`-escapes should be invalid.
|===

[[deprecate_self_resolving_dependency]]
==== Deprecated `SelfResolvingDependency`

The `SelfResolvingDependency` interface has been deprecated for removal in Gradle 9.0.
This type dates back to the first versions of Gradle, where some dependencies could be resolved independently.
Now, all dependencies should be resolved as part of a dependency graph using a `Configuration`.

Currently, `ProjectDependency` and `FileCollectionDependency` implement this interface.
In Gradle 9.0, these types will no longer implement `SelfResolvingDependency`.
Instead, they will both directly implement `Dependency`.

As such, the following methods of `ProjectDependency` and `FileCollectionDependency` will no longer be avaDilable:

- `resolve`
- `resolve(boolean)`
- `getBuildDependencies`

Consider the following scripts that showcase the deprecated interface and its replacement:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("java-library")
}

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

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

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

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

    // Wire build dependencies
    dependsOn(conf)

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

[[org_gradle_util_reports_deprecations]]
==== Deprecated members of the `org.gradle.util` package now report their deprecation

These members will be removed in Gradle 9.0.

* `Collection.stringize(Collection)`

[[changes_8.6]]
== Upgrading from 8.5 and earlier

=== Potential breaking changes

==== Upgrade to JaCoCo 0.8.11

JaCoCo has been updated to https://www.jacoco.org/jacoco/trunk/doc/changes.html[0.8.11].

==== `DependencyAdder` renamed to `DependencyCollector`

The incubating `DependencyAdder` interface has been renamed to link:{javadocPath}/org/gradle/api/artifacts/dsl/DependencyCollector.html[`DependencyCollector`].
A `getDependencies` method has been added to the interface that returns all declared dependencies.

=== Deprecations

[[deprecate_register_feature_main_source_set]]
==== Deprecated calling `registerFeature` using the `main` source set

Calling `link:{javadocPath}/org/gradle/api/plugins/JavaPluginExtension.html#registerFeature-java.lang.String-org.gradle.api.Action-[registerFeature]` on the `link:{javadocPath}/org/gradle/api/plugins/JavaPluginExtension.html[java]` extension using the `main` source set is deprecated and will change behavior in Gradle 9.0.

Currently, features created while calling `link:{javadocPath}/org/gradle/api/plugins/FeatureSpec.html#usingSourceSet-org.gradle.api.tasks.SourceSet-[usingSourceSet]` with the `main` source set are initialized differently than features created while calling `usingSourceSet` with any other source set.
Previously, when using the `main` source set, new `implementation`, `compileOnly`, `runtimeOnly`, `api`, and `compileOnlyApi` configurations were created, and the compile and runtime classpaths of the `main` source set were configured to extend these configurations.

Starting in Gradle 9.0, the `main` source set will be treated like any other source set.
With the `java-library` plugin applied (or any other plugin that applies the `java` plugin), calling `usingSourceSet` with the `main` source set will throw an exception.
This is because the `java` plugin already configures a main feature.
Only if the `java` plugin is not applied will the `main` source set be permitted when calling `usingSourceSet`.

Code that currently registers features with the main source set, like so:
=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("java-library")
}

java {
    registerFeature("feature") {
        usingSourceSet(sourceSets["main"])
    }
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
plugins {
    id("java-library")
}

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

Should instead create a separate source set for the feature, and register the feature with that source set:
=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("java-library")
}

sourceSets {
    create("feature")
}

java {
    registerFeature("feature") {
        usingSourceSet(sourceSets["feature"])
    }
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
plugins {
    id("java-library")
}

sourceSets {
    feature
}

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

[[publishing_artifact_name_different_from_artifact_id_maven]]
==== Deprecated publishing artifact dependencies with explicit name to Maven repositories

Publishing dependencies with an explicit artifact with a name different from the dependency's `artifactId` to Maven repositories has been deprecated.
This behavior is still permitted when publishing to Ivy repositories.
It will result in an error in Gradle 9.0.

Currently, when publishing to Maven repositories, Gradle will interpret the dependency below as if it were declared with coordinates `org:notfoo:1.0`.

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
dependencies {
    implementation("org:foo:1.0") {
        artifact {
            name = "notfoo"
        }
    }
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
dependencies {
    implementation("org:foo:1.0") {
        artifact {
            name = "notfoo"
        }
    }
}
----
======
=====

Instead, this dependency should be declared as:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
dependencies {
    implementation("org:notfoo:1.0")
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
dependencies {
    implementation("org:notfoo:1.0")
}
----
======
=====

[[deprecated_artifact_identifier]]
==== Deprecated `ArtifactIdentifier`
The `ArtifactIdentifier` class has been deprecated for removal in Gradle 9.0.

[[dependency_mutate_dependency_collector_after_finalize]]
==== Deprecate mutating `DependencyCollector` dependencies after observation

Starting in Gradle 9.0, mutating dependencies sourced from a link:{javadocPath}/org/gradle/api/artifacts/dsl/DependencyCollector.html[DependencyCollector] after those dependencies have been observed will result in an error.
The `DependencyCollector` interface is used to declare dependencies within the test suites DSL.

Consider the following example where a test suite's dependency is mutated after it is observed:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
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")
            }
        }
    }
}
----
======
=====

In the above example, the build logic uses iteration and mutation to try to set a default version for a particular dependency if the version is not already set.
Build logic like the above example creates challenges in resolving declared dependencies, as reporting tools will display this dependency as if the user declared the version as "2.0", even though they never did.
Instead, the build logic can avoid iteration and mutation by declaring a `preferred` version constraint on the dependency's coordinates.
This allows the dependency management engine to use the version declared on the constraint if no other version is declared.

Consider the following example that replaces the above iteration with an indiscriminate <<rich_versions.adoc#sec:preferred-version,preferred>> version constraint:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
dependencies {
    constraints {
        testImplementation("com:foo") {
            version {
                prefer("2.0")
            }
        }
    }
}
----
======
=====

[[changes_8.5]]
== Upgrading from 8.4 and earlier

=== Potential breaking changes

==== Upgrade to Kotlin 1.9.20

The embedded Kotlin has been updated to link:https://github.com/JetBrains/kotlin/releases/tag/v1.9.20[Kotlin 1.9.20].

==== Changes to Groovy task conventions

The `groovy-base` plugin is now responsible for configuring source and target compatibility version conventions on all `GroovyCompile` tasks.

If you are using this task *without applying `grooy-base`*, you will have to manually set compatibility versions on these tasks.
In general, the `groovy-base` plugin should be applied whenever working with Groovy language tasks.

==== Provider.filter

The type of the argument passed to `Provider.filter` is changed from `Predicate` to `Spec` for a more consistent API.
This change should not affect anyone using `Provider.filter` with a lambda expression.
However, this might affect plugin authors if they don't use SAM conversions to create a lambda.

=== Deprecations

[[org_gradle_util_reports_deprecations_8]]
==== Deprecated members of the `org.gradle.util` package now report their deprecation

These members will be removed in Gradle 9.0:

* `VersionNumber.parse(String)`
* `VersionNumber.compareTo(VersionNumber)`

[[depending_on_root_configuration]]
==== Deprecated depending on resolved configuration

When resolving a `Configuration`, it is sometimes possible to select that same configuration as a variant.
Configurations should be used for one purpose (resolution, consumption or dependency declarations), so this can only occur when a configuration is marked as both consumable and resolvable.

This can lead to confusing circular dependency graphs, as the configuration being resolved is used for two different purposes.

To avoid this problem, plugins should mark all resolvable configurations as `canBeConsumed=false` or use the `resolvable(String)` configuration factory method when creating configurations meant for resolution.

In Gradle 9.0, consuming configurations in this manner will no longer be allowed and will result in an error.

[[deprecated_missing_project_directory]]
==== Including projects without an existing directory

Gradle will warn if a project is added to the build where the associated `projectDir` does not exist or is not writable.
Starting with version 9.0, Gradle will not run builds if a project directory is missing or read-only.
If you intend to dynamically synthesize projects make sure to create directories for them as well:

=====
[.multi-language-sample]
======
.settings.gradle.kts
[source,kotlin]
----
include("project-without-directory")
project(":project-without-directory").projectDir.mkdirs()
----
======
[.multi-language-sample]
======
.settings.gradle
[source,groovy]
----
include 'project-without-directory'
project(":project-without-directory").projectDir.mkdirs()
----
======
=====


[[changes_8.4]]
== Upgrading from 8.3 and earlier

=== Potential breaking changes

==== Upgrade to Kotlin 1.9.10

The embedded Kotlin has been updated to link:https://github.com/JetBrains/kotlin/releases/tag/v1.9.10[Kotlin 1.9.10].

==== XML parsing now requires recent parsers

Gradle 8.4 now configures XML parsers with security features enabled.
If your build logic has dependencies on old XML parsers that don't support secure parsing, your build may now fail.
If you encounter a failure, check and update or remove any dependency on legacy XML parsers.

If you are unable to upgrade XML parsers coming from your build logic dependencies, you can force the use of the XML parsers built into the JVM.
For example, in OpenJDK this can be done by adding the following to `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
```
See the link:https://github.com/gradle/gradle/security/advisories/GHSA-mrff-q8qj-xvg8[CVE-2023-42445] advisory for more details and ways to enable secure XML processing on previous Gradle versions.

==== EAR plugin with customized JEE 1.3 descriptor

Gradle 8.4 forbids external XML entities when parsing XML documents.
If you use the EAR plugin and configure the `application.xml` descriptor via the EAR plugin's DSL and customize the descriptor using `withXml {}` and use `asElement{}` in the customization block, then the build will now fail for security reasons.

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("ear")
}
ear {
    deploymentDescriptor {
        version = "1.3"
        withXml {
            asElement()
        }
    }
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
plugins {
    id("ear")
}
ear {
    deploymentDescriptor {
        version = "1.3"
        withXml {
            asElement()
        }
    }
}
----
======
=====

If you happen to use `asNode()` instead of `asElement()` then nothing changes given `asNode()` simply ignores external DTDs.

You can work around this by running your build with the `javax.xml.accessExternalDTD` system property set to `http`.

On the command line, add this to your Gradle invocation:

[source,properties]
----
-Djavax.xml.accessExternalDTD=http
----

To make this workaround persistent, add the following line to your `gradle.properties`:

[source,properties]
----
systemProp.javax.xml.accessExternalDTD=http
----

Note that this will enable HTTP access to external DTDs for the whole build JVM.
See the link:https://docs.oracle.com/en/java/javase/13/security/java-api-xml-processing-jaxp-security-guide.html#GUID-8CD65EF5-D113-4D5C-A564-B875C8625FAC[JAXP documentation] for more details.

=== Deprecations

[[generate_maven_pom_method_deprecations]]
==== Deprecated `GenerateMavenPom` methods

The following methods on `link:{javadocPath}/org/gradle/api/publish/maven/tasks/GenerateMavenPom.html[GenerateMavenPom]` are deprecated and will be removed in Gradle 9.0.
They were never intended to be public API.

- `getVersionRangeMapper`
- `withCompileScopeAttributes`
- `withRuntimeScopeAttributes`

[[changes_8.3]]
== Upgrading from 8.2 and earlier

=== Potential breaking changes

==== Deprecated `Project.buildDir` can cause script compilation failure

With the deprecation of `Project.buildDir`, buildscripts that are compiled with warnings as errors could fail if the deprecated field is used.

See <<#project_builddir, the deprecation entry>> for details.

==== `TestLauncher` API no longer ignores build failures

The `TestLauncher` interface is part of the Tooling API, specialized for running tests.
It is a logical extension of the `BuildLauncher` that can only launch tasks.
A discrepancy has been reported in their behavior: if the same failing test is executed, `BuildLauncher` will report a build failure but `TestLauncher` won't.
Originally, this was a design decision in order to continue the execution and run the tests in all test tasks and not stop at the first failure.
At the same time, this behavior can be confusing for users as they can experience a failing test in a successful build.
To make the two APIs more uniform, we made `TestLauncher` also fail the build, which is a potential breaking change.
To continue the test execution even if a test task failed, Tooling API clients should explicitly pass `--continue` to the build.

[[legacy_attribute_snapshotting]]
==== Fixed variant selection behavior with `ArtifactView` and `ArtifactCollection`

The dependency resolution APIs for selecting different artifacts or files (`Configuration.getIncoming().artifactView { }` and `Configuration.getIncoming().getArtifacts()`) captured immutable copies of the underlying `Configuration`'s attributes to use for variant selection.
If the `Configuration`'s attributes were changed after these methods were called, the artifacts selected by these methods could be unexpected.

Consider the case where the set of attributes on a `Configuration` is changed after an `ArtifactView` is created.
====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
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
        }
    }
}

----
=====
====

The `inputFiles` property of `myTask` uses an artifact view to select a different type of artifact from the configuration `classpath`.
Since the artifact view was created before the attributes were added to the configuration, Gradle was not able to select the correct artifact.

Some builds may have worked around this by also putting the additional attributes into the artifact view. This is no longer necessary.

[[kotlin_1_9.0]]
==== Upgrade to Kotlin 1.9.0

The embedded Kotlin has been updated from 1.8.20 to link:https://github.com/JetBrains/kotlin/releases/tag/v1.9.0[Kotlin 1.9.0].
The Kotlin language and API levels for the Kotlin DSL are still set to 1.8 for backwards compatibility.
See the release notes for link:https://github.com/JetBrains/kotlin/releases/tag/v1.8.22[Kotlin 1.8.22] and link:https://github.com/JetBrains/kotlin/releases/tag/v1.8.21[Kotlin 1.8.21].

Kotlin 1.9 dropped support for Kotlin language and API level 1.3.
If you build Gradle plugins written in Kotlin with this version of Gradle and need to support Gradle <7.0 you need to stick to using the Kotlin Gradle Plugin <1.9.0 and configure the Kotlin language and API levels to 1.3.
See the <<compatibility.adoc#compatibility, Compatibility Matrix>> for details about other versions.

==== Eager evaluation of `Configuration` attributes

Gradle 8.3 updates the `org.gradle.libraryelements` and `org.gradle.jvm.version` attributes of JVM Configurations to be present at the time of creation, as opposed to previously, where they were only present after the Configuration had been resolved or consumed.
In particular, the value for `org.gradle.jvm.version` relies on the project's configured toolchain, meaning that querying the value for this attribute will finalize the value of the project's Java toolchain.

Plugins or build logic that eagerly queries the attributes of JVM configurations may now cause the project's Java toolchain to be finalized earlier than before.
Attempting to modify the toolchain after it has been finalized will result in error messages similar to the following:
```
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.
```

This situation may arise when plugins or build logic eagerly queries an existing JVM Configuration's attributes to create a new Configuration with the same attributes.
Previously, this logic would have omitted the two above noted attributes entirely, while now the same logic will copy the attributes and finalize the project's Java toolchain.
To avoid early toolchain finalization, attribute-copying logic should be updated to query the source Configuration's attributes lazily:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
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)
        }
    }
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
def source = configurations.runtimeClasspath.attributes
configurations {
    customRuntimeClasspath {
        source.keySet().each { key ->
            attributes.attributeProvider(key, provider { source.getAttribute(key) })
        }
    }
}
----
======
=====


=== Deprecations

[[project_builddir]]
==== Deprecated `Project.buildDir` is to be replaced by `Project.layout.buildDirectory`

The `Project.buildDir` property is deprecated.
It uses eager APIs and has ordering issues if the value is read in build logic and then later modified.
It could result in outputs ending up in different locations.

It is replaced by a `link:{javadocPath}/org/gradle/api/file/DirectoryProperty.html[DirectoryProperty]` found at `Project.layout.buildDirectory`.
See the `link:{groovyDslPath}/org.gradle.api.file.ProjectLayout.html[ProjectLayout]` interface for details.

Note that, at this stage, Gradle will not print deprecation warnings if you still use `Project.buildDir`.
We know this is a big change and want to give time for authors of major plugins to move away from its usage first.

The switch from a `File` to a `DirectoryProperty` requires adaptations in build logic.
The main impact is that you cannot use the property inside a `String` to expand it.
Instead, you should leverage the `dir` and `file` methods to compute the location you want.

Here is an example for creating a file, where the following:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
// Returns a java.io.File
file("$buildDir/myOutput.txt")
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
// Returns a java.io.File
file("$buildDir/myOutput.txt")
----
======
=====

should be replaced by:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
// 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 }
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
// 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 }
----
======
=====

Here is another example for creating a directory, where the following:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
// Returns a java.io.File
file("$buildDir/outputLocation")
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
// Returns a java.io.File
file("$buildDir/outputLocation")
----
======
=====

should be replaced by:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
// 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 }
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
// 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 }
----
======
=====

[[declaring_client_module_dependencies]]
==== Deprecated `ClientModule` dependencies

`link:{javadocPath}/org/gradle/api/artifacts/ClientModule.html[ClientModule]` dependencies are deprecated and will be removed in Gradle 9.0.

Client module dependencies were originally intended to allow builds to override incorrect or missing component metadata of external dependencies by defining the metadata locally.
This functionality has since been replaced by <<component_metadata_rules.adoc#sec:component_metadata_rules,Component Metadata Rules>>.

Consider the following client module dependency example:

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
dependencies {
    implementation(module("org:foo:1.0") {
        dependency("org:bar:1.0")
        module("org:baz:1.0") {
            dependency("com:example:1.0")
        }
    })
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
dependencies {
    implementation module("org:foo:1.0") {
        dependency "org:bar:1.0"
        module("org:baz:1.0") {
            dependency "com:example:1.0"
        }
    }
}
----
======
=====

This can be replaced with the following component metadata rule:

=====
[.multi-language-sample]
======
.build-logic/src/main/kotlin/my-plugin.gradle.kts
[source,kotlin]
----
@CacheableRule
abstract class AddDependenciesRule @Inject constructor(val dependencies: List<String>) : ComponentMetadataRule {
    override fun execute(context: ComponentMetadataContext) {
        listOf("compile", "runtime").forEach { base ->
            context.details.withVariant(base) {
                withDependencies {
                    dependencies.forEach {
                        add(it)
                    }
                }
            }
        }
    }
}
----
.build.gradle.kts
[source,kotlin]
----
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")
}
----
======
[.multi-language-sample]
======
.build-logic/src/main/groovy/my-plugin.gradle
[source,groovy]
----
@CacheableRule
abstract class AddDependenciesRule implements ComponentMetadataRule {

    List<String> dependencies

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

    @Override
    void execute(ComponentMetadataContext context) {
        ["compile", "runtime"].each { base ->
            context.details.withVariant(base) {
                withDependencies {
                    dependencies.each {
                        add(it)
                    }
                }
            }
        }
    }
}
----
.build.gradle
[source,groovy]
----
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"
}
----
======
=====

[[unsupported_ge_plugin_3.13]]
==== Earliest supported Develocity plugin version is 3.13.1

Starting in Gradle 9.0, the earliest supported Develocity plugin version is 3.13.1.
The plugin versions from 3.0 up to 3.13 will be ignored when applied.

Upgrade to version 3.13.1 or later of the Develocity plugin.
You can find the link:https://plugins.gradle.org/plugin/com.gradle.enterprise[latest available version on the Gradle Plugin Portal].
More information on the compatibility can be found link:https://docs.gradle.com/enterprise/compatibility/#build_scans[here].

[[changes_8.2]]
== Upgrading from 8.1 and earlier

=== Potential breaking changes

[[kotlin_1_8.20]]
==== Upgrade to Kotlin 1.8.20

The embedded Kotlin has been updated to link:https://github.com/JetBrains/kotlin/releases/tag/v1.8.20[Kotlin 1.8.20].
For more information, see https://kotlinlang.org/docs/whatsnew1820.html[What's new in Kotlin 1.8.20].

Note that there is a known issue with Kotlin compilation avoidance that can cause `OutOfMemory` exceptions in `compileKotlin` tasks if the compilation classpath contains very large JAR files.
This applies to builds applying the Kotlin plugin v1.8.20 or the `kotlin-dsl` plugin.

You can work around it by disabling Kotlin compilation avoidance in your `gradle.properties` file:

[source,properties]
----
kotlin.incremental.useClasspathSnapshot=false
----

See link:https://youtrack.jetbrains.com/issue/KT-57757/[KT-57757] for more information.

==== Upgrade to Groovy 3.0.17

Groovy has been updated to https://groovy-lang.org/changelogs/changelog-3.0.17.html[Groovy 3.0.17].

Since the previous version was 3.0.15, the https://groovy-lang.org/changelogs/changelog-3.0.16.html[3.0.16] changes are also included.

==== Upgrade to Ant 1.10.13

Ant has been updated to https://github.com/apache/ant/blob/rel/1.10.13/WHATSNEW[Ant 1.10.13].

Since the previous version was 1.10.11, the https://github.com/apache/ant/blob/rel/1.10.12/WHATSNEW[1.10.12] changes are also included.

==== Upgrade to CodeNarc 3.2.0

The default version of CodeNarc has been updated to https://github.com/CodeNarc/CodeNarc/blob/v3.2.0/CHANGELOG.md#version-320----jan-2023[CodeNarc 3.2.0].

==== Upgrade to PMD 6.55.0

PMD has been updated to https://docs.pmd-code.org/pmd-doc-6.55.0/pmd_release_notes.html[PMD 6.55.0].

Since the previous version was 6.48.0, all changes since then are included.

==== Upgrade to JaCoCo 0.8.9

JaCoCo has been updated to https://www.jacoco.org/jacoco/trunk/doc/changes.html[0.8.9].

==== Plugin compatibility changes

A plugin compiled with Gradle >= 8.2 that makes use of the Kotlin DSL functions link:{kotlinDslPath}/gradle/org.gradle.kotlin.dsl/the.html[`Project.the<T>()`], link:{kotlinDslPath}/gradle/org.gradle.kotlin.dsl/the.html[`Project.the(KClass)`] or link:{kotlinDslPath}/gradle/org.gradle.kotlin.dsl/configure.html[`Project.configure<T> {}`] cannot run on Gradle <= 6.1.

==== Deferred or avoided configuration of some tasks

When performing dependency resolution, Gradle creates an internal representation of the available link:{javadocPath}/org/gradle/api/artifacts/Configuration.html[Configuration]s.
This requires inspecting all configurations and artifacts.
Processing artifacts created by tasks causes those tasks to be realized and configured.

This internal representation is now created more lazily, which can change the order in which tasks are configured.
Some tasks may never be configured.

This change may cause code paths that relied on a particular order to no longer function, such as conditionally adding attributes to a configuration based on the presence of certain attributes.

This impacted the link:https://github.com/bndtools/bnd/issues/5695[bnd plugin and JUnit5 build].

We recommend not modifying domain objects (configurations, source sets, tasks, etc) from configuration blocks for other domain objects that may not be configured.

For example, avoid doing something like this:

```kotlin
    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))
          }
    }
```

=== Deprecations

[[compile_options_generated_sources_directory]]
==== `link:{javadocPath}/org/gradle/api/tasks/compile/CompileOptions.html[CompileOptions]` method deprecations

The following methods on `CompileOptions` are deprecated:

- `getAnnotationProcessorGeneratedSourcesDirectory()`
- `setAnnotationProcessorGeneratedSourcesDirectory(File)`
- `setAnnotationProcessorGeneratedSourcesDirectory(Provider<File>)`

Current usages of these methods should migrate to `link:{javadocPath}/org/gradle/api/tasks/compile/CompileOptions.html#getGeneratedSourceOutputDirectory--[DirectoryProperty getGeneratedSourceOutputDirectory()]`

[[deprecated_configuration_usage]]
==== Using configurations incorrectly

Gradle will now warn at runtime when methods of link:{javadocPath}/org/gradle/api/artifacts/Configuration.html--[Configuration] are called inconsistently with the configuration's intended usage.

This change is part of a larger ongoing effort to make the intended behavior of configurations more consistent and predictable, and to unlock further speed and memory improvements.

Currently, the following methods should only be called with these listed allowed usages:

- `resolve()` - RESOLVABLE configurations only
- `files(Closure)`, `files(Spec)`, `files(Dependency…)`, `fileCollection(Spec)`, `fileCollection(Closure)`, `fileCollection(Dependency…)` - RESOLVABLE configurations only
- `getResolvedConfigurations()` - RESOLVABLE configurations only
- `defaultDependencies(Action)` - DECLARABLE configurations only
- `shouldResolveConsistentlyWith(Configuration)` - RESOLVABLE configurations only
- `disableConsistentResolution()` - RESOLVABLE configurations only
- `getDependencyConstraints()` - DECLARABLE configurations only
- `copy()`, `copy(Spec)`, `copy(Closure)`, `copyRecursive()`, `copyRecursive(Spec)`, `copyRecursive(Closure)` - RESOLVABLE configurations only

Intended usage is noted in the `Configuration` interface's Javadoc.
This list is likely to grow in future releases.

Starting in Gradle 9.0, using a configuration inconsistently with its intended usage will be prohibited.

Also note that although it is not currently restricted, the `getDependencies()` method is really only intended for use with DECLARABLE configurations.
The `getAllDependencies()` method, which retrieves all declared dependencies on a configuration and any superconfigurations, will not be restricted to any particular usage.

[[deprecated_access_to_conventions]]
==== Deprecated access to plugin conventions

The concept of conventions is outdated and superseded by <<implementing_gradle_plugins_binary.adoc#modeling_dsl_like_apis, extensions>> to provide custom DSLs.

To reflect this in the Gradle API, the following elements are deprecated:

- link:{javadocPath}/org/gradle/api/Project.html#getConvention--[org.gradle.api.Project.getConvention()]
- link:{javadocPath}/org/gradle/api/plugins/Convention.html[org.gradle.api.plugins.Convention]
- `org.gradle.api.internal.HasConvention`

Gradle Core plugins still register their conventions in addition to their extensions for backwards compatibility.

It is deprecated to access any of these conventions and their properties.
Doing so will now emit a deprecation warning.
This will become an error in Gradle 9.0.
You should prefer accessing the extensions and their properties instead.

For specific examples see the next sections.

Prominent community plugins already migrated to using extensions to provide custom DSLs.
Some of them still registers conventions for backwards compatibility.
Registering conventions does not emit a deprecation warning yet to provide a migration window.
Future Gradle versions will do.

Also note that Plugins compiled with Gradle <= 8.1 that make use of the Kotlin DSL functions link:{kotlinDslPath}/gradle/org.gradle.kotlin.dsl/the.html[`Project.the<T>()`], link:{kotlinDslPath}/gradle/org.gradle.kotlin.dsl/the.html[`Project.the(KClass)`] or link:{kotlinDslPath}/gradle/org.gradle.kotlin.dsl/configure.html[`Project.configure<T> {}`] will emit a deprecation warning when run on Gradle >= 8.2.
To fix this these plugins should be recompiled with Gradle >= 8.2 or changed to access extensions directly using `extensions.getByType<T>()` instead.

[[base_convention_deprecation]]
==== Deprecated `base` plugin conventions

The convention properties contributed by the `base` plugin have been deprecated and scheduled for removal in Gradle 9.0.
For the wider context see the <<deprecated_access_to_conventions, section about plugin convention deprecation>>.

The conventions are replaced by the `base { }` configuration block backed by link:{groovyDslPath}/org.gradle.api.plugins.BasePluginExtension.html[BasePluginExtension].
The old convention object defines the `distsDirName`, `libsDirName` and `archivesBaseName` properties with simple getter and setter methods.
Those methods are available in the extension only to maintain backwards compatibility.
Build scripts should solely use the properties of type `Property`:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    base
}

base {
    archivesName.set("gradle")
    distsDirectory.set(layout.buildDirectory.dir("custom-dist"))
    libsDirectory.set(layout.buildDirectory.dir("custom-libs"))
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'base'
}

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

[[application_convention_deprecation]]
==== Deprecated `application` plugin conventions

The convention properties contributed by the `application` plugin have been deprecated and scheduled for removal in Gradle 9.0.
For the wider context see the <<deprecated_access_to_conventions, section about plugin convention deprecation>>.

The following code will now emit deprecation warnings:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    application
}

applicationDefaultJvmArgs = listOf("-Dgreeting.language=en") // Accessing a convention
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'application'
}

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

This should be changed to use the `application { }` configuration block, backed by link:{groovyDslPath}/org.gradle.api.plugins.JavaApplication.html[JavaApplication], instead:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    application
}

application {
    applicationDefaultJvmArgs = listOf("-Dgreeting.language=en")
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'application'
}

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

[[java_convention_deprecation]]
==== Deprecated `java` plugin conventions

The convention properties contributed by the `java` plugin have been deprecated and scheduled for removal in Gradle 9.0.
For the wider context see the <<deprecated_access_to_conventions, section about plugin convention deprecation>>.

The following code will now emit deprecation warnings:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("java")
}

configure<JavaPluginConvention> { // Accessing a convention
    sourceCompatibility = JavaVersion.VERSION_18
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'java'
}

sourceCompatibility = 18 // Accessing a convention
----
=====
====

This should be changed to use the `java { }` configuration block, backed by link:{groovyDslPath}/org.gradle.api.plugins.JavaPluginExtension.html[JavaPluginExtension], instead:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("java")
}

java {
    sourceCompatibility = JavaVersion.VERSION_18
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'java'
}

java {
    sourceCompatibility = JavaVersion.VERSION_18
}
----
=====
====

[[war_convention_deprecation]]
==== Deprecated `war` plugin conventions

The convention properties contributed by the `war` plugin have been deprecated and scheduled for removal in Gradle 9.0.
For the wider context see the <<deprecated_access_to_conventions, section about plugin convention deprecation>>.

The following code will now emit deprecation warnings:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("war")
}

configure<WarPluginConvention> { // Accessing a convention
    webAppDirName = "src/main/webapp"
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'war'
}

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

Clients should configure the `war` task  directly.
Also, link:{javadocPath}/org/gradle/api/DomainObjectCollection.html#withType-java.lang.Class-[tasks.withType(War.class).configureEach(...)] can be used to configure each task of type `War`.

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("war")
}

tasks.war {
    webAppDirectory.set(file("src/main/webapp"))
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'war'
}

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

[[ear_convention_deprecation]]
==== Deprecated `ear` plugin conventions

The convention properties contributed by the `ear` plugin have been deprecated and scheduled for removal in Gradle 9.0.
For the wider context see the <<deprecated_access_to_conventions, section about plugin convention deprecation>>.

The following code will now emit deprecation warnings:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("ear")
}

configure<EarPluginConvention> { // Accessing a convention
    appDirName = "src/main/app"
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'ear'
}

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

Clients should configure the `ear` task directly.
Also, link:{javadocPath}/org/gradle/api/DomainObjectCollection.html#withType-java.lang.Class-[tasks.withType(Ear.class).configureEach(...)] can be used to configure each task of type `Ear`.

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("ear")
}

tasks.ear {
    appDirectory.set(file("src/main/app"))
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'ear'
}

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

[[project_report_convention_deprecation]]
==== Deprecated `project-report` plugin conventions

The convention properties contributed by the `project-reports` plugin have been deprecated and scheduled for removal in Gradle 9.0.
For the wider context see the <<deprecated_access_to_conventions, section about plugin convention deprecation>>.

The following code will now emit deprecation warnings:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    `project-report`
}

configure<ProjectReportsPluginConvention> {
    projectReportDirName = "custom" // Accessing a convention
}
----
=====

[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'project-report'
}

projectReportDirName = "custom" // Accessing a convention
----
=====
====

Configure your report task instead:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    `project-report`
}

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

[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'project-report'
}

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

[[redundant_configuration_usage_activation]]
==== Redundant configuration usage activation

Calling `setCanBeConsumed(boolean)` or `setCanBeResolved(boolean)` on a configuration that already allows that usage is deprecated.

This deprecation is intended to help users identify unnecessary configuration usage modifications.

[[deprecated_configuration_get_all]]
==== `link:{javadocPath}/org/gradle/api/artifacts/Configuration.html[Configuration]` method deprecations

The following method on `Configuration` is deprecated for removal:

- `getAll()`

Obtain the set of all configurations from the project's `configurations` container instead.

[[test_framework_implementation_dependencies]]
==== Relying on automatic test framework implementation dependencies

In some cases, Gradle will load JVM test framework dependencies from the Gradle distribution in order to
execute tests.
This existing behavior can lead to test framework dependency version conflicts on the test
classpath.
To avoid these conflicts, this behavior is deprecated and will be removed in Gradle 9.0. Tests
using TestNG are unaffected.

In order to prepare for this change in behavior, either declare the required dependencies explicitly,
or migrate to link:jvm_test_suite_plugin.html[Test Suites], where these dependencies are managed automatically.

===== Test Suites

Builds that use test suites will not be affected by this change.
Test suites manage the test
framework dependencies automatically and do not require dependencies to be explicitly declared.
See link:jvm_test_suite_plugin.html[the user manual] for further information on migrating to test suites.

===== Manually declaring dependencies

In the absence of test suites, dependencies must be manually declared on the test runtime classpath:

  * If using JUnit 5, an explicit `runtimeOnly` dependency on `junit-platform-launcher` is required
  in addition to the existing `implementation` dependency on the test engine.
  * If using JUnit 4, only the existing `implementation` dependency on `junit` 4 is required.
  * If using JUnit 3, a test `runtimeOnly` dependency on `junit` 4 is required in addition to a
  `compileOnly` dependency on `junit` 3.

=====
[.multi-language-sample]
======
.build.gradle.kts
[source,kotlin]
----
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")
}
----
======
[.multi-language-sample]
======
.build.gradle
[source,groovy]
----
dependencies {
    // If using JUnit Jupiter
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

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

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

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

[[build_identifier_name_and_current_deprecation]]
==== `link:{javadocPath}/org/gradle/api/artifacts/component/BuildIdentifier.html[BuildIdentifier]` and `link:{javadocPath}/org/gradle/api/artifacts/component/ProjectComponentSelector.html[ProjectComponentSelector]` method deprecations

The following methods on `BuildIdentifier` are deprecated:

- `getName()`
- `isCurrentBuild()`

You could use these methods to distinguish between different project components with the same name but from different builds.
However, for certain composite build setups, these methods do not provide enough information to guarantee uniqueness.

Current usages of these methods should migrate to `link:{javadocPath}/org/gradle/api/artifacts/component/BuildIdentifier.html#getBuildPath--[BuildIdentifier.getBuildPath()]`.

Similarly, the method `ProjectComponentSelector.getBuildName()` is deprecated.
Use `link:{javadocPath}/org/gradle/api/artifacts/component/ProjectComponentSelector.html#getBuildPath--[ProjectComponentSelector.getBuildPath()]` instead.

[[changes_8.1]]
== Upgrading from 8.0 and earlier

[[cache_marking]]
=== CACHEDIR.TAG files are created in global cache directories
Gradle now emits a `CACHEDIR.TAG` file in some global cache directories, as specified in <<directory_layout#dir:gradle_user_home:cache_marking>>.

This may cause these directories to no longer be searched or backed up by some tools. To disable it, use the following code in an <<init_scripts#sec:using_an_init_script,init script>> in the Gradle User Home:

====
[.multi-language-sample]
=====
.init.gradle.kts
[source,kotlin]
----
beforeSettings {
    caches {
        // Disable cache marking for all caches
        markingStrategy.set(MarkingStrategy.NONE)
    }
}
----
=====
[.multi-language-sample]
=====
.init.gradle
[source,groovy]
----
beforeSettings { settings ->
    settings.caches {
        // Disable cache marking for all caches
        markingStrategy = MarkingStrategy.NONE
    }
}
----
=====
====

[[configuration_caching_options_renamed]]
=== Configuration cache options renamed

In this release, the configuration cache feature was promoted from incubating to stable, and as such, all properties
originally mentioned in the feature documentation (which had an `unsafe` part in their names, e.g. `org.gradle.unsafe.configuration-cache`) were renamed, in some cases, by just removing the `unsafe` bit.

[cols="1,1", options="header"]
|===

| Incubating property
| Finalized property

|`org.gradle.unsafe.configuration-cache`
|`org.gradle.configuration-cache`

|`org.gradle.unsafe.configuration-cache-problems`
|`org.gradle.configuration-cache.problems`*

|`org.gradle.unsafe.configuration-cache.max-problems`
|`org.gradle.configuration-cache.max-problems`
|===

Note that the original `org.gradle.unsafe.configuration-cache...` properties continue to be honored in this release,
and no warnings will be produced if they are used, but they will be deprecated and removed in a future release.

=== Potential breaking changes

==== Kotlin DSL scripts emit compilation warnings

Compilation warnings from Kotlin DSL scripts are printed to the console output.
For example, the use of deprecated APIs in Kotlin DSL will emit warnings each time the script is compiled.

This is a potentially breaking change if you are consuming the console output of Gradle builds.

==== Configuring Kotlin compiler options with the `kotlin-dsl` plugin applied

If you are configuring custom Kotlin compiler options on a project with the <<kotlin_dsl.adoc#sec:kotlin-dsl_plugin, kotlin-dsl>> plugin applied you might encounter a breaking change.

In previous Gradle versions, the `kotlin-dsl` plugin was adding required compiler arguments on link:{javadocPath}/org/gradle/api/Project.html#afterEvaluate-org.gradle.api.Action-[afterEvaluate {}].
Now that the Kotlin Gradle Plugin provides <<lazy_configuration.adoc#lazy_configuration, lazy configuration>> properties, our `kotlin-dsl` plugin switched to adding required compiler arguments to the lazy properties directly.
As a consequence, if you were setting `freeCompilerArgs` the `kotlin-dsl` plugin is now failing the build because its required compiler arguments are overridden by your configuration.

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    `kotlin-dsl`
}

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

With the configuration above you would get the following build failure:

[source,text]
----
* 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.
----

You must change this to adding your custom compiler arguments to the lazy configuration properties of the Kotlin Gradle Plugin in order for them to be appended to the ones required by the `kotlin-dsl` plugin:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    `kotlin-dsl`
}

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

If you were already adding to `freeCompilerArgs` instead of setting its value, then you should not experience a build failure.

==== New API introduced may clash with existing Gradle DSL code

When a new property or method is added to an existing type in the Gradle DSL, it may clash with names already in use in user code.

When a name clash occurs, one solution is to rename the element in user code.

This is a non-exhaustive list of API additions in 8.1 that may cause name collisions with existing user code.

* link:{javadocPath}/org/gradle/api/tasks/JavaExec.html#getJvmArguments--[`JavaExec.getJvmArguments()`]
* link:{javadocPath}/org/gradle/process/JavaExecSpec.html#getJvmArguments--[`JavaExecSpec.getJvmArguments()`]

==== Using unsupported API to start external processes at configuration time is no longer allowed with the configuration cache enabled

Since Gradle 7.5, using `Project.exec`, `Project.javaexec`, and standard Java and Groovy APIs to run external processes at configuration time has been considered an error only if the <<configuration_cache.adoc#config_cache:stable,feature preview `STABLE_CONFIGURATION_CACHE`>> was enabled.
With the configuration cache promotion to a stable feature in Gradle 8.1, this error is detected regardless of the feature preview status.
The <<configuration_cache#config_cache:requirements:external_processes,configuration cache chapter>> has more details to help with the migration to the new provider-based APIs to execute external processes at configuration time.

Builds that do not use the configuration cache, or only start external processes at execution time are not affected by this change.

=== Deprecations

[[configurations_allowed_usage]]
==== Mutating core plugin configuration usage

The allowed usage of a configuration should be immutable after creation.
Mutating the allowed usage on a configuration created by a Gradle core plugin is deprecated.
This includes calling any of the following `Configuration` methods:

- `setCanBeConsumed(boolean)`
- `setCanBeResolved(boolean)`

These methods now emit deprecation warnings on these configurations, except for certain special cases which make allowances for the existing behavior of popular plugins.
This rule does not yet apply to detached configurations or configurations created
in buildscripts and third-party plugins.
Calling `setCanBeConsumed(false)` on `apiElements` or `runtimeElements`
is not yet deprecated in order to avoid warnings that would be otherwise emitted when
using select popular third-party plugins.

This change is part of a larger ongoing effort to make the intended behavior of configurations more consistent and predictable, and to unlock further speed and memory improvements in this area of Gradle.

The ability to change the allowed usage of a configuration after creation will be removed in Gradle 9.0.

[[reserved_configuration_names]]
==== Reserved configuration names

Configuration names "detachedConfiguration" and "detachedConfigurationX" (where X is any integer) are reserved for internal use when creating detached configurations.

The ability to create non-detached configurations with these names will be removed in Gradle 9.0.

[[java_extension_without_java_component]]
==== Calling select methods on the `JavaPluginExtension` without the `java` component present

Starting in Gradle 8.1, calling any of the following methods on `JavaPluginExtension` without
the presence of the default `java` component is deprecated:

- `withJavadocJar()`
- `withSourcesJar()`
- `consistentResolution(Action)`

This `java` component is added by the `JavaPlugin`, which is applied by any of the Gradle JVM plugins including:

- `java-library`
- `application`
- `groovy`
- `scala`

Starting in Gradle 9.0, calling any of the above listed methods without the presence of the default `java` component
will become an error.

[[war_plugin_configure_configurations]]
==== `WarPlugin#configureConfiguration(ConfigurationContainer)`

Starting in Gradle 8.1, calling `WarPlugin#configureConfiguration(ConfigurationContainer)` is deprecated. This method was
intended for internal use and was never intended to be used as part of the public interface.

Starting in Gradle 9.0, this method will be removed without replacement.

[[test_task_default_classpath]]
==== Relying on conventions for custom Test tasks

By default, when applying the link:java_plugin.html[`java`] plugin, the `testClassesDirs`and `classpath` of all `Test` tasks have the same convention.
Unless otherwise changed, the default behavior is to execute the tests from the default `test` link:jvm_test_suite_plugin.html[`TestSuite`] by configuring the task with the `classpath` and `testClassesDirs` from the `test` suite.
This behavior will be removed in Gradle 9.0.

While this existing default behavior is correct for the use case of executing the default unit test suite under a different environment, it does not support the use case of executing an entirely separate set of tests.

If you wish to continue including these tests, use the following code to avoid the deprecation warning in 8.1 and prepare for the behavior change in 9.0.
Alternatively, consider migrating to test suites.

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
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 })
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
tasks.myTestTask {
    testClassesDirs = testing.suites.test.sources.output.classesDirs
    classpath = testing.suites.test.sources.runtimeClasspath
}
----
=====
====


[[gmm_modification_after_publication_populated]]
==== Modifying Gradle Module Metadata after a publication has been populated

Altering the link:publishing_gradle_module_metadata.html[GMM] (e.g., changing a component configuration variants) *after* a Maven or Ivy publication has been populated from their components is now deprecated.
This feature will be removed in Gradle 9.0.

Eager population of the publication can happen if the following methods are called:

* Maven
** link:{javadocPath}/org/gradle/api/publish/maven/MavenPublication.html#getArtifacts--[MavenPublication.getArtifacts()]
* Ivy
** link:{javadocPath}/org/gradle/api/publish/ivy/IvyPublication.html#getArtifacts--[IvyPublication.getArtifacts()]
** link:{javadocPath}/org/gradle/api/publish/ivy/IvyPublication.html#getConfigurations--[IvyPublication.getConfigurations()]
** link:{javadocPath}/org/gradle/api/publish/ivy/IvyPublication.html#configurations(Action)--[IvyPublication.configurations(Action)]

Previously, the following code did not generate warnings, but it created inconsistencies between published artifacts:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
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() }
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
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() }
----
=====
====

In this example, the Maven and Ivy publications will contain the main JAR artifacts for the project, whereas the GMM link:https://github.com/gradle/gradle/blob/master/platforms/documentation/docs/src/docs/design/gradle-module-metadata-latest-specification.md[module file] will omit them.

[[minimum_test_jvm_version]]
==== Running tests on JVM versions 6 and 7

Running JVM tests on JVM versions older than 8 is deprecated.
Testing on these versions will become an error in Gradle 9.0

[[kotlin_dsl_precompiled_gradle_lt_6]]
==== Applying Kotlin DSL precompiled scripts published with Gradle < 6.0

Applying Kotlin DSL precompiled scripts published with Gradle < 6.0 is deprecated.
Please use a version of the plugin published with Gradle >= 6.0.

[[kotlin_dsl_with_kgp_lt_1_8_0]]
==== Applying the `kotlin-dsl` together with Kotlin Gradle Plugin < 1.8.0

Applying the `kotlin-dsl` together with Kotlin Gradle Plugin < 1.8.0 is deprecated.
Please let Gradle control the version of `kotlin-dsl` by removing any explicit `kotlin-dsl` version constraints from your build logic.
This will let the `kotlin-dsl` plugin decide which version of the Kotlin Gradle Plugin to use.
If you explicitly declare which version of the Kotlin Gradle Plugin to use for your build logic, update it to >= 1.8.0.

[[kotlin_dsl_deprecated_catalogs_plugins_block]]
==== Accessing `libraries` or `bundles` from dependency version catalogs in the `plugins {}` block of a Kotlin script

Accessing `libraries` or `bundles` from dependency version catalogs in the `plugins {}` block of a Kotlin script is deprecated.
Please only use `versions` or `plugins` from dependency version catalogs in the `plugins {}` block.

[[validate_plugins_without_java_toolchain]]
==== Using `ValidatePlugins` task without a Java Toolchain

Using a task of type link:{javadocPath}/org/gradle/plugin/devel/tasks/ValidatePlugins.html[ValidatePlugins] without applying the link:toolchains.html[Java Toolchains] plugin is deprecated, and will become an error in Gradle 9.0.

To avoid this warning, please apply the plugin to your project:

====
[.multi-language-sample]
=====
.build.gradle.kts
[source,kotlin]
----
plugins {
    id("jvm-toolchains")
}
----
=====
[.multi-language-sample]
=====
.build.gradle
[source,groovy]
----
plugins {
    id 'jvm-toolchains'
}
----
=====
====

The Java Toolchains plugin is applied automatically by the <<java_library_plugin#java_library_plugin,Java library plugin>> or other JVM plugins.
So you can apply any of them to your project and it will fix the warning.

[[org_gradle_util_reports_deprecations_80]]
==== Deprecated members of the `org.gradle.util` package now report their deprecation

These members will be removed in Gradle 9.0.

* `WrapUtil.toDomainObjectSet(...)`
* `GUtil.toCamelCase(...)`
* `GUtil.toLowerCase(...)`
* `ConfigureUtil`

[[ibm_semeru_should_not_be_used]]
==== Deprecated JVM vendor IBM Semeru

The enum constant `JvmVendorSpec.IBM_SEMERU` is now deprecated and will be removed in Gradle 9.0.

Please replace it by its equivalent `JvmVendorSpec.IBM` to avoid warnings and potential errors in the next major version release.

[[configuring_custom_build_layout]]
==== Setting custom build layout on `StartParameter` and `GradleBuild`

Following the <<upgrading_version_7.adoc#configuring_custom_build_layout_7,related previous deprecation>> of the behaviour in Gradle 7.1, it is now also deprecated to use related link:{javadocPath}/org/gradle/StartParameter.html[StartParameter] and link:{javadocPath}/org/gradle/api/tasks/GradleBuild.html[GradleBuild] properties.
These properties will be removed in Gradle 9.0.

Setting custom build file using link:{groovyDslPath}/org.gradle.api.tasks.GradleBuild.html#org.gradle.api.tasks.GradleBuild:buildFile[buildFile] property in link:{groovyDslPath}/org.gradle.api.tasks.GradleBuild.html[GradleBuild] task has been deprecated.

Please use the link:{groovyDslPath}/org.gradle.api.tasks.GradleBuild.html#org.gradle.api.tasks.GradleBuild:dir[dir] property instead to specify the root of the nested build.
Alternatively, consider using one of the recommended alternatives for link:{groovyDslPath}/org.gradle.api.tasks.GradleBuild.html[GradleBuild] task as suggested in <<authoring_maintainable_build_scripts#sec:avoiding_use_of_gradlebuild, Avoid using the GradleBuild task type>> section.

Setting custom build layout using link:{javadocPath}/org/gradle/StartParameter.html[StartParameter] methods link:{javadocPath}/org/gradle/StartParameter.html#setBuildFile-java.io.File-[setBuildFile(File)] and link:{javadocPath}/org/gradle/StartParameter.html#setSettingsFile-java.io.File-[setSettingsFile(File)] as well as the counterpart getters link:{javadocPath}/org/gradle/StartParameter.html#getBuildFile--[getBuildFile()] and link:{javadocPath}/org/gradle/StartParameter.html#getSettingsFile--[getSettingsFile()] have been deprecated.

Please use standard locations for settings and build files:

* settings file in the root of the build
* build file in the root of each subproject

[[disabling_user_home_cache_cleanup]]
==== Deprecated org.gradle.cache.cleanup property

The `org.gradle.cache.cleanup` property in `gradle.properties` under Gradle User Home has been deprecated.
Please use the <<directory_layout#dir:gradle_user_home:configure_cache_cleanup,cache cleanup DSL>> instead to disable or modify the cleanup configuration.

Since the `org.gradle.cache.cleanup` property may still be needed for older versions of Gradle, this property may still be present and no deprecation warnings will be printed as long as it is also configured via the DSL.
The DSL value will always take preference over the `org.gradle.cache.cleanup` property.
If the desired configuration is to disable cleanup for older versions of Gradle (using `org.gradle.cache.cleanup`), but to enable cleanup with the default values for Gradle versions at or above Gradle 8, then cleanup should be configured to use link:{javadocPath}/org/gradle/api/cache/Cleanup.html#DEFAULT[Cleanup.DEFAULT]:

====
[.multi-language-sample]
=====
.cache-settings.gradle
[source,groovy]
----
if (GradleVersion.current() >= GradleVersion.version('8.0')) {
    apply from: "gradle8/cache-settings.gradle"
}
----
=====
[.multi-language-sample]
=====
.cache-settings.gradle.kts
[source,kotlin]
----
if (GradleVersion.current() >= GradleVersion.version("8.0")) {
    apply(from = "gradle8/cache-settings.gradle")
}
----
=====
====
====
[.multi-language-sample]
=====
.gradle8/cache-settings.gradle
[source,groovy]
----
beforeSettings { settings ->
    settings.caches {
        cleanup = Cleanup.DEFAULT
    }
}
----
=====
=====
.gradle8/cache-settings.gradle.kts
[source,kotlin]
----
beforeSettings {
    caches {
        cleanup.set(Cleanup.DEFAULT)
    }
}
----
=====
====

[no_relative_paths_for_java_executables]
==== Deprecated using relative paths to specify Java executables
Using relative file paths to point to Java executables is now deprecated and will become an error in Gradle 9.
This is done to reduce confusion about what such relative paths should resolve against.

[[task_convention]]
==== Calling `Task.getConvention()`, `Task.getExtensions()` from a task action

Calling link:{javadocPath}/org/gradle/api/Task.html#getConvention--[Task.getConvention()], link:{javadocPath}/org/gradle/api/Task.html#getExtensions--[Task.getExtensions()] from a task action at execution time is now deprecated and will be made an error in Gradle 9.0.

See the <<configuration_cache#config_cache:requirements:disallowed_types,configuration cache chapter>> for details on how to migrate these usages to APIs that are supported by the configuration cache.

[[test_task_fail_on_no_test_executed]]
==== Deprecated running test task successfully when no test executed
Running the `Test` task successfully when no test was executed is now deprecated and will become an error in Gradle 9.
Note that it is not an error when no test sources are present, in this case the `test` task is simply skipped. It is only an error when test sources are present, but no test was selected for execution.
This is changed to avoid accidental successful test runs due to erroneous configuration.

=== Changes in the IDE integration

[[kotlin_dsl_plugins_catalogs_workaround]]
==== Workaround for false positive errors shown in Kotlin DSL `plugins {}` block using version catalog is not needed anymore

Version catalog accessors for plugin aliases in the `plugins {}` block aren't shown as errors in IntelliJ IDEA and Android Studio Kotlin script editor anymore.

If you were using the `@Suppress("DSL_SCOPE_VIOLATION")` annotation as a workaround, you can now remove it.

If you were using the link:https://plugins.jetbrains.com/plugin/18949-gradle-libs-error-suppressor[Gradle Libs Error Suppressor] IntelliJ IDEA plugin, you can now uninstall it.

After upgrading Gradle to 8.1 you will need to clear the IDE caches and restart.

Also see <<upgrading_version_8.adoc#kotlin_dsl_deprecated_catalogs_plugins_block, the deprecated usages of version catalogs in the Kotlin DSL `plugins {}` block>> above.
