Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api/shadow.api
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public abstract interface class com/github/jengelman/gradle/plugins/shadow/tasks
public abstract fun project (Ljava/lang/Object;)Lorg/gradle/api/specs/Spec;
public abstract fun resolve (Ljava/util/Collection;)Lorg/gradle/api/file/FileCollection;
public abstract fun resolve (Lorg/gradle/api/artifacts/Configuration;)Lorg/gradle/api/file/FileCollection;
public abstract fun resolve (Lorg/gradle/api/file/ConfigurableFileCollection;)Lorg/gradle/api/file/FileCollection;
}

public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter$AbstractDependencyFilter : com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter {
Expand All @@ -175,6 +176,7 @@ public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/Dependenc
public fun resolve (Ljava/util/Collection;)Lorg/gradle/api/file/FileCollection;
protected abstract fun resolve (Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V
public fun resolve (Lorg/gradle/api/artifacts/Configuration;)Lorg/gradle/api/file/FileCollection;
public fun resolve (Lorg/gradle/api/file/ConfigurableFileCollection;)Lorg/gradle/api/file/FileCollection;
}

public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/FindResourceInClasspath : org/gradle/api/DefaultTask, org/gradle/api/tasks/util/PatternFilterable {
Expand Down Expand Up @@ -225,7 +227,7 @@ public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar
public fun getAddMultiReleaseAttribute ()Lorg/gradle/api/provider/Property;
public fun getApiJars ()Lorg/gradle/api/file/ConfigurableFileCollection;
protected abstract fun getArchiveOperations ()Lorg/gradle/api/file/ArchiveOperations;
public fun getConfigurations ()Lorg/gradle/api/provider/SetProperty;
public fun getConfigurations ()Lorg/gradle/api/file/ConfigurableFileCollection;
public fun getDependencyFilter ()Lorg/gradle/api/provider/Property;
public fun getDuplicatesStrategy ()Lorg/gradle/api/file/DuplicatesStrategy;
public fun getEnableAutoRelocation ()Lorg/gradle/api/provider/Property;
Expand Down
6 changes: 3 additions & 3 deletions docs/configuration/dependencies/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ merging can be configured using the [`configurations`][ShadowJar.configurations]

```kotlin
tasks.shadowJar {
configurations = project.configurations.compileClasspath.map { listOf(it) }
configurations.setFrom(project.configurations.compileClasspath)
Copy link
Copy Markdown
Member

@Goooler Goooler Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated DSL samples like this, as there are extension overloads (= assignments) missing from Gradle side, errors like:

No applicable 'assign' function found for '=' overload
Argument type mismatch: actual type is 'NamedDomainObjectProvider<Configuration>', but 'FileCollection' was expected.

For the smooth migrations, I think we can add these extensions for Kotlin/Groovy DSL from Gradle side.

}
```

=== "Groovy"

```groovy
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
configurations = project.configurations.named('compileClasspath').map { [it] }
configurations.setFrom project.configurations.named('compileClasspath')
}
```

Expand All @@ -27,7 +27,7 @@ This means any dependency declared in the `runtimeOnly` configuration would be *

> Note the literal use of [`project.configurations`][Project.configurations] when setting the
> [`configurations`][ShadowJar.configurations] attribute of a [`ShadowJar`][ShadowJar] task.
> This is **required**. It may be tempting to specify `configurations = [configurations.compileClasspath]` but this will
> This is **required**. It may be tempting to specify `configurations.setFrom(configurations.compileClasspath)` but this will
> not have the intended effect, as `configurations.compile` will try to delegate to the
> [`configurations`][ShadowJar.configurations] property of the [`ShadowJar`][ShadowJar] task instead of the `project`

Expand Down
6 changes: 4 additions & 2 deletions docs/configuration/relocation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ relocating), you can try out the trick like:
```kotlin
tasks.shadowJar {
// Empty configurations list will exclude all dependencies.
configurations = emptyList()
configurations.unset()
configurations.unsetConvention()
relocate("com.example", "shadow.com.example")
}
```
Expand All @@ -237,7 +238,8 @@ relocating), you can try out the trick like:
```groovy
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
// Empty configurations list will exclude all dependencies.
configurations = []
configurations.unset()
configurations.unsetConvention()
relocate 'com.example', 'shadow.com.example'
}
```
Expand Down
8 changes: 4 additions & 4 deletions docs/custom-tasks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ the output.

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

