<commit_before>// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.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.

:maven-optional-deps: https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html[Maven optional dependencies]
:metadata-file-spec: https://github.com/gradle/gradle/blob/master/subprojects/docs/src/docs/design/gradle-module-metadata-latest-specification.md

[[feature_variants]]
= Feature variants and optional dependencies

Gradle supports the concept of _feature variants_: when building a library, it's often the case that some features should only be available when some dependencies are present, or when special artifacts are used.

Feature variants let consumers choose what _features_ of a library they need: the dependency management engine will select the right artifacts and dependencies.

This allows for a number of different scenarios (list is non exhaustive):

- a (better) substitute to {maven-optional-deps}
- a _main_ library is built with support for different runtime features, and the <<sec::incompatible_variants,user has to choose between one of them>>
- a _main_ library is built with support for different runtime features, each of them requiring a different set of dependencies
- a _main_ library comes with secondary variants like _test fixtures_
- a _main_ library comes with a main artifact, and enabling an additional feature requires additional artifacts

[[sec::feature_variant_selection]]
== Selection of feature variants and capabilities

Declaring a dependency on a component is usually done by providing a set of coordinates (group, artifact, version also known as GAV coordinates).
This allows the engine to determine the _component_ we're looking for, but such a component may provide different _variants_.
A _variant_ is typically chosen based on the usage. For example, we might choose a different variant for compiling against a component (in which case we need the API of the component) or when executing code (in which case we need the runtime of the component).
All variants of a component provide a number of <<controlling_transitive_dependencies#sub:capabilities, capabilities>>, which are denoted similarly using GAV coordinates.

[NOTE]
====
A capability is denoted by GAV coordinates, but you must think of it as feature description:

- "I provide an SLF4J binding"
- "I provide runtime support for MySQL"
- "I provide a Groovy runtime"

And in general, having two components that provide the _same thing_ in the graph is a problem (they conflict).
====

This is an important concept because:

- by default a variant provides a capability corresponding to the GAV coordinates of its component
- it is not allowed to have different components or different variants of a component in a dependency graph if they provide the same capability
- it is allowed to select two variants of the same component, as long as they provide _different capabilities_

A typical component will *only* provide variants with the default capability.
A Java library, for example, exposes two variants (API and runtime) which provide the _same capability_.
As a consequence, it is an error to have both the _API_ and _runtime_ of a single component in a dependency graph.

However, imagine that you need the _runtime_ and the _test fixtures_ of a component.
Then it is allowed as long as the _runtime_ and _test fixtures_ variant of the library declare different capabilities.

If we do so, a consumer would then have to declare two dependencies:

- one on the "main" variant, the library
- one on the "test fixtures" variant, by _requiring its capability_

[NOTE]
====
While the engine supports feature variants independently of the the ecosystem, this feature is currently only available using the Java plugins and is incubating.
====

[[sec::declare_feature_variants]]
== Declaring feature variants

Feature variants can be declared by applying the `java` or `java-library` plugins.
The following code illustrates how to declare a feature named `mongodbSupport`:

.Declaring a feature variant
====
include::sample[dir="java-feature-variant/producer/groovy",files="build.gradle[tags=register_variant]"]
include::sample[dir="java-feature-variant/producer/kotlin",files="build.gradle.kts[tags=register_variant]"]
====

Gradle will automatically setup a number of things for you, in a very similar way to how the <<java_library_plugin#java_library_plugin,Java Library Plugin>> sets up configurations:

- the configuration `mongodbSupportApi`, used to _declare API dependencies_ for this feature
- the configuration `mongodbSupportImplementation`, used to _declare implementation dependencies_ for this feature
- the configuration `mongodbSupportApiElements`, used by consumers to fetch the artifacts and API dependencies of this feature
- the configuration `mongodbSupportRuntimeElements`, used by consumers to fetch the artifacts and runtime dependencies of this feature

Most users will only need to care about the first two configurations, to declare the specific dependencies of this feature:

.Declaring dependencies of a feature
====
include::sample[dir="java-feature-variant/producer/groovy",files="build.gradle[tags=variant_dependencies]"]
include::sample[dir="java-feature-variant/producer/kotlin",files="build.gradle.kts[tags=variant_dependencies]"]
====

