Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/docs/changes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
**Fixed**

- Support overriding `mainClass` provided by `JavaApplication`. ([#1182](https://github.com/GradleUp/shadow/pull/1182))
- Fix `ShadowJar` not being successful after `includes` or `excludes` are changed. ([#1200](https://github.com/GradleUp/shadow/pull/1200))


## [v9.0.0-beta6] (2025-01-23)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.jengelman.gradle.plugins.shadow.caching

import assertk.assertThat
import com.github.jengelman.gradle.plugins.shadow.util.Issue
import com.github.jengelman.gradle.plugins.shadow.util.containsEntries
import com.github.jengelman.gradle.plugins.shadow.util.doesNotContainEntries
import com.github.jengelman.gradle.plugins.shadow.util.isRegular
Expand Down Expand Up @@ -56,73 +57,99 @@ class ShadowJarCachingTest : BaseCachingTest() {
assertThat(jarPath("build/libs/foo-1.0-all.jar")).isRegular()
}

@Issue(
"https://github.com/GradleUp/shadow/issues/717",
)
@Test
fun shadowJarIsCachedCorrectlyWhenUsingIncludesExcludes() {
writeMainClass(className = "Main")
writeMainClass(className = "Main2")
projectScriptPath.appendText(
"""
dependencies {
implementation 'junit:junit:3.8.2'
}
$shadowJar {
exclude 'junit/*'
implementation 'shadow:a:1.0'
implementation 'shadow:b:1.0'
}
""".trimIndent(),
""".trimIndent() + System.lineSeparator(),
)

path("src/main/java/server/Server.java").writeText(
"""
package server;
import junit.framework.Test;
public class Server {}
""".trimIndent(),
)
path("src/main/java/server/Util.java").writeText(
// First run successful with all files.
assertFirstExecutionSuccess()
assertThat(outputShadowJar).useAll {
containsEntries(
"shadow/Main.class",
"shadow/Main2.class",
"a.properties",
"a2.properties",
"b.properties",
)
}

projectScriptPath.appendText(
"""
package server;
import junit.framework.Test;
public class Util {}
""".trimIndent(),
$shadowJar {
exclude '**.properties'
}
""".trimIndent() + System.lineSeparator(),
)

// Second run successful after excludes changed.
assertFirstExecutionSuccess()
assertThat(outputShadowJar).useAll {
containsEntries(
"server/Server.class",
"server/Util.class",
"shadow/Main.class",
"shadow/Main2.class",
)
doesNotContainEntries(
"a.properties",
"a2.properties",
"b.properties",
)
}

val replaced = projectScriptPath.readText().lines().dropLast(3).joinToString(System.lineSeparator())
projectScriptPath.writeText(
projectScriptPath.appendText(
"""
$replaced
$shadowJar {
include 'server/*'
exclude '*/Util.*'
include 'shadow/Main.class'
}
""".trimIndent(),
""".trimIndent() + System.lineSeparator(),
)
// Third run successful after includes changed.
assertFirstExecutionSuccess()
assertThat(outputShadowJar).useAll {
containsEntries(
"server/Server.class",
"shadow/Main.class",
)
doesNotContainEntries(
"server/Util.class",
"junit/framework/Test.class",
"shadow/Main2.class",
"a.properties",
"a2.properties",
"b.properties",
)
}

assertExecutionsAreCachedAndUpToDate()
projectScriptPath.appendText(
"""
$shadowJar {
include 'shadow/Main2.class'
}
""".trimIndent() + System.lineSeparator(),
)
// Forth run successful after includes changed again.
assertFirstExecutionSuccess()
assertThat(outputShadowJar).useAll {
containsEntries(
"server/Server.class",
"shadow/Main.class",
"shadow/Main2.class",
)
doesNotContainEntries(
"server/Util.class",
"junit/framework/Test.class",
"a.properties",
"a2.properties",
"b.properties",
)
}

// Clean and run 2 more times to ensure the states are cached and up-to-date.
assertExecutionsAreCachedAndUpToDate()
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public abstract class ShadowJar :
duplicatesStrategy = DuplicatesStrategy.INCLUDE
manifest = DefaultInheritManifest(services.get(FileResolver::class.java))

// Ensure includes and excludes are considered as inputs.
// TODO: workaround for https://github.com/gradle/gradle/blob/236bdeb129e4d16c100667b677d4315448bc9ede/subprojects/core-api/src/main/java/org/gradle/api/tasks/util/PatternFilterable.java#L70-L84.
inputs.property("includes", includes)
inputs.property("excludes", excludes)

outputs.doNotCacheIf("Has one or more transforms or relocators that are not cacheable") {
// TODO: this has been called but the cache is still working fine, need to investigate why.
transformers.get().any { !isCacheableTransform(it::class.java) } ||
Expand Down