manifest {
// Optionally, set the main class for the JAR.
Expand All @@ -36,7 +36,7 @@ the output.

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

manifest {
// Optionally, set the main class for the JAR.
Expand Down Expand Up @@ -67,7 +67,7 @@ source code. This is accomplished by creating a custom [`ShadowJar`][ShadowJar]
tasks.registering(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) {
description = "Create a shadow JAR of all dependencies"
archiveClassifier = "dep"
configurations = project.configurations.runtimeClasspath.map { listOf(it) }
configurations.setFrom(project.configurations.runtimeClasspath)
}
```

Expand All @@ -77,7 +77,7 @@ source code. This is accomplished by creating a custom [`ShadowJar`][ShadowJar]
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] }
configurations.setFrom project.configurations.named('runtimeClasspath')
}
```

Expand Down
6 changes: 3 additions & 3 deletions docs/publishing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ 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
`shadowJar.configurations.setFrom(configurations.myConfiguration)`, there is no automatic
configuration of the POM file.

This automatic configuration occurs _only_ when using the above methods for
Expand Down Expand Up @@ -402,7 +402,7 @@ It is possible to publish a custom [`ShadowJar`][ShadowJar] task's output via th
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) }
configurations.setFrom(project.configurations.testRuntimeClasspath)
}

dependencies {
Expand Down Expand Up @@ -434,7 +434,7 @@ It is possible to publish a custom [`ShadowJar`][ShadowJar] task's output via th
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] }
configurations.setFrom project.configurations.named('testRuntimeClasspath')
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ class JavaPluginsTest : BasePluginTest() {
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] }
configurations.setFrom project.configurations.named('testRuntimeClasspath')
manifest {
attributes '$mainClassAttributeKey': 'my.Main'
}
Expand Down Expand Up @@ -751,7 +751,7 @@ class JavaPluginsTest : BasePluginTest() {
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] }
configurations.setFrom project.configurations.named('testRuntimeClasspath')
manifest {
attributes '$mainClassAttributeKey': 'my.Main'
}
Expand Down Expand Up @@ -795,7 +795,7 @@ class JavaPluginsTest : BasePluginTest() {
def $dependencyShadowJar = tasks.register('$dependencyShadowJar', ${ShadowJar::class.java.name}) {
description = 'Create a shadow JAR of all dependencies'
archiveClassifier = 'dep'
configurations = project.configurations.named('runtimeClasspath').map { [it] }
configurations.setFrom project.configurations.named('runtimeClasspath')
}
"""
.trimIndent()
Expand Down Expand Up @@ -1185,7 +1185,7 @@ class JavaPluginsTest : BasePluginTest() {
}

$shadowJarTask {
configurations = [project.configurations.runtimeClasspath]
configurations.setFrom project.configurations.runtimeClasspath
}

configurations.runtimeClasspath {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ class PublishingTest : BasePluginTest() {
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] }
configurations.setFrom project.configurations.named('testRuntimeClasspath')
}
"""
.trimIndent(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,8 @@ class RelocationTest : BasePluginTest() {
implementation 'junit:junit:3.8.2'
}
$shadowJarTask {
configurations = []
configurations.unset()
configurations.unsetConvention()
relocate('', 'foo/')
}
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl
val taskProvider =
registerShadowJarCommon(tasks.named("jar", Jar::class.java)) { task ->
task.from(sourceSets.named("main").map { it.output })
task.configurations.convention(provider { listOf(runtimeConfiguration) })
task.configurations.convention(provider { runtimeConfiguration })
}
artifacts.add(configurations.shadow.name, taskProvider)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public abstract class ShadowKmpPlugin : Plugin<Project> {
task.from(kotlinJvmMain.map { it.output.allOutputs })
task.configurations.convention(
provider {
listOf(configurations.getByName(kotlinJvmMain.get().runtimeDependencyConfigurationName))
configurations.getByName(kotlinJvmMain.get().runtimeDependencyConfigurationName)
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import org.gradle.api.specs.Spec
Expand All @@ -22,6 +23,13 @@ public interface DependencyFilter : Serializable {
*/
public fun resolve(configurations: Collection<Configuration>): FileCollection

/**
* Resolve a [ConfigurableFileCollection] against the [include]/[exclude] rules in the filter.
*
* Any [Configuration] sources within the collection are resolved individually and combined.
*/
public fun resolve(configurations: ConfigurableFileCollection): FileCollection

/** Exclude dependencies that match the provided [spec]. */
public fun exclude(spec: Spec<ResolvedDependency>)

Expand Down Expand Up @@ -68,6 +76,24 @@ public interface DependencyFilter : Serializable {
.reduceOrNull { acc, fileCollection -> acc + fileCollection } ?: project.files()
}

override fun resolve(configurations: ConfigurableFileCollection): FileCollection {
val extracted = configurations.from.flatMap { source -> extractConfigurations(source) }
return resolve(extracted)
}

private fun extractConfigurations(source: Any): List<Configuration> =
when (source) {
is Configuration -> listOf(source)
is Provider<*> ->
when (val value = source.orNull) {
is Configuration -> listOf(value)
is Iterable<*> -> value.filterIsInstance<Configuration>()
else -> emptyList()
}
is Iterable<*> -> source.filterIsInstance<Configuration>()
else -> emptyList()
}

override fun exclude(spec: Spec<ResolvedDependency>) {
excludeSpecs.add(spec)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import org.apache.tools.zip.Zip64Mode
import org.apache.tools.zip.ZipOutputStream
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.ArchiveOperations
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.CopySpec
Expand Down Expand Up @@ -101,7 +100,7 @@ public abstract class ShadowJar : Jar() {
@get:Classpath
public open val toMinimize: ConfigurableFileCollection = objectFactory.fileCollection {
minimizeJar.map {
if (it) (dependencyFilterForMinimize.resolve(configurations.get()) - apiJars) else emptySet()
if (it) (dependencyFilterForMinimize.resolve(configurations) - apiJars) else emptySet()
}
}

Expand Down Expand Up @@ -137,7 +136,7 @@ public abstract class ShadowJar : Jar() {
* Defaults to a set that contains `runtimeClasspath` or `runtime` configuration.
*/
@get:Classpath
public open val configurations: SetProperty<Configuration> = objectFactory.setProperty()
public open val configurations: ConfigurableFileCollection = objectFactory.fileCollection()

@get:Input
public open val dependencyFilter: Property<DependencyFilter> =
Expand All @@ -146,7 +145,7 @@ public abstract class ShadowJar : Jar() {
/** Final dependencies to be shadowed. */
@get:Classpath
public open val includedDependencies: ConfigurableFileCollection = objectFactory.fileCollection {
dependencyFilter.zip(configurations) { df, cs -> df.resolve(cs) }
dependencyFilter.map { df -> df.resolve(configurations) }
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPlugin.API_CONFIGURATION_NAME
import org.gradle.api.plugins.JavaPlugin.COMPILE_ONLY_API_CONFIGURATION_NAME
import org.gradle.api.plugins.JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
Expand Down Expand Up @@ -154,7 +155,8 @@ class ShadowPropertiesTest {
assertThat(mainClass.orNull).isNull()

assertThat(relocationPrefix.get()).isEqualTo(ShadowBasePlugin.SHADOW)
assertThat(configurations.get()).containsOnly(runtimeConfiguration)
assertThat(configurations.from.map { (it as Provider<*>).get() })
.containsOnly(runtimeConfiguration)
}
}

Expand Down
Loading