Support shadowed sources JAR - #2265
Conversation
Goooler
commented
Sep 1, 2026
- CHANGELOG's "Unreleased" section has been updated, if applicable.
51fa468 to
7161bfa
Compare
…t even without dependency sources
29523cb to
68c2e1b
Compare
…h and match unused classes
This reverts commit 23adce5.
This comment was marked as outdated.
This comment was marked as outdated.
This reverts commit 0100ab2. ### 1. Test Versions | Commit Hash | Local Version Tag | Description | | :--- | :--- | :--- | | [`51d5feb5`](51d5feb) | `9.0.3-51d5feb5` | **Before Worker API** (single-threaded serial execution) | | [`0100ab21`](0100ab2) | `9.0.3-0100ab21` | **After Worker API** (asynchronous parallel execution via Gradle Worker API) | --- ### 2. Detailed 10-Iteration Benchmark Results (Unit: ms) | Iteration | Before Worker API (`51d5feb5`) | After Worker API (`0100ab21`) | | :---: | :---: | :---: | | **Warm-up 1** | 19,131.87 | 7,158.15 | | **Warm-up 2** | 937.74 | 927.13 | | **Warm-up 3** | 867.42 | 892.92 | | **Build 1** | 949.85 | 887.27 | | **Build 2** | 855.78 | 895.07 | | **Build 3** | 870.54 | 913.32 | | **Build 4** | 842.07 | 962.29 | | **Build 5** | 834.61 | 902.32 | | **Build 6** | 895.61 | 863.34 | | **Build 7** | 842.98 | 882.96 | | **Build 8** | 836.82 | 862.21 | | **Build 9** | 843.10 | 888.14 | | **Build 10** | 874.22 | 867.52 | --- ### 3. Summary Statistics | Metric | Before Worker API (`51d5feb5`) | After Worker API (`0100ab21`) | Difference | | :--- | :---: | :---: | :--- | | **Mean** | **864.56 ms** | **892.44 ms** | +27.88 ms (+3.2%) | | **Median** | **849.44 ms** | **891.17 ms** | +41.73 ms (+4.9%) | | **Min** | **834.61 ms** | **862.21 ms** | +27.60 ms | | **Max** | **949.85 ms** | **962.29 ms** | +12.44 ms |
There was a problem hiding this comment.
🟡 Changes recommended
There are confirmed correctness/behavior issues (notably a ClassCastException risk in includedSourcesJars and non-deterministic ZIP timestamps) that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds first-class support for generating and publishing a shadowed sources JAR alongside the shadowed binary JAR, including relocation of source contents/paths and optional filtering of sources for minimized dependencies.
Changes:
- Add a new internal implementation to generate a relocated/merged sources JAR from project sources plus dependency
-sources.jars. - Extend
ShadowJar/plugins to wire source directories, resolve dependency sources, and publish a newshadowSourcesElementsvariant. - Add functional/unit tests plus documentation updates covering publishing and doc-generation (Javadoc/Dokka) from shadowed sources.
File summaries
| File | Description |
|---|---|
| src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/JarPath.kt | Exposes toEntries() for broader test assertions. |
| src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSourcesJarTest.kt | Unit tests for package parsing, unused filtering, and package-dir normalization. |
| src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt | Generates shadowed sources JAR during shadowJar execution; tracks unused classes for source filtering. |
| src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowKmpPlugin.kt | Wires KMP JVM sources directories into shadowJar. |
| src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt | Registers/publishes shadowSourcesElements configuration/variant and attaches sources artifact. |
| src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.kt | Fixes application classpaths to use the shadow JAR archive file provider. |
| src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt | Removes outdated comment about source relocation usage. |
| src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSourcesJar.kt | New generator for relocated/merged sources JAR (project + dependency sources). |
| src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilter.kt | Adds dependency-sources resolution (-sources.jar) honoring include/exclude rules. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/LocalMavenRepository.kt | Test repo now publishes sources jars for selected modules. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/GradleModuleMetadata.kt | Adds accessor for new shadowSourcesElements variant. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/util/AppendableMavenRepository.kt | Supports publishing an additional sources artifact in test publications. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt | Adds functional coverage for relocated sources jar output/content and empty-sources behavior. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt | Verifies publishing outputs include shadowed sources jar + new variant metadata; adds KMP publication test. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt | Verifies minimized dependencies also prune corresponding sources from shadowed sources jar (dependency-analyzer mode). |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt | Adds Dokka + package-dir normalization tests consuming shadowed sources jar. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt | Adds Javadoc generation test consuming shadowed sources jar. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FilteringTest.kt | Ensures dependency excludes apply consistently to both binary and sources jars. |
| src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt | Test scaffolding now produces sources jars + exposes standard shadowed sources jar output paths. |
| src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/SnippetExecutable.kt | Adds Dokka-related gradle.properties to stabilize snippet execution in isolated builds. |
| gradle/libs.versions.toml | Adds Dokka version + plugin alias; refactors Dokka plugin declaration to use version ref. |
| docs/publishing/README.md | Documents shadowed sources jar behavior, publishing variant, customization, and Javadoc/Dokka usage. |
| docs/kotlin-plugins/README.md | Links KMP publishing docs for shadowed artifacts/sources. |
| docs/getting-started/README.md | Notes automatic shadowed sources jar generation + variant behavior. |
| docs/configuration/minimizing/README.md | Documents limitation for R8 minimization vis-à-vis sources filtering. |
| CHANGELOG.md | Adds unreleased entry for shadowed sources jar support. |
| build.gradle.kts | Adds Dokka to test plugin runtime classpath. |
| api/shadow.api | Updates ABI dump for new public API surface (sources elements constant + archiveSourcesFile). |
Review details
- Files reviewed: 27/28 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This reverts commit cd245cb.
120f9bb to
6079bbc
Compare
ed571e7 to
ac67d84
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The new shadowed sources JAR generation currently has reproducibility and correctness risks (non-deterministic ZIP ordering and a fragile @file:[...] JvmName(...) regex) that should be addressed before approval.
Review details
Suppressed comments (6)
Previously missed (5) — in code that hasn't changed since the last review.
src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSourcesJar.kt:49
walkTopDown()and iteration oversourceSetsSourceDirscan yield non-deterministic file ordering (filesystem / Set iteration), which makes the generated shadowed sources JAR vary between runs and hurts cacheability/reproducibility. Sorting the source directories and their walked files by relative path produces stable ZIP entry ordering.
src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSourcesJar.kt:92sourcesJarscomes from a FileCollection and may have non-stable iteration order, which can make ZIP entry ordering vary between builds. Sorting the input jars makes the output more reproducible.
src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt:53- This file’s KDoc references
[WARN](DuplicatesStrategy) later on, but the correspondingDuplicatesStrategy.WARNimport was removed in this change. That can break Dokka/KDoc link resolution for theWARNstrategy; re-add the import to keep the links resolvable.
src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt:129 - Typo in comment: “If
withSourcesJarpresents.” should be grammatically “is present”.
src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSourcesJar.kt:152 parentDirectoryEntries()already returns parent directories from root-to-leaf (see Zip.kt), but the extra.asReversed()flips it back to leaf-to-root. This looks unintentional and produces directory entries in a surprising order; iterating in the original order is simpler and more consistent.
src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowSourcesJar.kt:171
jvmNameRegexintends to support bracketed file annotations (e.g.@file:[Suppress(...) JvmName("X")]), but the current(?:\[[^]]*\b)?sub-pattern can stop before the closing]and prevent a match. That makesisUnusedmiss custom facades and keep sources that should be filtered when minimizing.
private val jvmNameRegex =
"""@file\s*:\s*(?:\[[^]]*\b)?(?:kotlin\s*\.\s*jvm\s*\.\s*)?JvmName\s*\(\s*(?:name\s*=\s*)?"([^"]+)""""
.toRegex()
- Files reviewed: 27/28 changed files
- Comments generated: 0 new
- Review effort level: Lite
# Conflicts: # src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt