Skip to content

Commit ab5ffc3

Browse files
committed
Merge remote-tracking branch 'origin/main' into g/20250311/kotlin-new-app-block
// Conflicts: // src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KmpPluginTest.kt
2 parents 271ccdb + 36b8cfb commit ab5ffc3

File tree

34 files changed

+926
-555
lines changed

34 files changed

+926
-555
lines changed

.github/workflows/deploy.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ jobs:
1414
with:
1515
# Fetch all tags and branches, so that MkDocs could push incremental updates.
1616
fetch-depth: 0
17+
- uses: gradle/actions/setup-gradle@v4
18+
with:
19+
cache-read-only: true
20+
# Prepare API documentations for MkDocs.
21+
- run: ./gradlew dokkaHtml --no-configuration-cache
1722
- uses: ./.github/actions/deploy-site

docs/README.md

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,59 @@
11
<div style="text-align: center;">
2-
<img src="images/logo.svg" alt="Shadow Gradle Plugin" style="max-width: 300px; height: auto;">
2+
<img src="images/logo.svg" alt="Shadow Gradle Plugin" width="300"/>
33
<h1><strong>Shadow Gradle Plugin</strong></h1>
4-
<p><em>The library author's dependency toolkit</em></p>
54
</div>
65

7-
---
6+
# Introduction
87