[NOTE]
====
By convention, Gradle will map the feature name to a capability which group and version are the same as the group and version of the main component, but with a name composed of the main component name and the kebab-cased feature name.

For example, if the group is `org.gradle.demo`, the name of the component is `provider`, its version is `1.0` and the feature is named `mongodbSupport`, the feature variant will be `org.gradle.demo:provider-mongodb-support:1.0`.

If you choose the capability name yourself or add more capabilities to a variant, it is recommended to follow the same convention.
====

[[sec:feature_variant_source_set]]
=== Feature variant source set

In the previous example, we're declaring a feature variant which uses the _main source set_.
This is a typical use case in the Java ecosystem, where it's, for whatever reason, not possible to split the sources of a project into different subprojects or different source sets.
Gradle will therefore declare the configurations as described, but will also setup the compile classpath and runtime classpath of the _main source set_ so that it extends from the feature configuration.
Said differently, this allows you to declare the dependencies specific to a feature in their own "bucket", but everything is still compiled as a single source set.
There will also be a single artifact (the component Jar) including support for all features.

However, it is often preferred to have a _separate source set_ for a feature. Gradle will then perform a similar mapping, but will _not_ make the compile and runtime classpath of the main component extend from the dependencies of the registered features.
It will also, by convention, create a `Jar` task to bundle the classes built from this feature source set, using a classifier corresponding to the kebab-case name of the feature:

.Declaring a feature variant using a separate source set
====
include::sample[dir="java-feature-variant/producer-separate-sourceset/groovy",files="build.gradle[tags=register_variant]"]
include::sample[dir="java-feature-variant/producer-separate-sourceset/kotlin",files="build.gradle.kts[tags=register_variant]"]
====

[[sec::publishing_feature_variants]]
== Publishing feature variants
<commit_msg>improved confusing documentation and fixed odd grammar<commit_after>// Copyright 2019 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.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.

:maven-optional-deps: https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html[Maven optional dependencies]
:metadata-file-spec: https://github.com/gradle/gradle/blob/master/subprojects/docs/src/docs/design/gradle-module-metadata-latest-specification.md

[[feature_variants]]
= Feature variants and optional dependencies

Gradle supports the concept of _feature variants_: when running a library, it's often the case that some features should only be available when some dependencies are present, or when special artifacts are used.

Feature variants let consumers choose what _features_ of a library they need: the dependency management engine will select the right artifacts and dependencies.

This allows for a number of different scenarios (list is non-exhaustive):

- a (better) substitute for {maven-optional-deps}
- a _main_ library is built with support for different mutually-exclusive implementations of runtime features; the <<sec::incompatible_variants,user must choose one, and only one, implementation of each such feature>>
- a _main_ library is built with support for optional runtime features, each of which requires a different set of dependencies
- a _main_ library comes with secondary variants like _test fixtures_
- a _main_ library comes with a main artifact, and enabling an additional feature requires additional artifacts

[[sec::feature_variant_selection]]
== Selection of feature variants and capabilities

Declaring a dependency on a component is usually done by providing a set of coordinates (group, artifact, version also known as GAV coordinates).
This allows the engine to determine the _component_ we're looking for, but such a component may provide different _variants_.
A _variant_ is typically chosen based on the usage. For example, we might choose a different variant for compiling against a component (in which case we need the API of the component) or when executing code (in which case we need the runtime of the component).
All variants of a component provide a number of <<controlling_transitive_dependencies#sub:capabilities, capabilities>>, which are denoted similarly using GAV coordinates.

[NOTE]
====
A capability is denoted by GAV coordinates, but you must think of it as feature description:

- "I provide an SLF4J binding"
- "I provide runtime support for MySQL"
- "I provide a Groovy runtime"

And in general, having two components that provide the _same thing_ in the graph is a problem (they conflict).
====

This is an important concept because:

- by default a variant provides a capability corresponding to the GAV coordinates of its component
- it is not allowed to have different components or different variants of a component in a dependency graph if they provide the same capability
- it is allowed to select two variants of the same component, as long as they provide _different capabilities_

