-
-
Notifications
You must be signed in to change notification settings - Fork 424
Description
Expected and Results
Expected: Running clean shadowJar twice in a row with local build cache enabled should result in the shadowJar task being FROM-CACHE on the second run.
Actual: The shadowJar task has a cache miss and re-executes on the second run, even though no inputs have changed.
Related environment and versions
- Shadow plugin: 9.3.2 (also verified on 9.4.0 release notes — no caching fix mentioned)
- Gradle: 9.4.1
- Observed in: micrometer-metrics/micrometer
implementations/micrometer-registry-statsd/build.gradle
Reproduction steps
This was observed in the micrometer project which has the following shadowJar configuration:
shadowJar {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
failOnDuplicateEntries = true
configurations.set([project.configurations.compileClasspath])
archiveClassifier.set('')
dependencies {
include(dependency('io.projectreactor:.*'))
include(dependency('io.projectreactor.netty:.*'))
include(dependency('org.reactivestreams:reactive-streams:.*'))
include(dependency('io.netty:.*'))
exclude("META-INF/maven/**")
exclude("META-INF/io.netty.versions.properties")
}
relocate 'reactor', 'io.micrometer.shaded.reactor'
relocate 'org.reactivestreams', 'io.micrometer.shaded.org.reactorstreams'
relocate 'io.netty', 'io.micrometer.shaded.io.netty'
relocate 'META-INF/native/libnetty', 'META-INF/native/libio_micrometer_shaded_netty'
metaInf {
from "$rootDir/LICENSE"
from "$rootDir/NOTICE"
}
mergeServiceFiles()
}Steps to reproduce:
- Clone micrometer:
git clone https://github.com/micrometer-metrics/micrometer - Run:
./gradlew clean :micrometer-registry-statsd:shadowJar --build-cache - Run the same command again:
./gradlew clean :micrometer-registry-statsd:shadowJar --build-cache - Observe that
shadowJaris re-executed instead ofFROM-CACHE
Analysis
This issue was introduced when micrometer upgraded from Shadow 8.3.9 to 9.3.2. With Shadow 8.x, shadowJar was not part of the assemble lifecycle and was not affected. With Shadow 9.x, shadowJar is automatically added to assemble, exposing this caching regression.
The ShadowJar task's @TaskAction (copy() method) calls from(archiveOperations.zipTree(file)) and from(file) dynamically during execution. While the includedDependencies are properly tracked with @Classpath, the interaction between the parent Jar task's CopySpec tracking and the dynamic from() calls during execution may cause cache key instability.
Build scan evidence
- First build: https://ge.solutions-team.gradle.com/s/nv5bsjbia5ize
- Second build (cache miss): https://ge.solutions-team.gradle.com/s/c3dbxceit3bcq
- Task inputs comparison: https://ge.solutions-team.gradle.com/c/nv5bsjbia5ize/c3dbxceit3bcq/task-inputs?cacheability=cacheable,overlapping-outputs,validation-failure