Repository: GradleUp/shadow
Pull request #1365 (2025-03-25 03:07:42)

Support command line options for `ShadowJar`
https://docs.gradle.org/current/userguide/custom_tasks.html#sec:declaring_and_using_command_line_options

---

- [x] [CHANGELOG](https://github.com/GradleUp/shadow/blob/main/docs/changes/README.md)'s "Unreleased" section has been updated, if applicable.



Patch:
diff --git a/docs/changes/README.md b/docs/changes/README.md
index 26086b63..5ee10af1 100644
--- a/docs/changes/README.md
+++ b/docs/changes/README.md
@@ -4,6 +4,20 @@
 ## [Unreleased]
 [Unreleased]: https://github.com/GradleUp/shadow/compare/9.0.0-beta11...HEAD
 
+**Added**
+
+- Support command line options for `ShadowJar`. ([#1365](https://github.com/GradleUp/shadow/pull/1365))
+```
+Options:
+
+--enable-relocation       Enable relocation of packages in the jar
+--no-enable-relocation    Disables option --enable-relocation
+--minimize-jar            Minimize the jar by removing unused classes
+--no-minimize-jar         Disables option --minimize-jar
+--relocation-prefix       Prefix to use for relocated packages
+--rerun                   Causes the task to be re-run even if up-to-date
+```
+
 **Changed**
 
 - Move the group of `ShadowJar` from `shadow` to `build`. ([#1355](https://github.com/GradleUp/shadow/pull/1355))
diff --git a/docs/getting-started/README.md b/docs/getting-started/README.md
index b9dbd48c..c34f3b13 100644
--- a/docs/getting-started/README.md
+++ b/docs/getting-started/README.md
@@ -140,3 +140,18 @@ Shadow will automatically configure the following behavior:
     * `META-INF/versions/**/module-info.class`
     * `module-info.class`
 * Creates and registers the `shadow` component in the project (used for integrating with `maven-publish`).
+
+## ShadowJar Command Line options
+
+Sometimes, a user wants to declare the value of an exposed task property on the command line instead of the 
+build script. Passing property values on the command line is particularly helpful if they change more frequently.  
+Here are the options that can be passed to the `shadowJar`:
+
+```
+--enable-relocation       Enable relocation of packages in the jar
+--no-enable-relocation    Disables option --enable-relocation
+--minimize-jar            Minimize the jar by removing unused classes
+--no-minimize-jar         Disables option --minimize-jar
+--relocation-prefix       Prefix to use for relocated packages
+--rerun                   Causes the task to be re-run even if up-to-date
+```
diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt
index 617cd0c8..2d0db074 100644
--- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt
+++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt
@@ -46,6 +46,7 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.bundling.Jar
 import org.gradle.api.tasks.bundling.ZipEntryCompression
+import org.gradle.api.tasks.options.Option
 
 @CacheableTask
 public abstract class ShadowJar :
@@ -74,6 +75,7 @@ public abstract class ShadowJar :
    * Defaults to `false`.
    */
   @get:Input
+  @get:Option(option = "minimize-jar", description = "Minimize the jar by removing unused classes")
   public open val minimizeJar: Property<Boolean> = objectFactory.property(false)
 
   @get:Classpath
@@ -141,6 +143,7 @@ public abstract class ShadowJar :
    * Defaults to `false`.
    */
   @get:Input
+  @get:Option(option = "enable-relocation", description = "Enable relocation of packages in the jar")
   public open val enableRelocation: Property<Boolean> = objectFactory.property(false)
 
   /**
@@ -149,6 +152,7 @@ public abstract class ShadowJar :
    * Defaults to `shadow`.
    */
   @get:Input
+  @get:Option(option = "relocation-prefix", description = "Prefix to use for relocated packages")
   public open val relocationPrefix: Property<String> = objectFactory.property(ShadowBasePlugin.SHADOW)
 
   @Internal


Test patch:
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
index 0402d96d..1a5072d4 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
@@ -120,6 +120,19 @@ class JavaPluginTest : BasePluginTest() {
     }
   }
 
+  @Test
+  fun shadowJarCliOptions() {
+    val result = run("help", "--task", shadowJarTask)
+
+    assertThat(result.output).contains(
+      "--enable-relocation     Enable relocation of packages in the jar",
+      "--no-enable-relocation     Disables option --enable-relocation",
+      "--minimize-jar     Minimize the jar by removing unused classes",
+      " --no-minimize-jar     Disables option --minimize-jar",
+      "--relocation-prefix     Prefix to use for relocated packages",
+    )
+  }
+
   @Test
   fun includeProjectDependencies() {
     writeClientAndServerModules()
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizationTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizationTest.kt
index 2576bc25..c5343924 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizationTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizationTest.kt
@@ -8,6 +8,8 @@ import com.github.jengelman.gradle.plugins.shadow.util.containsOnly
 import kotlin.io.path.appendText
 import kotlin.io.path.writeText
 import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ValueSource
 
 class MinimizationTest : BasePluginTest() {
   /**
@@ -204,6 +206,37 @@ class MinimizationTest : BasePluginTest() {
     }
   }
 
+  @ParameterizedTest
+  @ValueSource(booleans = [false, true])
+  fun enableMinimizationByCliOption(enable: Boolean) {
+    writeClientAndServerModules()
+
+    if (enable) {
+      run(serverShadowJarTask, "--minimize-jar")
+    } else {
+      run(serverShadowJarTask)
+    }
+
+    assertThat(outputServerShadowJar).useAll {
+      if (enable) {
+        containsAtLeast(
+          "server/Server.class",
+          manifestEntry,
+        )
+        containsNone(
+          "client/Client.class",
+        )
+      } else {
+        containsAtLeast(
+          "client/Client.class",
+          "server/Server.class",
+          *junitEntries,
+          manifestEntry,
+        )
+      }
+    }
+  }
+
   private fun writeApiLibAndImplModules() {
     settingsScriptPath.appendText(
       """
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt
index 52b3a9a3..d8d57088 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt
@@ -3,6 +3,7 @@ package com.github.jengelman.gradle.plugins.shadow
 import assertk.assertFailure
 import assertk.assertThat
 import assertk.assertions.contains
+import assertk.assertions.containsOnly
 import assertk.assertions.isEmpty
 import assertk.assertions.isInstanceOf
 import assertk.assertions.isNotEmpty
@@ -548,6 +549,50 @@ class RelocationTest : BasePluginTest() {
     }
   }
 
+  @ParameterizedTest
+  @MethodSource("relocationCliOptionProvider")
+  fun enableRelocationByCliOption(enableRelocation: Boolean, relocationPrefix: String) {
+    val mainClassEntry = writeClass()
+    projectScriptPath.appendText(
+      """
+        dependencies {
+          implementation 'junit:junit:3.8.2'
+        }
+      """.trimIndent(),
+    )
+    val relocatedEntries = junitEntries.map { "$relocationPrefix/$it" }
+      .filterNot { it.startsWith("$relocationPrefix/META-INF/") }
+      .toTypedArray()
+
+    if (enableRelocation) {
+      run(shadowJarTask, "--enable-relocation", "--relocation-prefix=$relocationPrefix")
+    } else {
+      run(shadowJarTask, "--relocation-prefix=$relocationPrefix")
+    }
+
+    assertThat(outputShadowJar).useAll {
+      if (enableRelocation) {
+        containsAtLeast(
+          mainClassEntry,
+          *relocatedEntries,
+          manifestEntry,
+        )
+        containsNone(
+          *junitEntries.filterNot { it.startsWith("META-INF/") }.toTypedArray(),
+        )
+      } else {
+        containsAtLeast(
+          mainClassEntry,
+          *junitEntries,
+          manifestEntry,
+        )
+        containsNone(
+          *relocatedEntries.filterNot { it.startsWith("META-INF/") }.toTypedArray(),
+        )
+      }
+    }
+  }
+
   private companion object {
     @JvmStatic
     fun prefixProvider() = listOf(
@@ -563,5 +608,13 @@ class RelocationTest : BasePluginTest() {
       Arguments.of(false, true),
       Arguments.of(true, true),
     )
+
+    @JvmStatic
+    fun relocationCliOptionProvider() = listOf(
+      Arguments.of(false, "foo"),
+      Arguments.of(false, "bar"),
+      Arguments.of(true, "foo"),
+      Arguments.of(true, "bar"),
+    )
   }
 }