A typical component will *only* provide variants with the default capability.
A Java library, for example, exposes two variants (API and runtime) which provide the _same capability_.
As a consequence, it is an error to have both the _API_ and _runtime_ of a single component in a dependency graph.

However, imagine that you need the _runtime_ and the _test fixtures_ of a component.
Then it is allowed as long as the _runtime_ and _test fixtures_ variant of the library declare different capabilities.

If we do so, a consumer would then have to declare two dependencies:

- one on the "main" variant, the library
- one on the "test fixtures" variant, by _requiring its capability_

[NOTE]
====
While the engine supports feature variants independently of the the ecosystem, this feature is currently only available using the Java plugins and is incubating.
====

[[sec::declare_feature_variants]]
== Declaring feature variants

Feature variants can be declared by applying the `java` or `java-library` plugins.
The following code illustrates how to declare a feature named `mongodbSupport`:

.Declaring a feature variant
====
include::sample[dir="java-feature-variant/producer/groovy",files="build.gradle[tags=register_variant]"]
include::sample[dir="java-feature-variant/producer/kotlin",files="build.gradle.kts[tags=register_variant]"]
====

Gradle will automatically setup a number of things for you, in a very similar way to how the <<java_library_plugin#java_library_plugin,Java Library Plugin>> sets up configurations:

- the configuration `mongodbSupportApi`, used to _declare API dependencies_ for this feature
- the configuration `mongodbSupportImplementation`, used to _declare implementation dependencies_ for this feature
- the configuration `mongodbSupportApiElements`, used by consumers to fetch the artifacts and API dependencies of this feature
- the configuration `mongodbSupportRuntimeElements`, used by consumers to fetch the artifacts and runtime dependencies of this feature

Most users will only need to care about the first two configurations, to declare the specific dependencies of this feature:

.Declaring dependencies of a feature
====
include::sample[dir="java-feature-variant/producer/groovy",files="build.gradle[tags=variant_dependencies]"]
include::sample[dir="java-feature-variant/producer/kotlin",files="build.gradle.kts[tags=variant_dependencies]"]
====

[NOTE]
====
By convention, Gradle maps the feature name to a capability whose group and version are the same as the group and version of the main component, respectively, but whose name is the main component name followed by a `-` followed by the kebab-cased feature name.

For example, if the group is `org.gradle.demo`, the name of the component is `provider`, its version is `1.0` and the feature is named `mongodbSupport`, the feature variant will be `org.gradle.demo:provider-mongodb-support:1.0`.

If you choose the capability name yourself or add more capabilities to a variant, it is recommended to follow the same convention.
====

[[sec:feature_variant_source_set]]
=== Feature variant source set

In the previous example, we're declaring a feature variant which uses the _main source set_.
This is a typical use case in the Java ecosystem, where it's, for whatever reason, not possible to split the sources of a project into different subprojects or different source sets.
Gradle will therefore declare the configurations as described, but will also setup the compile classpath and runtime classpath of the _main source set_ so that it extends from the feature configuration.
Said differently, this allows you to declare the dependencies specific to a feature in their own "bucket", but everything is still compiled as a single source set.
There will also be a single artifact (the component Jar) including support for all features.

However, it is often preferred to have a _separate source set_ for a feature. Gradle will then perform a similar mapping, but will _not_ make the compile and runtime classpath of the main component extend from the dependencies of the registered features.
It will also, by convention, create a `Jar` task to bundle the classes built from this feature source set, using a classifier corresponding to the kebab-case name of the feature:

.Declaring a feature variant using a separate source set
====
include::sample[dir="java-feature-variant/producer-separate-sourceset/groovy",files="build.gradle[tags=register_variant]"]
include::sample[dir="java-feature-variant/producer-separate-sourceset/kotlin",files="build.gradle.kts[tags=register_variant]"]
====

[[sec::publishing_feature_variants]]
== Publishing feature variants

{'fraction_non_alphanumeric': 0.06252676659528908, 'fraction_numerical': 0.0015907005200367084, 'mean_word_length': 5.243697478991597, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6004090', 'n_tokens_mistral': 3993, 'n_tokens_neox': 3805, 'n_words': 2107}