9-
Previously this plugin was developed by [@johnrengelman](https://github.com/johnrengelman) and published under the ID [
10-
`com.github.johnrengelman.shadow`](https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow)
11-
before maintenance was transferred to the [GradleUp organization](https://github.com/GradleUp) to ensure future
12-
development, see [#908](https://github.com/GradleUp/shadow/issues/908).
8+
Shadow is a Gradle plugin for combining a project's dependency classes and resources into a single
9+
output Jar.
10+
The combined Jar is often referred to a _fat-jar_ or _uber-jar_.
11+
Shadow utilizes [`JarInputStream`](https://docs.oracle.com/javase/8/docs/api/java/util/jar/JarInputStream.html) and [`JarOutputStream`](https://docs.oracle.com/javase/8/docs/api/java/util/jar/JarOutputStream.html) to efficiently process dependent libraries
12+
into the output jar without incurring the I/O overhead of expanding the jars to disk.
1313

14-
If you are still using the old plugin ID in your build script, we recommend to switch to the new plugin ID [
15-
`com.gradleup.shadow`](https://plugins.gradle.org/plugin/com.gradleup.shadow)
16-
and update to the latest version to receive all the latest bug fixes and improvements.
14+
!!! warning "Plugin ID Change"
15+
16+
Previously this plugin was developed by [@johnrengelman](https://github.com/johnrengelman) and published under the ID [
17+
`com.github.johnrengelman.shadow`](https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow)
18+
before maintenance was transferred to the [GradleUp organization](https://github.com/GradleUp) to ensure future
19+
development, see [#908](https://github.com/GradleUp/shadow/issues/908).
20+
21+
If you are still using the old plugin ID in your build script, we recommend to switch to the new plugin ID [
22+
`com.gradleup.shadow`](https://plugins.gradle.org/plugin/com.gradleup.shadow)
23+
and update to the latest version to receive all the latest bug fixes and improvements.
24+
25+
## Benefits of Shadow
26+
27+
Shadowing a project output has 2 major use cases:
28+
29+
1. Creating an _executable_ JAR distribution
30+
2. Bundling and relocating common dependencies in libraries to avoid classpath conflicts
31+
32+
### Executable Distributions
33+
34+
Executable distribution is the main use case for deploying an _application_ that can be executed/run in the runtime
35+
environment.
36+
In the case of Shadow, this is a single _uber_ or _fat_ JAR.
37+
The JAR file contains all the application code and dependent libraries to execute (not including the standard JVM
38+
libraries).
39+
The shadow JAR does **not** include the JRE itself.
40+
It must be available on the target system.
41+
42+
Executable JARs contain a JAR MANIFEST that specifies the application Main Class.
43+
This allows the application to be started with a single command:
44+
45+
```shell
46+
java -jar application-shadow.jar
47+
```
48+
49+
### Library Bundling
50+
51+
Dependency bundling and relocation is the main use case for _library_ authors.
52+
The goal of a bundled library is to create a pre-packaged dependency for other libraries or applications to utilize.
53+
Often in these scenarios, a library may contain a dependency that a downstream library or application also uses.
54+
In _some_ cases, different versions of this common dependency can cause an issue in either the upstream library or
55+
the downstream application.
56+
These issues often manifest themselves as binary incompatibilities in either the library or application code.
57+
58+
By utilizing Shadow's ability to _relocate_ the package names for dependencies, a library author can ensure that the
59+
library's dependencies will not conflict with the same dependency being declared by the downstream application.

docs/about/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# About This Project
22

3-
I started this project in December 2012. We were working on converting from a monolithic application into the
3+
I (John Engelman) started this project in December 2012. We were working on converting from a monolithic application into the
44
new hot jazz of "microservices" using Dropwizard.
55
I had also just started learning about Gradle and I knew that the incremental build system it provided would benefit
66
our development team greatly.
77
Unfortunately, the closest thing that Gradle had to Maven's Shade plugin was its ability to create application TARs and
88
ZIPs.
99

10-
So, Charlie Knudsen and I (John Engelman) set out to port the existing Shade code into a Gradle plugin.
10+
So, Charlie Knudsen and I set out to port the existing Shade code into a Gradle plugin.
1111
This port is what existed up until the `0.9` milestone releases for Shadow.
1212
It functioned, but it wasn't idiomatic Gradle by any means.
1313

@@ -19,6 +19,7 @@ so Shadow was published there.
1919
## Maintainers
2020

2121
* [John Engelman](https://github.com/johnrengelman)
22+
* [Goooler](https://github.com/Goooler)
2223

2324
## Contributors
2425

docs/changes/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
- Add Kotlin DSL examples in docs. ([#1306](https://github.com/GradleUp/shadow/pull/1306))
99
- Support using type-safe dependency accessors in `ShadowJar.dependencies`. ([#1322](https://github.com/GradleUp/shadow/pull/1322))
10+
- Set `Main-Class` attr for KMP 2.1.0 or above. ([#1337](https://github.com/GradleUp/shadow/pull/1337))
1011

1112
**Changed**
1213

docs/configuration/merging/README.md

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Controlling JAR Content Merging
22

33
Shadow allows for customizing the process by which the output JAR is generated through the
4-
[`Transformer`](https://gradleup.com/shadow/api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-transformer/index.html) interface.
4+
[`ResourceTransformer`](https://gradleup.com/shadow/api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-resource-transformer/index.html) interface.
55
This is a concept that has been carried over from the original Maven Shade implementation.
6-
A [`Transformer`](https://gradleup.com/shadow/api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-transformer/index.html) is invoked for each
6+
A [`ResourceTransformer`](https://gradleup.com/shadow/api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-resource-transformer/index.html) is invoked for each
77
entry in the JAR before being written to the final output JAR.
8-
This allows a [`Transformer`](https://gradleup.com/shadow/api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-transformer/index.html) to
8+
This allows a [`ResourceTransformer`](https://gradleup.com/shadow/api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-resource-transformer/index.html) to
99
determine if it should process a particular entry and apply any modifications before writing the stream to the output.
1010

1111
=== "Kotlin"
@@ -48,7 +48,7 @@ determine if it should process a particular entry and apply any modifications be
4848
}
4949
```
5050

51-
Additionally, a `Transformer` can accept a `Closure` to configure the provided `Transformer`.
51+
Additionally, a `ResourceTransformer` can accept a `Closure` to configure the provided `ResourceTransformer`.
5252

5353
=== "Kotlin"
5454

@@ -95,7 +95,7 @@ Additionally, a `Transformer` can accept a `Closure` to configure the provided `
9595
}
9696
```
9797

98-
An instantiated instance of a `Transformer` can also be provided.
98+
An instantiated instance of a `ResourceTransformer` can also be provided.
9999

100100
=== "Kotlin"
101101

@@ -254,7 +254,7 @@ method to add this transformer.
254254

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

257-
`Log4j2PluginsCacheFileTransformer` is a `Transformer` that merges `META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat` plugin caches from all the jars
257+
`Log4j2PluginsCacheFileTransformer` is a `ResourceTransformer` that merges `META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat` plugin caches from all the jars
258258
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).
259259

260260
=== "Kotlin"
@@ -355,3 +355,45 @@ It must be added using the [`transform`](https://gradleup.com/shadow/api/shadow/
355355
}
356356
}
357357
```
358+
359+
## Handling Duplicates Strategy
360+
361+
`ShadowJar` is a subclass of
362+
[`org.gradle.api.tasks.AbstractCopyTask`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.AbstractCopyTask.html),
363+
which means it honors the `duplicatesStrategy` property as its parent classes do. There are several strategies to handle:
364+
365+
- `EXCLUDE`: Do not allow duplicates by ignoring subsequent items to be created at the same path.
366+
- `FAIL`: Throw a `DuplicateFileCopyingException` when subsequent items are to be created at the same path.
367+
- `INCLUDE`: Do not attempt to prevent duplicates.
368+
- `INHERIT`: Uses the same strategy as the parent copy specification.
369+
- `WARN`: Do not attempt to prevent duplicates, but log a warning message when multiple items are to be created at the same path.
370+
371+
You can see more details about them in
372+
[`DuplicatesStrategy`](https://docs.gradle.org/current/javadoc/org/gradle/api/file/DuplicatesStrategy.html).
373+
374+
`ShadowJar` recognizes `DuplicatesStrategy.INCLUDE` as the default, if you want to change the strategy, you can
375+
override it like:
376+
377+
=== "Kotlin"
378+
379+
```kotlin
380+
tasks.shadowJar {
381+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or something else.
382+
}
383+
```
384+
385+
=== "Groovy"
386+
387+
```groovy
388+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
389+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or something else.
390+
}
391+
```
392+
393+
Different strategies will lead to different results for `foo/bar` files in the JARs to be merged:
394+
395+
- `EXCLUDE`: The **first** `foo/bar` file will be included in the final JAR.
396+
- `FAIL`: **Fail** the build with a `DuplicateFileCopyingException` if there are duplicated `foo/bar` files.
397+
- `INCLUDE`: The **last** `foo/bar` file will be included in the final JAR (the default behavior).
398+
- `INHERIT`: **Fail** the build with an exception like `Entry .* is a duplicate but no duplicate handling strategy has been set`.
399+
- `WARN`: The **last** `foo/bar` file will be included in the final JAR, and a warning message will be logged.

docs/configuration/relocation/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,31 @@ In versions before 8.1.0 it was necessary to configure a separate `ConfigureShad
127127
in the configurations declared to be shadowed. By default, this is the `runtime` or `runtimeClasspath` configurations.
128128
Be mindful that some Gradle plugins will automatically add dependencies to your class path. You may need to remove these
129129
dependencies if you do not intend to shadow them into your library.
130+
131+
## Relocating Project Resources Only
132+
133+
If you want to relocate the resources of the project only and exclude all dependencies (related to a normal JAR but with
134+
relocating), you can try out the trick like:
135+
136+
=== "Kotlin"
137+
138+
```kotlin
139+
tasks.shadowJar {
140+
// Empty configurations list will exclude all dependencies.
141+
configurations = emptyList()
142+
relocate("com.example", "shadow.com.example")
143+
}
144+
```
145+
146+
=== "Groovy"
147+
148+
```groovy
149+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
150+
// Empty configurations list will exclude all dependencies.
151+
configurations = []
152+
relocate 'com.example', 'shadow.com.example'
153+
}
154+
```
155+
156+
This is useful in some cases like [#759](https://github.com/GradleUp/shadow/issues/759) mentioned. See
157+
[Configuring Shadowed Dependencies](../dependencies/README.md) for more information about `configurations`.

docs/getting-started/README.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,16 @@ Instead, Shadow _reacts_
116116
This means, that for most users, the `java` or `groovy` plugins must be _explicitly_ applied
117117
to have the desired effect.
118118

119-
## Default Java/Groovy Tasks
119+
## Default Java/Kotlin/Groovy Tasks
120120

121-
In the presence of the `java` or `groovy` plugins, Shadow will automatically configure the
122-
following behavior:
121+
In the presence of the `java`, `org.jetbrains.kotlin.jvm` or `groovy` plugins
122+
(that apply [JavaPlugin](https://docs.gradle.org/current/userguide/java_plugin.html) in their build logic),
123+
Shadow will automatically configure the following behavior:
123124

124125
* Adds a `shadowJar` task to the project.
125126
* Adds a `shadow` configuration to the project.
127+
* Adds a `shadow` variant to the project.
128+
* Adds a `shadow` component to the project.
126129
* Configures the `shadowJar` task to include all sources from the project's `main` sourceSet.
127130
* Configures the `shadowJar` task to bundle all dependencies from the `runtimeClasspath` configuration.
128131
* Configures the _classifier_ attribute of the `shadowJar` task to be `'all'` .
@@ -137,10 +140,3 @@ following behavior:
137140
* `META-INF/versions/**/module-info.class`
138141
* `module-info.class`
139142
* Creates and registers the `shadow` component in the project (used for integrating with `maven-publish`).
140-
141-
## Shadowing Gradle Plugins
142-
143-
Shadow ships with a companion task that can be used to automatically discover dependency packages and configure
144-
them for relocation. This is useful in projects if you want to relocate all dependencies.
145-
146-
For more details see the section [Using Shadow to Package Gradle Plugins](../plugins/README.md)
File renamed without changes.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Integrating with Groovy and Scala Plugins
2+
3+
Shadow also works well for Groovy and Scala, here are integration examples:
4+
5+
For Groovy:
6+
7+
=== "Kotlin"
8+
9+
```kotlin
10+
plugins {
11+
groovy
12+
id("com.gradleup.shadow")
13+
}
14+
15+
dependencies {
16+
// If you don't want the Groovy standard library to be shadowed, please replace `implementation` with `api`.
17+
implementation(localGroovy())
18+
}
19+
20+
tasks.shadowJar {
21+
manifest {
22+
// Optionally, set the main class for the shadowed JAR.
23+
attributes["Main-Class"] = "com.example.Main"
24+
}
25+
}
26+
```
27+
28+
=== "Groovy"
29+
30+
```groovy
31+
plugins {
32+
id 'groovy'
33+
id 'com.gradleup.shadow'
34+
}
35+
36+
dependencies {
37+
// If you don't want the Groovy standard library to be shadowed, please replace `implementation` with `api`.
38+
implementation localGroovy()
39+
}
40+
41+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
42+
manifest {
43+
// Optionally, set the main class for the shadowed JAR.
44+
attributes 'Main-Class': 'com.example.Main'
45+
}
46+
}
47+
```
48+
49+
For Scala:
50+
51+
=== "Kotlin"
52+
53+
```kotlin
54+
plugins {
55+
scala
56+
id("com.gradleup.shadow")
57+
}
58+
59+
dependencies {
60+
// If you don't want the Scala standard library to be shadowed, please replace `implementation` with `api`.
61+
implementation("org.scala-lang:scala-library:2.13.16")
62+
}
63+
64+
tasks.shadowJar {
65+
manifest {
66+
// Optionally, set the main class for the shadowed JAR.
67+
attributes["Main-Class"] = "com.example.Main"
68+
}
69+
}
70+
```
71+
72+
=== "Groovy"
73+
74+
```groovy
75+
plugins {
76+
id 'scala'
77+
id 'com.gradleup.shadow'
78+
}
79+
80+
dependencies {
81+
// If you don't want the Scala standard library to be shadowed, please replace `implementation` with `api`.
82+
implementation 'org.scala-lang:scala-library:2.13.16'
83+
}
84+
85+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
86+
manifest {
87+
// Optionally, set the main class for the shadowed JAR.
88+
attributes 'Main-Class': 'com.example.Main'
89+
}
90+
}
91+
```

docs/introduction/README.md

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
 (0)