From a49a41b356e41b1383addba278b43d37f8771436 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 13 Aug 2026 21:29:12 +0800 Subject: [PATCH 1/4] Fix formatting and copyright handling in ApacheNoticeResourceTransformer (#1623, #1627, #1628) Original commit on main: 2c104019ffcd8a9e7df4234d0dc28b84100b6496 --- src/docs/changes/README.md | 1 + .../ApacheNoticeResourceTransformer.groovy | 38 +++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 9b00ab0f0..cccf80696 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -20,6 +20,7 @@ - Fix skipStringConstants per-relocator behavior in mapName. ([#1968](https://github.com/GradleUp/shadow/pull/1968)) - Fix excluding dependencies whose versions contain `+`. ([#1597](https://github.com/GradleUp/shadow/pull/1597)) - Fix relocation exclusion for file patterns like `kotlin/kotlin.kotlin_builtins`. ([#1313](https://github.com/GradleUp/shadow/pull/1313)) +- Fix formatting and copyright handling in `ApacheNoticeResourceTransformer`. ([#1623](https://github.com/GradleUp/shadow/pull/1623), [#1627](https://github.com/GradleUp/shadow/pull/1627), [#1628](https://github.com/GradleUp/shadow/pull/1628)) **Deprecated** diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy index f7a8add39..f28ef5a42 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy @@ -71,6 +71,8 @@ class ApacheNoticeResourceTransformer implements Transformer { @Input String copyright + private String fallbackCopyright + /** * The file encoding of the NOTICE file. */ @@ -148,7 +150,7 @@ class ApacheNoticeResourceTransformer implements Transformer { } else { String ent = sb.toString() if (ent.startsWith(projectName) && ent.indexOf("Copyright ") != -1) { - copyright = ent + fallbackCopyright = ent } if (currentOrg == null) { entries.add(ent) @@ -183,42 +185,40 @@ class ApacheNoticeResourceTransformer implements Transformer { zipEntry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, zipEntry.time) os.putNextEntry(zipEntry) - Writer pow - if (StringUtils.isNotEmpty(encoding)) { - pow = new OutputStreamWriter(os, encoding) - } else { - pow = new OutputStreamWriter(os) - } - PrintWriter writer = new PrintWriter(pow) + String actualCopyright = copyright ?: fallbackCopyright + StringBuilder sb = new StringBuilder() int count = 0 for (String line : entries) { ++count - if (line == copyright && count != 2) { + if (line == actualCopyright && count != 2) { continue } - if (count == 2 && copyright != null) { - writer.print(copyright) - writer.print('\n') + if (count == 2 && actualCopyright != null) { + sb.append(actualCopyright).append('\n') } else { - writer.print(line) - writer.print('\n') + sb.append(line).append('\n') } if (count == 3) { //do org stuff for (Map.Entry> entry : organizationEntries.entrySet()) { - writer.print(entry.getKey()) - writer.print('\n') + sb.append(entry.getKey()).append('\n') for (String l : entry.getValue()) { - writer.print(l) + sb.append(l) } - writer.print('\n') + sb.append('\n') } } } - writer.flush() + byte[] bytes + if (StringUtils.isNotEmpty(encoding)) { + bytes = sb.toString().trim().getBytes(encoding) + } else { + bytes = sb.toString().trim().getBytes() + } + os.write(bytes) entries.clear() } From c4acdd9fe229512cdf405c12b9ac7052a2b5e55c Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 13 Aug 2026 21:29:41 +0800 Subject: [PATCH 2/4] Fix ShadowJar not being successful after includes or excludes are changed (#1200) Original commit on main: 450b83108c8c058259919991111a88f00043a414 --- src/docs/changes/README.md | 1 + .../jengelman/gradle/plugins/shadow/tasks/ShadowJar.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index cccf80696..0ff919f31 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -21,6 +21,7 @@ - Fix excluding dependencies whose versions contain `+`. ([#1597](https://github.com/GradleUp/shadow/pull/1597)) - Fix relocation exclusion for file patterns like `kotlin/kotlin.kotlin_builtins`. ([#1313](https://github.com/GradleUp/shadow/pull/1313)) - Fix formatting and copyright handling in `ApacheNoticeResourceTransformer`. ([#1623](https://github.com/GradleUp/shadow/pull/1623), [#1627](https://github.com/GradleUp/shadow/pull/1627), [#1628](https://github.com/GradleUp/shadow/pull/1628)) +- Fix ShadowJar not being re-executed after includes or excludes are changed. ([#1200](https://github.com/GradleUp/shadow/pull/1200)) **Deprecated** diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.java b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.java index 1d3c26fb7..dcc522a49 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.java +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.java @@ -44,6 +44,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.Callable; @CacheableTask @@ -81,6 +82,9 @@ public ShadowJar() { relocators = new ArrayList<>(); configurations = new ArrayList<>(); + this.getInputs().property("minimize", (Callable) () -> minimizeJar); + this.getInputs().property("includes", (Callable>) () -> getIncludes()); + this.getInputs().property("excludes", (Callable>) () -> getExcludes()); this.getOutputs().doNotCacheIf("Has one or more transforms or relocators that are not cacheable", task -> { for (Transformer transformer : transformers) { if (!isCacheableTransform(transformer.getClass())) { From 62dba81ca1a7615fd377b28f5f6219c9a801dd33 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 13 Aug 2026 21:30:26 +0800 Subject: [PATCH 3/4] Honor executableDir in ShadowApplicationPlugin (#1738) Original commit on main: c2cd2ced073e990174d57e33f0555c95a489dd46 --- src/docs/changes/README.md | 1 + .../gradle/plugins/shadow/ShadowApplicationPlugin.groovy | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 0ff919f31..de09fb3c4 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -22,6 +22,7 @@ - Fix relocation exclusion for file patterns like `kotlin/kotlin.kotlin_builtins`. ([#1313](https://github.com/GradleUp/shadow/pull/1313)) - Fix formatting and copyright handling in `ApacheNoticeResourceTransformer`. ([#1623](https://github.com/GradleUp/shadow/pull/1623), [#1627](https://github.com/GradleUp/shadow/pull/1627), [#1628](https://github.com/GradleUp/shadow/pull/1628)) - Fix ShadowJar not being re-executed after includes or excludes are changed. ([#1200](https://github.com/GradleUp/shadow/pull/1200)) +- Respect `executableDir` in application extension when configuring start scripts and distribution. ([#1738](https://github.com/GradleUp/shadow/pull/1738)) **Deprecated** diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy index 9fdc54bc8..3e449f947 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy @@ -94,7 +94,7 @@ class ShadowApplicationPlugin implements Plugin { project.tasks.named(SHADOW_INSTALL_TASK_NAME, Sync).configure { task -> task.doFirst { if (task.destinationDir.directory) { - if (task.destinationDir.listFiles().size() != 0 && (!new File(task.destinationDir, 'lib').directory || !new File(task.destinationDir, 'bin').directory)) { + if (task.destinationDir.listFiles().size() != 0 && (!new File(task.destinationDir, 'lib').directory || !new File(task.destinationDir, 'bin').directory || !new File(task.destinationDir, javaApplication.executableDir).directory)) { throw new GradleException("The specified installation directory '${task.destinationDir}' is neither empty nor does it contain an installation for '${javaApplication.applicationName}'.\n" + "If you really want to install to this directory, delete it and run the install task again.\n" + "Alternatively, choose a different installation directory." @@ -104,7 +104,7 @@ class ShadowApplicationPlugin implements Plugin { } task.doLast { task.eachFile { - if (it.path == "bin/${javaApplication.applicationName}") { + if (it.path == "${javaApplication.executableDir}/${javaApplication.applicationName}") { it.mode = 0x755 } } @@ -122,7 +122,7 @@ class ShadowApplicationPlugin implements Plugin { from(jar) from(project.configurations.shadow) } - into("bin") { + into({ javaApplication.executableDir }) { from(startScripts) filePermissions { it.unix(493) } } From 9bd08dffcf4f3f35c6e175174a75632c0776a250 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Thu, 13 Aug 2026 21:56:52 +0800 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../gradle/plugins/shadow/ShadowApplicationPlugin.groovy | 2 +- .../transformers/ApacheNoticeResourceTransformer.groovy | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy index 3e449f947..e5d7dfd43 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowApplicationPlugin.groovy @@ -94,7 +94,7 @@ class ShadowApplicationPlugin implements Plugin { project.tasks.named(SHADOW_INSTALL_TASK_NAME, Sync).configure { task -> task.doFirst { if (task.destinationDir.directory) { - if (task.destinationDir.listFiles().size() != 0 && (!new File(task.destinationDir, 'lib').directory || !new File(task.destinationDir, 'bin').directory || !new File(task.destinationDir, javaApplication.executableDir).directory)) { + if (task.destinationDir.listFiles().size() != 0 && (!new File(task.destinationDir, 'lib').directory || !new File(task.destinationDir, javaApplication.executableDir).directory)) { throw new GradleException("The specified installation directory '${task.destinationDir}' is neither empty nor does it contain an installation for '${javaApplication.applicationName}'.\n" + "If you really want to install to this directory, delete it and run the install task again.\n" + "Alternatively, choose a different installation directory." diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy index f28ef5a42..11e22fbde 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformer.groovy @@ -214,9 +214,9 @@ class ApacheNoticeResourceTransformer implements Transformer { byte[] bytes if (StringUtils.isNotEmpty(encoding)) { - bytes = sb.toString().trim().getBytes(encoding) + bytes = sb.toString().stripTrailing().getBytes(encoding) } else { - bytes = sb.toString().trim().getBytes() + bytes = sb.toString().stripTrailing().getBytes() } os.write(bytes)