## 1. Project Overview & Quickstart (GradleUp/shadow)

## File: README.md

# Shadow

A Gradle plugin for creating fat/uber JARs, transforming files, relocating packages, and optimizing applications
with R8/ProGuard. The Gradle counterpart to Maven Shade Plugin.

[](https://central.sonatype.com/artifact/com.gradleup.shadow/shadow-gradle-plugin)
[](https://plugins.gradle.org/plugin/com.gradleup.shadow)
[](https://github.com/GradleUp/shadow/actions/workflows/build.yml?query=branch:main+event:push)
[](LICENSE)

> [!NOTE]\
> Previously this plugin was developed by [@johnrengelman](https://github.com/johnrengelman) and published under the
> ID [`com.github.johnrengelman.shadow`][johnrengelman's]
> before maintenance was transferred to the [GradleUp organization](https://github.com/GradleUp) to ensure future
> development, see [#908](https://github.com/GradleUp/shadow/issues/908).
>
> If you are still using the old plugin ID in your build script, we recommend to switch to the new plugin ID [
`com.gradleup.shadow`][gradleup's]
> and update to the latest version to receive all the latest bug fixes and improvements.

## Documentation

- [User Guide](https://gradleup.com/shadow/)
- [Change Log](docs/changes/README.md)

## Compatibility Matrix

| Shadow Version | Min Gradle Version | Min Java Version | Plugin ID                                            |
|----------------|--------------------|------------------|------------------------------------------------------|
| 8.0.0+         | 8.0                | 8                | [`com.github.johnrengelman.shadow`][johnrengelman's] |
| 8.3.0+         | 8.3                | 8                | [`com.gradleup.shadow`][gradleup's]                  |
| 9.0.0+         | 8.11               | 11               | [`com.gradleup.shadow`][gradleup's]                  |
| 9.2.0+         | 8.11               | 17               | [`com.gradleup.shadow`][gradleup's]                  |
| 9.3.0+         | 9.0                | 17               | [`com.gradleup.shadow`][gradleup's]                  |
| 9.5.0+         | 9.2                | 17               | [`com.gradleup.shadow`][gradleup's]                  |
| 9.7.0+         | 9.4                | 17               | [`com.gradleup.shadow`][gradleup's]                  |



[johnrengelman's]: https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow
[gradleup's]: https://plugins.gradle.org/plugin/com.gradleup.shadow

---

## File: docs/publishing/README.md

# Publishing Shadow JARs

## Publishing with Maven-Publish Plugin

The Shadow plugin will automatically configure the necessary tasks in the presence of Gradle's
[`maven-publish`][maven-publish] plugin.
The plugin provides the `shadow` component to configure the publication with the necessary
artifact and dependencies in the POM file.

=== "Kotlin"

    ```kotlin
    plugins {
      java
      `maven-publish`
      id("com.gradleup.shadow")
    }

    publishing {
      publications {
        create<MavenPublication>("shadow") {
          from(components["shadow"])
        }
      }
      repositories {
        maven("https://repo.myorg.com")
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java'
      id 'maven-publish'
      id 'com.gradleup.shadow'
    }

    publishing {
      publications {
        shadow(MavenPublication) {
          from components.shadow
        }
      }
      repositories {
        maven { url = 'https://repo.myorg.com' }
      }
    }
    ```

## Shadow Variant in Default Java Component

The Shadow plugin adds an optional variant to the `java` component when publishing. This variant contains the shadowed
JAR. This allows consumers of the published library to choose between the standard JAR and the shadowed JAR.

This feature is enabled by default. It can be disabled by setting the `addShadowVariantIntoJavaComponent` property in
the `shadow` extension to `false`. If you want to publish the standard JAR only, disable this feature like:

=== "Kotlin"

    ```kotlin
    plugins {
      java
      `maven-publish`
      id("com.gradleup.shadow")
    }

    shadow {
      addShadowVariantIntoJavaComponent = false
    }

    publishing {
      publications {
        create<MavenPublication>("shadow") {
          from(components["shadow"])
        }
      }
      repositories {
        maven("https://repo.myorg.com")
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java'
      id 'maven-publish'
      id 'com.gradleup.shadow'
    }

    shadow {
      addShadowVariantIntoJavaComponent = false
    }

    publishing {
      publications {
        shadow(MavenPublication) {
          from components.shadow
        }
      }
      repositories {
        maven { url = 'https://repo.myorg.com' }
      }
    }
    ```

The target JVM version attribute (`org.gradle.jvm.version`) of the shadowed variant is added by default, it is useful
for consumers to select the correct variant based on their target JVM version. But it may cause issues in some cases,
you can disable this by setting the `addTargetJvmVersionAttribute` property in the `shadow` extension to `false`:

=== "Kotlin"

    ```kotlin
    shadow {
      addTargetJvmVersionAttribute = false
    }
    ```

=== "Groovy"

    ```groovy
    shadow {
      addTargetJvmVersionAttribute = false
    }
    ```

The BUNDLING attribute (`org.gradle.dependency.bundling`) of the shadowed variant is set to `shadowed` by default,
it is useful for consumers to distinguish between normal and shadowed dependencies. You can override this attribute by
setting the `bundlingAttribute` property in the `shadow` extension:

=== "Kotlin"

    ```kotlin
    shadow {
      // Per description of the attribute, you should set it to either `Bundling.SHADOWED` or `Bundling.EMBEDDED`.
      bundlingAttribute = Bundling.EMBEDDED
    }
    ```

=== "Groovy"

    ```groovy
    shadow {
      // Per description of the attribute, you should set it to either `Bundling.SHADOWED` or `Bundling.EMBEDDED`.
      bundlingAttribute = Bundling.EMBEDDED
    }
    ```

## Shadow Configuration and Publishing

The Shadow plugin provides a custom configuration (`configurations.shadow`) to specify
runtime dependencies that are **not** merged into the final JAR file.
When configuring publishing with the Shadow plugin, the dependencies in the `shadow`
configuration, are translated to become `RUNTIME` scoped dependencies of the
published artifact.

No other dependencies are automatically configured for inclusion in the POM file.
For example, excluded dependencies are **not** automatically added to the POM file or
if the configuration for merging are modified by specifying
`shadowJar.configurations = [configurations.myConfiguration]`, there is no automatic
configuration of the POM file.

This automatic configuration occurs _only_ when using the above methods for
configuring publishing. If this behavior is not desirable, then publishing **must**
be manually configured.


=== "Kotlin"

    ```kotlin
    plugins {
      java
      `maven-publish`
      id("com.gradleup.shadow")
    }

    dependencies {
      // This will be bundled in the shadowed JAR and not declared in the POM.
      implementation("com.squareup.retrofit2:retrofit:<version>")
      // This will be excluded from the shadowed JAR but declared as a runtime dependency in `META-INF/MANIFEST.MF`
      // file's `Class-Path` entry, and also in the POM file.
      shadow("com.squareup.retrofit2:converter-java8:<version>")
      // This will be excluded from the shadowed JAR and not declared in the POM or `META-INF/MANIFEST.MF`.
      compileOnly("com.squareup.retrofit2:converter-scalars:<version>")
    }

    publishing {
      publications {
        create<MavenPublication>("shadow") {
          from(components["shadow"])

          // Optionally, you can add extra dependencies to the POM file like the following:
          pom.withXml {
            val dependenciesNode = asNode().get("dependencies") ?: asNode().appendNode("dependencies")
            val node = (dependenciesNode as groovy.util.Node).appendNode("dependency")
            node.appendNode("groupId", "com.squareup.retrofit2")
            node.appendNode("artifactId", "converter-gson")
            node.appendNode("version", "<version>")
            node.appendNode("scope", "runtime")
          }
        }
      }
      repositories {
        maven("https://repo.myorg.com")
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java'
      id 'maven-publish'
      id 'com.gradleup.shadow'
    }

    dependencies {
      // This will be bundled in the shadowed JAR and not declared in the POM.
      implementation "com.squareup.retrofit2:retrofit:<version>"
      // This will be excluded from the shadowed JAR but declared as a runtime dependency in `META-INF/MANIFEST.MF`
      // file's `Class-Path` entry, and also in the POM file.
      shadow "com.squareup.retrofit2:converter-java8:<version>"
      // This will be excluded from the shadowed JAR and not declared in the POM or `META-INF/MANIFEST.MF`.
      compileOnly "com.squareup.retrofit2:converter-scalars:<version>"
    }

    publishing {
      publications {
        shadow(MavenPublication) {
          from components.shadow

          // Optionally, you can add extra dependencies to the POM file like the following:
          pom.withXml { xml ->
            def dependenciesNode = xml.asNode().get('dependencies') ?: xml.asNode().appendNode('dependencies')
            def node = dependenciesNode.appendNode('dependency')
            node.appendNode('groupId', 'com.squareup.retrofit2')
            node.appendNode('artifactId', 'converter-gson')
            node.appendNode('version', '<version>')
            node.appendNode('scope', 'runtime')
          }
        }
      }
      repositories {
        maven { url = 'https://repo.myorg.com' }
      }
    }
    ```

## Publishing the Shadowed JAR instead of the Original JAR

You may want to publish the shadowed JAR instead of the original JAR. This can be done by trimming
the `archiveClassifier` of the shadowed JAR like the following:

=== "Kotlin"

    ```kotlin
    plugins {
      java
      `maven-publish`
      id("com.gradleup.shadow")
    }

    tasks.shadowJar {
      archiveClassifier = ""
    }

    publishing {
      publications {
        create<MavenPublication>("shadow")
      }
      repositories {
        maven("https://repo.myorg.com")
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java'
      id 'maven-publish'
      id 'com.gradleup.shadow'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      archiveClassifier = ''
    }

    publishing {
      publications {
        shadow(MavenPublication)
      }
      repositories {
        maven { url = 'https://repo.myorg.com' }
      }
    }
    ```

Because the default `archiveClassifier` of [`Jar`][Jar] is `""` (empty), setting the `archiveClassifier` of
[`ShadowJar`][ShadowJar] to `""` (empty) will make collisions between the outputs of these two tasks in some cases.
If you don't need the standard JAR, you can disable the `jar` task like:

=== "Kotlin"

    ```kotlin
    tasks.jar {
      enabled = false
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('jar', Jar) {
      enabled = false
    }
    ```

Or set a different `archiveClassifier` for the standard [`Jar`][Jar] like:

=== "Kotlin"

    ```kotlin
    tasks.jar {
      archiveClassifier = "ignored"
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('jar', Jar) {
      archiveClassifier = 'ignored'
    }
    ```

## Publishing the Shadowed Gradle Plugins

The Gradle Publish Plugin introduced support for plugins packaged with Shadow in version 1.0.0.
Starting with this version, plugin projects that apply both Shadow and the Gradle Plugin Publish plugin will be
automatically configured to publish the output of the [`ShadowJar`][ShadowJar] tasks as the consumable artifact for the
plugin. See the
[Gradle Plugin Publish docs](https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html#shadow_dependencies)
for details. The only thing you need to do from the Shadow side is to empty the `archiveClassifier` like:

=== "Kotlin"

    ```kotlin
    plugins {
      id("com.gradle.plugin-publish") version "latest"
      id("com.gradleup.shadow")
    }

    dependencies {
      // Your plugin dependencies.
    }

    tasks.shadowJar {
      archiveClassifier = ""
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'com.gradle.plugin-publish' version 'latest'
      id 'com.gradleup.shadow'
    }

    dependencies {
      // Your plugin dependencies.
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      archiveClassifier = ''
    }
    ```

## Publishing Custom ShadowJar Task Outputs

It is possible to publish a custom [`ShadowJar`][ShadowJar] task's output via the
[`MavenPublication.artifact()`][MavenPublication.artifact] method.

=== "Kotlin"

    ```kotlin
    plugins {
      java
      `maven-publish`
      id("com.gradleup.shadow")
    }

    val testShadowJar = tasks.register<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("testShadowJar") {
      description = "Create a combined JAR of project and test dependencies"
      archiveClassifier = "tests"
      from(sourceSets.test.map { it.output })
      configurations = project.configurations.testRuntimeClasspath.map { listOf(it) }
    }

    dependencies {
      testImplementation("junit:junit:3.8.2")
    }

    publishing {
      publications {
        create<MavenPublication>("shadow") {
          artifact(testShadowJar)
        }
      }
      repositories {
        maven("https://repo.myorg.com")
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java'
      id 'maven-publish'
      id 'com.gradleup.shadow'
    }

    def testShadowJar = tasks.register('testShadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      description = 'Create a combined JAR of project and test dependencies'
      archiveClassifier = 'tests'
      from sourceSets.named('test').map { it.output }
      configurations = project.configurations.named('testRuntimeClasspath').map { [it] }
    }

    dependencies {
      testImplementation 'junit:junit:3.8.2'
    }

    publishing {
      publications {
        shadow(MavenPublication) {
          artifact(testShadowJar)
        }
      }
      repositories {
        maven { url = 'https://repo.myorg.com' }
      }
    }
    ```

## Publishing the Shadowed JAR with Custom Artifact Name

It is possible to configure the artifact name of the shadowed JAR via properties like `archiveBaseName`, see more
customizable properties listed in [Configuring Output Name](../configuration/README.md#configuring-output-name). e.g.

=== "Kotlin"

    ```kotlin
    plugins {
      java
      `maven-publish`
      id("com.gradleup.shadow")
    }

    group = "my-group"
    version = "1.0"

    tasks.shadowJar {
      archiveClassifier = "my-classifier"
      archiveExtension = "my-ext"
      archiveBaseName = "maven-all"
    }

    publishing {
      publications {
        create<MavenPublication>("shadow") {
          from(components["shadow"])
          // This will override `archiveBaseName`.
          artifactId = "my-artifact"
        }
      }
      repositories {
        maven("https://repo.myorg.com")
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java'
      id 'maven-publish'
      id 'com.gradleup.shadow'
    }

    group = 'my-group'
    version = '1.0'

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      archiveClassifier = 'my-classifier'
      archiveExtension = 'my-ext'
      archiveBaseName = 'maven-all'
    }

    publishing {
      publications {
        shadow(MavenPublication) {
          from components.shadow
          // This will override `archiveBaseName`.
          artifactId = 'my-artifact'
        }
      }
      repositories {
        maven { url = 'https://repo.myorg.com' }
      }
    }
    ```

We modified `archiveClassifier`, `archiveExtension` and `archiveBaseName` in this example, the published artifact will
be named `my-artifact-2.0-my-classifier.my-ext` instead of `1.0-all.jar`.



[Jar]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html
[MavenPublication.artifact]: https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.MavenPublication.html#org.gradle.api.publish.maven.MavenPublication:artifact(java.lang.Object)
[ShadowJar]: ../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/index.html
[maven-publish]: https://docs.gradle.org/current/userguide/publishing_maven.html

---

## File: docs/multi-project/README.md

# Using Shadow in Multi-Project Builds

When using Shadow in a multi-project build, project dependencies will be treated the same as
external dependencies.
That is a project dependency will be merged into the [`ShadowJar`][ShadowJar] output of the project that
is applying the Shadow plugin.

## Depending on the Shadow Jar from Another Project

In a multi-project build there may be one project that applies Shadow and another that
requires the shadowed JAR as a dependency.
In this case, use Gradle's normal dependency declaration mechanism to depend on the `shadow`
configuration of the shadowed project.

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation(project(path = ":api", configuration = "shadow"))
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation project(path: ':api', configuration: 'shadow')
    }
    ```

## Making the Shadowed JAR the Default Artifact

When a project needs to expose the shadowed JAR as its default output — so that consumers can depend on it without
specifying the `shadow` configuration explicitly — you can reconfigure the consumable configurations `apiElements` and
`runtimeElements` to publish the shadowed JAR instead of the regular JAR.

As a reminder, configurations like `api` and `implementation` are where dependencies are declared (_declarable_), while
`apiElements` and `runtimeElements` are what Gradle consumes when projects depend on each other.

By tuning these consumable configurations, a simple declaration like `implementation(project(":api"))` will resolve to
the shadowed JAR by default, preventing accidental consumption of the unshadowed artifact.

**In the shadowed project (`:api`):**

=== "Kotlin"

    ```kotlin
    plugins {
      `java-library`
      id("com.gradleup.shadow")
    }

    configurations {
      named("apiElements") {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.shadowJar)
      }
      named("runtimeElements") {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.shadowJar)
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java-library'
      id 'com.gradleup.shadow'
    }

    configurations {
      apiElements {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.named('shadowJar'))
      }
      runtimeElements {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.named('shadowJar'))
      }
    }
    ```

!!! important

    Clearing `outgoing.variants` ensures Gradle doesn't select the unshadowed `classes` variant by default during compilation.

**Consuming projects can then depend on `:api` without specifying the `shadow` configuration:**

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation(project(":api"))
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation project(':api')
    }
    ```

### Excluding Transitive Dependencies

If you want to exclude transitive dependencies that were bundled into the shadow JAR, you can add `exclude` rules to the
configurations as well:

=== "Kotlin"

    ```kotlin
    configurations {
      named("apiElements") {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.shadowJar)
        exclude(group = "com.example", module = "bundled-library")
      }
      named("runtimeElements") {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.shadowJar)
        exclude(group = "com.example", module = "bundled-library")
      }
    }
    ```

=== "Groovy"

    ```groovy
    configurations {
      apiElements {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.named('shadowJar'))
        exclude group: 'com.example', module: 'bundled-library'
      }
      runtimeElements {
        outgoing.artifacts.clear()
        outgoing.variants.clear()
        outgoing.artifact(tasks.named('shadowJar'))
        exclude group: 'com.example', module: 'bundled-library'
      }
    }
    ```

[Jar]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html
[ShadowJar]: ../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/index.html

---

## File: docs/kotlin-plugins/README.md

# Integrating with Kotlin Plugins

Kotlin standard libraries (stdlib) are added by Kotlin plugins by default via `implementation` (`runtimeClasspath`),
they will be bundled into the shadowed JARs automatically.
If you don't need a standard library at all, you can add the following Gradle property to your gradle.properties file:

```properties
kotlin.stdlib.default.dependency=false
```

Kotlin compilations may still require the standard libraries, you can add them into `compileOnly` (`compileClasspath`)
to make sure compilations success and avoid shadowing as follows:

=== "Kotlin"

    ```kotlin
    dependencies {
      compileOnly("org.jetbrains.kotlin:kotlin-stdlib:<version>")
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:<version>'
    }
    ```

See more information about
[Dependency on the standard library](https://kotlinlang.org/docs/gradle-configure-project.html#dependency-on-the-standard-library).

## For Kotlin JVM Plugin

Shadow works well for Kotlin JVM projects like Java projects. Here is an example:

=== "Kotlin"

    ```kotlin
    plugins {
      id("org.jetbrains.kotlin.jvm")
      id("com.gradleup.shadow")
    }

    dependencies {
      implementation("io.ktor:ktor-client-okhttp:3.1.0")
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'org.jetbrains.kotlin.jvm'
      id 'com.gradleup.shadow'
    }

    dependencies {
      implementation 'io.ktor:ktor-client-okhttp:3.1.0'
    }
    ```

You can mix the Kotlin JVM plugin with `java-gradle-plugin`, `application`, and other Java plugins,
easily organize your build logic for [Publishing Libraries](../publishing/README.md),
[Running Applications](../application-plugin/README.md), and so on.

## For Kotlin Multiplatform Plugin

Shadow honors Kotlin's [`org.jetbrains.kotlin.multiplatform`][org.jetbrains.kotlin.multiplatform] plugin and will
automatically configure additional tasks for bundling the shadowed JAR for its `jvm` target.

=== "Kotlin"

    ```kotlin
    plugins {
      id("org.jetbrains.kotlin.multiplatform")
      id("com.gradleup.shadow")
    }

    kotlin {
      jvm().mainRun {
        // Optionally, set the main class for `runJvm`.
        mainClass = "myapp.MainKt"
      }
      sourceSets {
        commonMain {
          dependencies {
            implementation("io.ktor:ktor-client-core:<version>")
          }
        }
        jvmMain {
          dependencies {
            implementation("io.ktor:ktor-client-okhttp:<version>")
          }
        }
      }
    }

    // TODO: Gradle doesn't generate accessors for this use case, so we can't call `tasks.shadowJar` directly like the other examples.
    tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
      manifest {
        // Optionally, set the main class for the shadowed JAR.
        attributes["Main-Class"] = "com.example.MainKt"
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'org.jetbrains.kotlin.multiplatform'
      id 'com.gradleup.shadow'
    }

    kotlin {
      jvm().mainRun {
        // Optionally, set the main class for `runJvm`.
        it.mainClass.set('myapp.MainKt')
      }
      sourceSets {
        commonMain {
          dependencies {
            implementation "io.ktor:ktor-client-core:<version>"
          }
        }
        jvmMain {
          dependencies {
            implementation "io.ktor:ktor-client-okhttp:<version>"
          }
        }
      }
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      manifest {
        // Optionally, set the main class for the shadowed JAR.
        attributes 'Main-Class': 'com.example.MainKt'
      }
    }
    ```

## Kotlin Module Metadata Remapping

Kotlin module metadata (`.kotlin_module`) files contain information about package parts and facades. When relocating
classes, Shadow automatically relocates the packages and facades inside the Kotlin module metadata files. This feature
is enabled by default via the deprecated `enableKotlinModuleRemapping` property.

To explicitly apply this remapping (recommended for future compatibility), add
[`KotlinModuleMetadataTransformer`][KotlinModuleMetadataTransformer] to your task configuration:

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.KotlinModuleMetadataTransformer::class.java)
    }
    ```

=== "Groovy"

    ```groovy
    tasks.shadowJar {
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.KotlinModuleMetadataTransformer)
    }
    ```

[org.jetbrains.kotlin.multiplatform]: https://kotlinlang.org/docs/multiplatform-intro.html
[KotlinModuleMetadataTransformer]: ../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-kotlin-module-metadata-transformer/index.html

---

## File: docs/groovy-and-scala-plugins/README.md

# Integrating with Groovy and Scala Plugins

Shadow also works well for Groovy and Scala, here are integration examples:

For Groovy:

=== "Kotlin"

    ```kotlin
    plugins {
      groovy
      id("com.gradleup.shadow")
    }

    tasks.shadowJar {
      manifest {
        // Optionally, set the main class for the shadowed JAR.
        attributes["Main-Class"] = "com.example.Main"
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'groovy'
      id 'com.gradleup.shadow'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      manifest {
        // Optionally, set the main class for the shadowed JAR.
        attributes 'Main-Class': 'com.example.Main'
      }
    }
    ```

For Scala:

=== "Kotlin"

    ```kotlin
    plugins {
      scala
      id("com.gradleup.shadow")
    }

    tasks.shadowJar {
      manifest {
        // Optionally, set the main class for the shadowed JAR.
        attributes["Main-Class"] = "com.example.Main"
      }
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'scala'
      id 'com.gradleup.shadow'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      manifest {
        // Optionally, set the main class for the shadowed JAR.
        attributes 'Main-Class': 'com.example.Main'
      }
    }
    ```

You can customize the other configurations of the `shadowJar` task as needed, just like with Java projects.

---

## File: docs/getting-started/README.md

# Getting Started

=== "Kotlin"

    ```kotlin
    plugins {
      java
      id("com.gradleup.shadow") version "<version>"
    }
    ```

=== "Groovy"

    ```groovy
    plugins {
      id 'java'
      id 'com.gradleup.shadow' version '<version>'
    }
    ```

Alternatively, the plugin can be added to the buildscript classpath and applied:

=== "Kotlin"

    ```kotlin
    buildscript {
      repositories {
        mavenCentral()
        gradlePluginPortal()
      }
      dependencies {
        classpath("com.gradleup.shadow:shadow-gradle-plugin:<version>")
      }
    }
    // `apply plugin` stuff are used with `buildscript`.
    apply(plugin = "java")
    apply(plugin = "com.gradleup.shadow")
    ```

=== "Groovy"

    ```groovy
    buildscript {
      repositories {
        mavenCentral()
        gradlePluginPortal()
      }
      dependencies {
        classpath 'com.gradleup.shadow:shadow-gradle-plugin:<version>'
      }
    }
    // `apply plugin` stuff are used with `buildscript`.
    apply plugin: 'java'
    apply plugin: 'com.gradleup.shadow'
    ```

===! "Kotlin"

    
    Snapshots of the development version are available in Central Portal Snapshots.
    
    

    ```kotlin
    buildscript {
      repositories {
        mavenCentral()
        maven("https://central.sonatype.com/repository/maven-snapshots/")
      }
      dependencies {
        // You can get the latest snapshot version from `VERSION_NAME` declared in https://github.com/GradleUp/shadow/blob/main/gradle.properties
        classpath("com.gradleup.shadow:shadow-gradle-plugin:<version>")
      }
    }
    // `apply plugin` stuff are used with `buildscript`.
    apply(plugin = "java")
    apply(plugin = "com.gradleup.shadow")
    ```

    
    

=== "Groovy"

    
    Snapshots of the development version are available in Central Portal Snapshots.
    
    

    ```groovy
    buildscript {
      repositories {
        mavenCentral()
        maven { url = 'https://central.sonatype.com/repository/maven-snapshots/' }
      }
      dependencies {
        // You can get the latest snapshot version from `VERSION_NAME` declared in https://github.com/GradleUp/shadow/blob/main/gradle.properties
        classpath 'com.gradleup.shadow:shadow-gradle-plugin:<version>'
      }
    }
    // `apply plugin` stuff are used with `buildscript`.
    apply plugin: 'java'
    apply plugin: 'com.gradleup.shadow'
    ```

    
    

!!! note

    The correct maven coordinates for each version of Shadow can be found by referencing the Gradle Plugin
    documentation [here](https://plugins.gradle.org/plugin/com.gradleup.shadow).

Shadow is a reactive plugin.
This means that applying Shadow by itself will perform no configuration on your project.
Instead, Shadow _reacts_
This means, that for most users, the `java` or `groovy` plugins must be _explicitly_ applied
to have the desired effect.

## Default Java/Kotlin/Groovy Tasks

In the presence of the `java`, `org.jetbrains.kotlin.jvm` or `groovy` plugins (that apply [`JavaPlugin`][JavaPlugin]
in their build logic), Shadow will automatically configure the following behavior:

* Adds a [`ShadowJar`][ShadowJar] task to the project.
* Adds a `shadow` configuration to the project.
* Adds a `shadow` variant to the project.
* Adds a `shadow` component to the project.
* Configures the [`ShadowJar`][ShadowJar] task to include all sources from the project's `main` sourceSet.
* Configures the [`ShadowJar`][ShadowJar] task to bundle all dependencies from the `runtimeClasspath` configuration.
* Configures the _classifier_ attribute of the [`ShadowJar`][ShadowJar] task to be `'all'` .
* Configures the [`ShadowJar`][ShadowJar] task to generate a `Manifest` with:
    * Inheriting all configuration from the standard [`Jar`][Jar] task.
    * Adds a `Class-Path` attribute to the `Manifest` that appends all dependencies from the `shadow` configuration
* Configures the [`ShadowJar`][ShadowJar] task to _exclude_ any JAR index or cryptographic signature files matching the
  following patterns:
    * `META-INF/INDEX.LIST`
    * `META-INF/*.SF`
    * `META-INF/*.DSA`
    * `META-INF/*.RSA`
    * `META-INF/versions/**/module-info.class`
    * `module-info.class`
* Creates and registers the `shadow` component in the project (used for integrating with
  [`maven-publish`][maven-publish]).

## ShadowJar Command Line options

Sometimes, a user wants to declare the value of an exposed task property on the command line instead of the
build script. Passing property values on the command line is particularly helpful if they change more frequently.  
Here are the options that can be passed to the `shadowJar`:

```
--add-multi-release-attribute         Adds the multi-release attribute to the manifest if any dependencies contain it.
--no-add-multi-release-attribute      Disables option --add-multi-release-attribute.
--enable-auto-relocation              Enables auto relocation of packages in the dependencies.
--no-enable-auto-relocation           Disables option --enable-auto-relocation.
--enable-kotlin-module-remapping      Enables remapping of Kotlin module metadata files.
--no-enable-kotlin-module-remapping   Disables option --enable-kotlin-module-remapping.
--fail-on-duplicate-entries           Fails build if the ZIP entries in the shadowed JAR are duplicate.
--no-fail-on-duplicate-entries        Disables option --fail-on-duplicate-entries.
--main-class                          Main class attribute to add to manifest.
--minimize-jar                        Minimizes the jar by removing unused classes.
--no-minimize-jar                     Disables option --minimize-jar.
--relocation-prefix                   Prefix used for auto relocation of packages in the dependencies.
--rerun                               Causes the task to be re-run even if up-to-date.
```

Also, you can view more information about the [`ShadowJar`][ShadowJar] task by running the following command:

```shell
./gradlew -q help --task shadowJar
```

Refer to
[listing command line options](https://docs.gradle.org/current/userguide/custom_tasks.html#sec:listing_task_options).



[Jar]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html
[JavaPlugin]: https://docs.gradle.org/current/userguide/java_plugin.html
[maven-publish]: https://docs.gradle.org/current/userguide/publishing_maven.html
[ShadowJar]: ../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/index.html

---

## File: docs/custom-tasks/README.md

# Creating a Custom ShadowJar Task

The built in [`ShadowJar`][ShadowJar] task only provides an output for the `main` source set of the project.
It is possible to add arbitrary [`ShadowJar`][ShadowJar] tasks to a project. When doing so, ensure that the
[`configurations`][ShadowJar.configurations] property is specified to inform Shadow which dependencies to merge into
the output.

=== "Kotlin"

    ```kotlin
    val testShadowJar = tasks.register<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("testShadowJar") {
      description = "Create a combined JAR of project and test dependencies"

      archiveClassifier = "test"
      from(sourceSets.test.map { it.output })
      configurations = project.configurations.testRuntimeClasspath.map { listOf(it) }

      manifest {
        // Optionally, set the main class for the JAR.
        attributes(mapOf("Main-Class" to "test.Main"))
        // You can also set other attributes here.
      }
    }

    // Optionally, make the `assemble` task depend on the new task.
    tasks.assemble {
      dependsOn(testShadowJar)
    }
    ```

=== "Groovy"

    ```groovy
    def testShadowJar = tasks.register('testShadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      description = 'Create a combined JAR of project and test dependencies'

      archiveClassifier = 'test'
      from sourceSets.named('test').map { it.output }
      configurations = project.configurations.named('testRuntimeClasspath').map { [it] }

      manifest {
        // Optionally, set the main class for the JAR.
        attributes 'Main-Class': 'test.Main'
        // You can also set other attributes here.
      }
    }

    // Optionally, make the `assemble` task depend on the new task.
    tasks.named('assemble') {
      dependsOn testShadowJar
    }
    ```

The code snippet above will generate a shadowed JAR containing both the `main` and `test` sources as well as all
`testRuntimeOnly` and `testImplementation` dependencies. The file is output to
`build/libs/-<version>-test.jar`.

## Creating a Dependencies-Only Shadow JAR

It is also possible to create a shadow JAR that contains *only* the dependencies and none of the project's own
source code. This is accomplished by creating a custom [`ShadowJar`][ShadowJar] task and configuring the
[`configurations`][ShadowJar.configurations] property, but **not** adding any project sources with `from(...)`.

=== "Kotlin"

    ```kotlin
    val dependencyShadowJar = tasks.register<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("dependencyShadowJar") {
      description = "Create a shadow JAR of all dependencies"
      archiveClassifier = "dep"
      configurations = project.configurations.runtimeClasspath.map { listOf(it) }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.register('dependencyShadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      description = 'Create a shadow JAR of all dependencies'
      archiveClassifier = 'dep'
      configurations = project.configurations.named('runtimeClasspath').map { [it] }
    }
    ```

The above configuration will create a shadow JAR file that contains only the classes from the `runtimeClasspath`
configuration. The standard `jar` task will still produce a JAR with only the project's sources.


[Jar]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html
[ShadowJar.configurations]: ../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/configurations.html
[ShadowJar]: ../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/index.html

---

## File: docs/configuration/minimizing/README.md

# Minimizing

Shadow can automatically remove all JARs and classes of dependencies that are not used by the project, thereby
minimizing the resulting shadowed JAR.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      minimize()
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize()
    }
    ```

A dependency can be excluded from the minimization process, thereby forcing its inclusion the shadow JAR.
This is useful when the dependency analyzer cannot find the usage of a class programmatically, for example if the class
is loaded dynamically via `Class.forName(String)`. Each of the `group`, `name` and `version` fields separated by `:` of
a `dependency` is interpreted as a regular expression.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      minimize {
        exclude(dependency("org.scala-lang:.*:.*"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        exclude(dependency('org.scala-lang:.*:.*'))
      }
    }
    ```

!!! note

    Dependencies scoped as `api` will be automatically excluded from minimization and used as "entry points" on
    minimization.

Similar to [`ShadowJar.dependencies`][ShadowJar.dependencies], projects can also be excluded.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      minimize {
        exclude(project(":api"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        exclude(project(":api"))
      }
    }
    ```

!!! note

    When excluding a `project`, all dependencies of the excluded `project` are automatically excluded from
    minimization as well.

## Minimizing with R8

Shadow can also run [R8][R8] over the final shadowed JAR. This is useful when you want
whole-program shrinking instead of the default dependency analyzer. R8 runs after Shadow has merged, transformed, and
relocated the JAR, so service descriptors in `META-INF/services` are used to keep service providers.

The default R8 configuration only shrinks unused code. It disables name minification and optimization.
R8 also applies rules published in dependency JARs, for example under `META-INF/proguard`.

=== "Kotlin"

    ```kotlin
    repositories {
      google()
    }

    tasks.shadowJar {
      minimize {
        r8 {
          // Optional extra configuration
          proguardRules.add("-keep class com.example.ReflectiveApi { *; }")
          proguardRuleFiles.from(layout.projectDirectory.file("r8-rules.pro"))
          configurationFile.set(layout.buildDirectory.file("r8/configuration.txt"))
        }
      }
    }
    ```

=== "Groovy"

    ```groovy
    repositories {
      google()
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        r8 {
          // Optional extra configuration
          proguardRules.add('-keep class com.example.ReflectiveApi { *; }')
          proguardRuleFiles.from(layout.projectDirectory.file('r8-rules.pro'))
          configurationFile.set(layout.buildDirectory.file('r8/configuration.txt'))
        }
      }
    }
    ```

R8 writes the collective ProGuard configuration it used to `build/shadowJar/r8/configuration.txt` by default. Shadow
passes this location to R8 with `--pg-conf-output`. Set `configurationFile` to retain it elsewhere.

R8 also supports ProGuard reporting options such as

- [`-printmapping`][-printmapping]
- [`-printseeds`][-printseeds]
- [`-printusage`][-printusage]

Add them as `proguardRules` when you want to retain name mappings, matched keep rules, or removed code:

=== "Kotlin"

    ```kotlin
    repositories {
      google()
    }

    tasks.shadowJar {
      minimize {
        r8 {
          enableObfuscation()
          configurationFile.set(layout.buildDirectory.file("r8/configuration.txt"))
          proguardRules.addAll(
            "-printmapping reports/mapping.txt",
            "-printseeds reports/seeds.txt",
            "-printusage reports/usage.txt",
          )
        }
      }
    }
    ```

=== "Groovy"

    ```groovy
    repositories {
      google()
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        r8 {
          enableObfuscation()
          configurationFile.set(layout.buildDirectory.file('r8/configuration.txt'))
          proguardRules.addAll(
            '-printmapping reports/mapping.txt',
            '-printseeds reports/seeds.txt',
            '-printusage reports/usage.txt',
          )
        }
      }
    }
    ```

Relative report paths are resolved from the directory containing `configurationFile`. The example above writes the
reports under `build/r8/reports`. Use absolute paths if the reports must be written independently of the configuration
file location. This behavior follows
[R8's configuration parser][ProguardConfigurationParser].
`-printmapping` only contains renamed items, so call `enableObfuscation()` when you need a useful mapping.

These reporting options belong in the build's R8 configuration, not in rules published inside a dependency JAR.
Android's
[library optimization guidance][library-optimization-guidance]
lists them among the global options that library authors should not publish as consumer keep rules.

Shadow resolves R8 from the `shadowR8` configuration. The default dependency is `com.android.tools:r8`, which is
published by Google Maven rather than Maven Central. Add `google()` to your repositories or override the dependency:

=== "Kotlin"

    ```kotlin
    dependencies {
      shadowR8("com.android.tools:r8:9.1.31")
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      shadowR8 'com.android.tools:r8:9.1.31'
    }
    ```

Advanced R8 command line arguments can be added with `args`. Replacing the default `args` value removes Shadow's
default command line arguments, so prefer the helper functions for common obfuscation and optimization toggles. These
helpers are independent and can be used together.

For example, to downgrade R8 warnings to info:

=== "Kotlin"

    ```kotlin
    repositories {
      google()
    }

    tasks.shadowJar {
      minimize {
        r8 {
          args.addAll(listOf("--map-diagnostics", "warning", "info"))
        }
      }
    }
    ```

=== "Groovy"

    ```groovy
    repositories {
      google()
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        r8 {
          args.addAll(['--map-diagnostics', 'warning', 'info'])
        }
      }
    }
    ```

To enable name obfuscation:

=== "Kotlin"

    ```kotlin
    repositories {
      google()
    }

    tasks.shadowJar {
      minimize {
        r8 {
          enableObfuscation()
        }
      }
    }
    ```

=== "Groovy"

    ```groovy
    repositories {
      google()
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        r8 {
          enableObfuscation()
        }
      }
    }
    ```

To enable optimization:

=== "Kotlin"

    ```kotlin
    repositories {
      google()
    }

    tasks.shadowJar {
      minimize {
        r8 {
          enableOptimization()
        }
      }
    }
    ```

=== "Groovy"

    ```groovy
    repositories {
      google()
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        r8 {
          enableOptimization()
        }
      }
    }
    ```

To enable both:

=== "Kotlin"

    ```kotlin
    repositories {
      google()
    }

    tasks.shadowJar {
      minimize {
        r8 {
          enableObfuscation()
          enableOptimization()
        }
      }
    }
    ```

=== "Groovy"

    ```groovy
    repositories {
      google()
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      minimize {
        r8 {
          enableObfuscation()
          enableOptimization()
        }
      }
    }
    ```

[-printmapping]: https://www.guardsquare.com/manual/configuration/usage#printmapping
[-printseeds]: https://www.guardsquare.com/manual/configuration/usage#printseeds
[-printusage]: https://www.guardsquare.com/manual/configuration/usage#printusage
[library-optimization-guidance]: https://developer.android.com/topic/performance/app-optimization/library-optimization
[R8]: https://r8.googlesource.com/r8
[ProguardConfigurationParser]: https://r8.googlesource.com/r8/+/refs/tags/9.1.31/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
[ShadowJar.dependencies]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/dependencies.html

---

## File: docs/configuration/merging/README.md

# Controlling JAR Content Merging

Shadow allows for customizing the process by which the output JAR is generated through the
[`ResourceTransformer`][ResourceTransformer] interface. This is a concept that has been carried over from the original
Maven Shade implementation. A [`ResourceTransformer`][ResourceTransformer] is invoked for each entry in the JAR before
being written to the final output JAR. This allows a [`ResourceTransformer`][ResourceTransformer] to determine if it
should process a particular entry and apply any modifications before writing the stream to the output.

!!! important "Guaranteed Processing Order"

    [`ResourceTransformer`][ResourceTransformer] follows a guaranteed processing order:

    1. **Project files first**: All files in projects are processed before any dependency files.
    2. **Dependency files second**: Files from configurations (runtime dependencies) or added via [`ShadowJar.from`][ShadowJar.from] are processed after project files.

    This ordering is crucial when merging configuration files where you want to preserve project-specific values while
    merging in additional data from dependencies.

## Handling Duplicates Strategy

`ShadowJar` is a subclass of [`org.gradle.api.tasks.AbstractCopyTask`][AbstractCopyTask], which means it honors the
`duplicatesStrategy` property as its parent classes do. There are several strategies to handle:

- `EXCLUDE`: Do not allow duplicates by ignoring subsequent items to be created at the same path.
- `FAIL`: Throw a `DuplicateFileCopyingException` when subsequent items are to be created at the same path.
- `INCLUDE`: Do not attempt to prevent duplicates.
- `INHERIT`: Use the same strategy as the parent copy specification.
- `WARN`: Do not attempt to prevent duplicates, but log a warning message when multiple items are to be created at the
  same path.

see more details about them in [`DuplicatesStrategy`][DuplicatesStrategy].

`ShadowJar` recognizes `EXCLUDE` as the default, if you want to change the strategy, you can override it like:

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or something else.
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or something else.
    }
    ```

Different strategies will lead to different results for `foo/bar` files in the JARs to be merged:

- `EXCLUDE`: The **first** `foo/bar` file will be included in the final JAR.
- `FAIL`: **Fail** the build with a `DuplicateFileCopyingException` if there are duplicate `foo/bar` files.
- `INCLUDE`: **Duplicate** `foo/bar` entries will be included in the final JAR.
- `INHERIT`: **Fail** the build with an exception like
  `Entry .* is a duplicate but no duplicate handling strategy has been set`.
- `WARN`: **Warn** about duplicates in the build log, this behaves exactly as `INHERIT` otherwise.

!!! note "Precedence of DuplicatesStrategy"

    The `duplicatesStrategy` evaluation takes precedence over transforming and relocating.
    Because `ShadowJar` is a subclass of Gradle's `AbstractCopyTask`, duplicate filtering configured via
    `duplicatesStrategy` is performed at Gradle's `CopySpec` processing layer **before** entries are passed to Shadow's
    internal [`ResourceTransformer`][ResourceTransformer] engine.

If you mix the usages of `duplicatesStrategy = DuplicatesStrategy.EXCLUDE` and
[`ResourceTransformer`][ResourceTransformer] like below:

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      duplicatesStrategy = DuplicatesStrategy.EXCLUDE // The default strategy.
      mergeServiceFiles()
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      duplicatesStrategy = DuplicatesStrategy.EXCLUDE // The default strategy.
      mergeServiceFiles()
    }
    ```

The [`ResourceTransformer`][ResourceTransformer]s like [`ServiceFileTransformer`][ServiceFileTransformer] will not work
as expected because duplicate resource files are filtered out and dropped by Gradle before reaching the transformer.

If Shadow detects a resource matched by a built-in [`ResourceTransformer`][ResourceTransformer] while its
`duplicatesStrategy` is `EXCLUDE`, it will log a warning during the build:

    'META-INF/services/foo' is matched by com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer but its DuplicatesStrategy is EXCLUDE — duplicates may be silently dropped before the transformer processes them.
    Set it to INCLUDE or WARN to ensure all duplicates are processed by the transformer.

Want [`ResourceTransformer`][ResourceTransformer]s and `duplicatesStrategy` to work together? There are several common
steps to take:

1. Set the default strategy to `INCLUDE` or `WARN`.
2. Apply your [`ResourceTransformer`][ResourceTransformer]s.
3. Remove duplicate entries by
    - overriding the default strategy for specific files to `EXCLUDE` or `FAIL` using
    [`filesMatching`][Jar.filesMatching], [`filesNotMatching`][Jar.filesNotMatching], or [`eachFile`][Jar.eachFile] functions
    - or applying [`PreserveFirstFoundResourceTransformer`][PreserveFirstFoundResourceTransformer] for specific files
    - or write your own [`ResourceTransformer`][ResourceTransformer] to handle duplicates
    - or mechanism similar.

Alternatively, you can follow these steps:

1. Set the default strategy to `EXCLUDE` or `FAIL`.
2. Apply your [`ResourceTransformer`][ResourceTransformer]s.
3. Bypass the duplicate entries which should be handled by the [`ResourceTransformer`][ResourceTransformer]s using
    [`filesMatching`][Jar.filesMatching], [`filesNotMatching`][Jar.filesNotMatching], or [`eachFile`][Jar.eachFile] functions
    to set their `duplicatesStrategy` to `INCLUDE` or `WARN`.

!!! warning "Build Cache Impact"

    Functions inherited from [`CopySpec`][CopySpec], such as [`filesMatching`][Jar.filesMatching], [`filesNotMatching`][Jar.filesNotMatching], [`eachFile`][Jar.eachFile], or others, disable the output caching.

Optional steps:

- Enable [`ShadowJar.failOnDuplicateEntries`][ShadowJar.failOnDuplicateEntries] to check duplicate entries in the final JAR.
  This can also ensure the regressions are caught in the future.
- Use [Diffuse](https://github.com/JakeWharton/diffuse) to diff the JARs.

Here are some examples:

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      // Step 1.
      duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
      // Step 2.
      mergeServiceFiles()
      // Step 3. Using `filesNotMatching`:
      filesNotMatching("META-INF/services/**") {
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
      }
      // Step 3. Using `PreserveFirstFoundResourceTransformer`:
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.PreserveFirstFoundResourceTransformer>() {
        resources.add("META-INF/foo/**") // Or something else where the first occurrence should be preserved.
      }
    }

    tasks.shadowJar {
      // Step 1.
      duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
      // Step 2.
      mergeServiceFiles()
      // Step 3. Using `filesMatching`:
      filesMatching("META-INF/services/**") {
        duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
      }
      // Step 3. Using `eachFile`:
      eachFile {
        if (path.startsWith("META-INF/services/")) {
          duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
        }
      }
    }

    tasks.shadowJar {
      // Optional step.
      failOnDuplicateEntries = true
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Step 1.
      duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
      // Step 2.
      mergeServiceFiles()
      // Step 3. Using `filesNotMatching`:
      filesNotMatching('META-INF/services/**') {
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
      }
      // Step 3. Using `PreserveFirstFoundResourceTransformer`:
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.PreserveFirstFoundResourceTransformer) {
        resources.add('META-INF/foo/**') // Or something else where the first occurrence should be preserved.
      }
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Step 1.
      duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
      // Step 2.
      mergeServiceFiles()
      // Step 3. Using `filesMatching`:
      filesMatching('META-INF/services/**') {
        duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
      }
      // Step 3. Using `eachFile`:
      eachFile {
        if (it.path.startsWith('META-INF/services/')) {
          it.duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
        }
      }
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Optional step.
      failOnDuplicateEntries = true
    }
    ```

## Basic ResourceTransformer Usage

For simpler use cases, you can create a basic transformer:

=== "Kotlin"

    ```kotlin
    import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
    import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
    import org.apache.tools.zip.ZipOutputStream
    import org.gradle.api.file.FileTreeElement

    class MyTransformer : ResourceTransformer {
      override fun canTransformResource(element: FileTreeElement): Boolean = true
      override fun transform(context: TransformerContext) {}
      override fun hasTransformedResource(): Boolean = true
      override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {}
    }

    tasks.shadowJar {
      transform<MyTransformer>()
    }
    ```

=== "Groovy"

    ```groovy
    import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
    import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
    import org.apache.tools.zip.ZipOutputStream
    import org.gradle.api.file.FileTreeElement

    class MyTransformer implements ResourceTransformer {
      @Override boolean canTransformResource(FileTreeElement element) { return true }
      @Override void transform(TransformerContext context) {}
      @Override boolean hasTransformedResource() { return true }
      @Override void modifyOutputStream(ZipOutputStream os, boolean preserveFileTimestamps) {}
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      transform(MyTransformer)
    }
    ```

Additionally, a [`ResourceTransformer`][ResourceTransformer] can accept a closure to configure the provided
[`ResourceTransformer`][ResourceTransformer]. An instantiated instance of a [`ResourceTransformer`][ResourceTransformer]
can also be provided.

=== "Kotlin"

    ```kotlin
    import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
    import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
    import org.apache.tools.zip.ZipOutputStream
    import org.gradle.api.file.FileTreeElement

    class MyTransformer(@get:Input var enabled: Boolean = false) : ResourceTransformer {
      override fun canTransformResource(element: FileTreeElement): Boolean = enabled
      override fun transform(context: TransformerContext) {}
      override fun hasTransformedResource(): Boolean = enabled
      override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {}
    }

    tasks.shadowJar {
      // Initialize with default constructor and configure with closure.
      transform<MyTransformer>() {
        enabled = true
      }

      // Or use the instantiated instance with closure.
      transform(MyTransformer(false)) {
        enabled = true
      }
    }
    ```

=== "Groovy"

    ```groovy
    import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
    import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
    import org.apache.tools.zip.ZipOutputStream
    import org.gradle.api.file.FileTreeElement

    class MyTransformer implements ResourceTransformer {
      @Input boolean enabled
      MyTransformer(boolean enabled = false) { this.enabled = enabled }
      @Override boolean canTransformResource(FileTreeElement element) { return enabled }
      @Override void transform(TransformerContext context) {}
      @Override boolean hasTransformedResource() { return enabled }
      @Override void modifyOutputStream(ZipOutputStream os, boolean preserveFileTimestamps) {}
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Initialize with default constructor and configure with closure.
      transform(MyTransformer) {
        enabled = true
      }

      // Or use the instantiated instance with closure.
      transform(new MyTransformer(false)) {
        enabled = true
      }
    }
    ```

## Merging Service Descriptor Files

Java libraries often contain service descriptors files in the `META-INF/services` directory of the JAR.
A service descriptor typically contains a line delimited list of classes that are supported for a particular _service_.
At runtime, this file is read and used to configure library or application behavior.

Multiple dependencies may use the same service descriptor file name.
In this case, it is generally desired to merge the content of each instance of the file into a single output file.
The [`ServiceFileTransformer`][ServiceFileTransformer] class is used to perform this merging.
By default, it will merge each copy of a file under `META-INF/services` into a single file in the output JAR.
You can use either the short syntax method [`mergeServiceFiles()`][ShadowJar.mergeServiceFiles] or the full syntax
method [`transform`][ShadowJar.transform] to add the [`ServiceFileTransformer`][ServiceFileTransformer]:

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      // Short syntax.
      mergeServiceFiles()

      // Full syntax.
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer>()
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Short syntax.
      mergeServiceFiles()

      // Full syntax.
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer)
    }
    ```

!!! note "Groovy Extension Modules"

    Groovy Extension Module descriptor files (located at `META-INF/services/org.codehaus.groovy.runtime.ExtensionModule`)
    are ignored by the [`ServiceFileTransformer`][ServiceFileTransformer].
    This is due to these files having a different syntax than standard service descriptor files.
    Use the [`mergeGroovyExtensionModules()`][mergeGroovyExtensionModules] method to merge
    these files if your dependencies contain them.

### Configuring the Location of Service Descriptor Files

By default, the [`ServiceFileTransformer`][ServiceFileTransformer] is configured to merge files in `META-INF/services`.
This directory can be overridden to merge descriptor files in a different location.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      // Short syntax.
      mergeServiceFiles {
        path = "META-INF/custom"
      }

      // Full syntax.
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer>() {
        path = "META-INF/custom"
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Short syntax.      
      mergeServiceFiles {
        path = 'META-INF/custom'
      }

      // Full syntax.
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer) {
        path = 'META-INF/custom'
      }
    }
    ```

### Excluding/Including Specific Service Descriptor Files From Merging

The [`ServiceFileTransformer`][ServiceFileTransformer] class supports specifying specific files to include or exclude
from merging.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      // Short syntax.
      mergeServiceFiles {
        exclude("META-INF/services/com.acme.*")
      }

      // Full syntax.
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer>() {
        exclude("META-INF/services/com.acme.*")
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Short syntax.
      mergeServiceFiles {
        exclude 'META-INF/services/com.acme.*'
      }

      // Full syntax.
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer) {
        exclude 'META-INF/services/com.acme.*'
      }
    }
    ```

## Merging Groovy Extension Modules

Shadow provides a specific transformer for dealing with Groovy extension module files.
This is due to their special syntax and how they need to be merged together.
The [`GroovyExtensionModuleTransformer`][GroovyExtensionModuleTransformer] will handle these files.
The [`ShadowJar`][ShadowJar] task also provides a short syntax method to add this transformer.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      // Short syntax.
      mergeGroovyExtensionModules()

      // Full syntax.
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer>()
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // Short syntax.
      mergeGroovyExtensionModules()

      // Full syntax.
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer)
    }
    ```

## Merging Log4j2 Plugin Cache Files (`Log4j2Plugins.dat`)

[`Log4j2PluginsCacheFileTransformer`][Log4j2PluginsCacheFileTransformer] is a
[`ResourceTransformer`][ResourceTransformer] that merges
`META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat` plugin caches from all the jars
containing Log4j 2.x Core components. It's a Gradle equivalent of
[Log4j Plugin Descriptor Transformer](https://logging.apache.org/log4j/transform/log4j-transform-maven-shade-plugin-extensions.html#log4j-plugin-cache-transformer).

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer>()
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer)
    }
    ```

## Appending Text Files

Generic text files can be appended together using the [`AppendingTransformer`][AppendingTransformer].
Each file is appended using separators (defaults to `\n`) to separate content.
The [`ShadowJar`][ShadowJar] task provides a short syntax method of [`append(String)`][ShadowJar.append] to configure
this transformer.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      append("test.properties")
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      append 'test.properties'
    }
    ```

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      // short syntax
      append("resources/application.yml", "\n---\n")
      // full syntax
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer>() {
        resource = "resources/custom-config/application.yml"
        separator = "\n---\n"
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      // short syntax
      append('resources/application.yml', '\n---\n')
      // full syntax
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer) {
        resource = 'resources/custom-config/application.yml'
        separator = '\n---\n'
      }
    }
    ```

## Appending XML Files

XML files require a special transformer for merging. The [`XmlAppendingTransformer`][XmlAppendingTransformer]
reads each XML document and merges each root element into a single document.
There is no short syntax method for the [`XmlAppendingTransformer`][XmlAppendingTransformer].
It must be added using the [`transform`][ShadowJar.transform] methods.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.XmlAppendingTransformer>() {
        resource = "properties.xml"
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.XmlAppendingTransformer) {
        resource = 'properties.xml'
      }
    }
    ```

## Merging R8/ProGuard Rule Files

Dependencies may publish ProGuard or R8 rules under `META-INF/proguard`.
When multiple dependencies have files with the same name under `META-INF/proguard`,
the [`ProGuardFilesResourceTransformer`][ProGuardFilesResourceTransformer] merges them into a single file in the
output JAR, while retaining distinct file names for non-conflicting rules. It also relocates matched class names
and package patterns within the rules according to configured relocators.

You can add this transformer using [`transform`][ShadowJar.transform]:

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.ProGuardFilesResourceTransformer>()
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.ProGuardFilesResourceTransformer)
    }
    ```

## Configuring Resource Transformer Filtering by Pattern

There are lots of built-in [`ResourceTransformer`][ResourceTransformer]s provided by Shadow. Some of them extend
[`PatternFilterableResourceTransformer`][PatternFilterableResourceTransformer], which extends
[`PatternFilterable`][PatternFilterable] to provide `include`/`exclude` pattern filtering capabilities. e.g.

- [`ApacheLicenseResourceTransformer`][ApacheLicenseResourceTransformer]
- [`ApacheNoticeResourceTransformer`][ApacheNoticeResourceTransformer]
- [`ProGuardFilesResourceTransformer`][ProGuardFilesResourceTransformer]
- [`ServiceFileTransformer`][ServiceFileTransformer]
- ...

You can use `include`/`exclude` and more methods to configure the patterns for those
[`ResourceTransformer`][ResourceTransformer]s that support it. For example:

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      transform<com.github.jengelman.gradle.plugins.shadow.transformers.ApacheLicenseResourceTransformer>() {
        include("META-INF/LICENSE.*")
        exclude("META-INF/LICENSE.log")
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      transform(com.github.jengelman.gradle.plugins.shadow.transformers.ApacheLicenseResourceTransformer) {
        include 'META-INF/LICENSE.*'
        exclude 'META-INF/LICENSE.log'
      }
    }
    ```

## Finding Resources in the Classpath

When dealing with resource merge conflicts, it can be helpful to find which dependencies contain the conflicting resources.
Shadow provides a [`FindResourceInClasspath`][FindResourceInClasspath] helper task for this purpose.

To scan for resources, register a [`FindResourceInClasspath`][FindResourceInClasspath] task in your build script and configure its `classpath` and the resource patterns to look for:

=== "Kotlin"

    ```kotlin
    tasks.register<com.github.jengelman.gradle.plugins.shadow.tasks.FindResourceInClasspath>("findResources") {
      classpath.from(configurations.runtimeClasspath)
      include("META-INF/services/org.codehaus.groovy.runtime.ExtensionModule")
    }
    ```

=== "Groovy"

    ```groovy
    tasks.register('findResources', com.github.jengelman.gradle.plugins.shadow.tasks.FindResourceInClasspath) {
      classpath.from(configurations.runtimeClasspath)
      include 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule'
    }
    ```

You can then run the task to scan each entry on the classpath and print any matched resources to the console:

```shell
./gradlew findResources
```



[AbstractCopyTask]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.AbstractCopyTask.html
[Jar.eachFile]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:eachFile(org.gradle.api.Action)
[Jar.filesMatching]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:filesMatching(java.lang.Iterable,%20org.gradle.api.Action)
[Jar.filesNotMatching]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:filesNotMatching(java.lang.Iterable,%20org.gradle.api.Action)
[AppendingTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-appending-transformer/index.html
[DuplicatesStrategy]: https://docs.gradle.org/current/javadoc/org/gradle/api/file/DuplicatesStrategy.html
[FindResourceInClasspath]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-find-resource-in-classpath/index.html
[GroovyExtensionModuleTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-groovy-extension-module-transformer/index.html
[Jar]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html
[Log4j2PluginsCacheFileTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-log4j2-plugins-cache-file-transformer/index.html
[ResourceTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-resource-transformer/index.html
[ApacheLicenseResourceTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-apache-license-resource-transformer/index.html
[ApacheNoticeResourceTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-apache-notice-resource-transformer/index.html
[ProGuardFilesResourceTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-pro-guard-files-resource-transformer/index.html
[ServiceFileTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-service-file-transformer/index.html
[PreserveFirstFoundResourceTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-preserve-first-found-resource-transformer/index.html
[PatternFilterable]: https://docs.gradle.org/current/kotlin-dsl/gradle/org.gradle.api.tasks.util/-pattern-filterable/index.html
[PatternFilterableResourceTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-pattern-filterable-resource-transformer/index.html
[ShadowJar.append]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/append.html
[ShadowJar.failOnDuplicateEntries]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/fail-on-duplicate-entries.html
[ShadowJar.from]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:from(java.lang.Object,%20org.gradle.api.Action)
[ShadowJar.mergeServiceFiles]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/merge-service-files.html
[ShadowJar.transform]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/transform.html
[ShadowJar]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/index.html
[XmlAppendingTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-xml-appending-transformer/index.html
[mergeGroovyExtensionModules]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/merge-groovy-extension-modules.html
[CopySpec]: https://docs.gradle.org/current/javadoc/org/gradle/api/file/CopySpec.html

## 2. Official Technical Reference & Guides (GradleUp/GradleUp.github.io)

[](https://gradleup.com/)
[](https://gradleup.com/projects/)
[](https://gradleup.com/docs/community/participate/#slack)
[](https://gradleup.com/docs/community/participate/)

This repository hosts a [GradleUp website](https://gradleup.com/).
It includes the styles and some top-level content.
Project documentation and other information are sourced from other repositories.

## What is GradleUp?

GradleUp is an umbrella [GitHub organization](https://github.com/gradleup) created by, and for, the community.
GradleUp focuses on simplifying building Java, Kotlin and Android projects.
On our menu: Gradle plugins, developer tools and best practices.

**GradleUp is not affiliated with, or sponsored by Gradle, Inc. Gradle Up is an independent organization and its projects, plugins, and products are not affiliated with or sponsored by Gradle, Inc. in any way.**

## License

<a property="dct:title" rel="cc:attributionURL" href="https://gradleup.com">This site</a> by the <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://github.com/GradleUp">GradleUp team and contributors</a> is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

Imported content from external repositories might have other licenses.

## Contributing

Any contributions, typo fixes and patches are welcome!
The content is located inside the project repositories.
If you want to contribute to the GradleUp site,
see the guidelines [here](./CONTRIBUTING.md)