From b6b90f9f0fd3f4edf2e5255fdd7a22a97872c48f Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 2 Feb 2025 10:13:33 +0800 Subject: [PATCH 01/72] Don't deploy website on 8.x branch --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1055e210d..b34587e60 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -76,6 +76,5 @@ tasks.register("release") { dependsOn( tasks.publish, tasks.publishPlugins, - tasks.gitPublishPush, ) } From 8f4d4b4eea41054739d309797a47a50a40d12ceb Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Sun, 8 Dec 2024 00:12:57 +0800 Subject: [PATCH 02/72] Tweak Gradle flags (#1093) (cherry picked from commit ccc04a67c791134114c64ef296b753d7ecbf8c45) --- build-logic/gradle.properties | 1 + gradle.properties | 10 +++-- src/docs/configuration/merging/README.md | 55 +++++++++++++++--------- 3 files changed, 43 insertions(+), 23 deletions(-) create mode 100644 build-logic/gradle.properties diff --git a/build-logic/gradle.properties b/build-logic/gradle.properties new file mode 100644 index 000000000..338c1c3fc --- /dev/null +++ b/build-logic/gradle.properties @@ -0,0 +1 @@ +org.gradle.kotlin.dsl.allWarningsAsErrors=true diff --git a/gradle.properties b/gradle.properties index e8d2c2537..d41ad959d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,13 @@ -org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx4g -XX:MaxMetaspaceSize=2g -org.gradle.parallel=true +# Omit automatic compile dependency on kotlin-stdlib +# https://kotlinlang.org/docs/gradle.html#dependency-on-the-standard-library +kotlin.stdlib.default.dependency=false + org.gradle.caching=true org.gradle.configuration-cache=true org.gradle.configuration-cache.parallel=true - +org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx4g -XX:MaxMetaspaceSize=2g +org.gradle.kotlin.dsl.allWarningsAsErrors=true +org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin diff --git a/src/docs/configuration/merging/README.md b/src/docs/configuration/merging/README.md index 72882fb65..9c9fbcc42 100644 --- a/src/docs/configuration/merging/README.md +++ b/src/docs/configuration/merging/README.md @@ -12,17 +12,22 @@ determine if it should process a particular entry and apply any modifications be // Adding a Transformer import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext +import javax.annotation.Nonnull import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement class MyTransformer implements Transformer { - boolean canTransformResource(FileTreeElement element) { true } + @Override + boolean canTransformResource(@Nonnull FileTreeElement element) { return true } - void transform(TransformerContext context) {} + @Override + void transform(@Nonnull TransformerContext context) {} - boolean hasTransformedResource() { true } + @Override + boolean hasTransformedResource() { return true } - void modifyOutputStream(ZipOutputStream jos, boolean preserveFileTimestamps) {} + @Override + void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {} } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { @@ -36,20 +41,24 @@ Additionally, a `Transformer` can accept a `Closure` to configure the provided ` // Configuring a Transformer import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext +import javax.annotation.Nonnull import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement class MyTransformer implements Transformer { + boolean enabled - boolean enabled + @Override + boolean canTransformResource(@Nonnull FileTreeElement element) { return true } - boolean canTransformResource(FileTreeElement element) { true } + @Override + void transform(@Nonnull TransformerContext context) {} - void transform(TransformerContext context) {} + @Override + boolean hasTransformedResource() { return true } - boolean hasTransformedResource() { true } - - void modifyOutputStream(ZipOutputStream jos, boolean preserveFileTimestamps) {} + @Override + void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {} } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { @@ -65,24 +74,32 @@ An instantiated instance of a `Transformer` can also be provided. // Adding a Transformer Instance import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext +import javax.annotation.Nonnull import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement class MyTransformer implements Transformer { + final boolean enabled - boolean enabled + MyTransformer(boolean enabled) { + this.enabled = enabled + } - boolean canTransformResource(FileTreeElement element) { true } + @Override + boolean canTransformResource(@Nonnull FileTreeElement element) { return true } - void transform(TransformerContext context) {} + @Override + void transform(@Nonnull TransformerContext context) {} - boolean hasTransformedResource() { true } + @Override + boolean hasTransformedResource() { return true } - void modifyOutputStream(ZipOutputStream jos, boolean preserveFileTimestamps) {} + @Override + void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {} } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - transform(new MyTransformer(enabled: true)) + transform(new MyTransformer(true)) } ``` @@ -186,11 +203,9 @@ It must be added using the [`transform`](https://gradleup.com/shadow/api/com/git ```groovy // Appending a XML File -import com.github.jengelman.gradle.plugins.shadow.transformers.XmlAppendingTransformer - tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - transform(XmlAppendingTransformer.class) { + transform(com.github.jengelman.gradle.plugins.shadow.transformers.XmlAppendingTransformer.class) { resource = 'properties.xml' } } -``` \ No newline at end of file +``` From 12328c9b138afe9dff03b07e6825495b795b04cb Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 2 Feb 2025 17:25:37 +0800 Subject: [PATCH 03/72] Run CI for 8.x branch --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce18159a0..8a8c880da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,8 +3,10 @@ name: CI on: push: branches: - - main + - 8.x pull_request: + branches: + - 8.x workflow_dispatch: jobs: @@ -27,7 +29,7 @@ jobs: publish-snapshot: needs: build runs-on: ubuntu-latest - if: github.repository == 'GradleUp/shadow' && github.ref == 'refs/heads/main' + if: github.repository == 'GradleUp/shadow' && github.ref == 'refs/heads/8.x' steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 From 611253d5d7be0af5bcd69cc106d80371459e7e67 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:29:25 +0800 Subject: [PATCH 04/72] Update dependency gradle to v8.12.1 (#1113) * Update dependency gradle to v8.12 * Space-assignment syntax in Groovy DSL has been deprecated. This is scheduled to be removed in Gradle 10.0. Consult the upgrading guide for further information: https://docs.gradle.org/8.12/userguide/upgrading_version_8.html#groovy_space_assignment_syntax * Update dependency gradle to v8.12.1 * Fix `auto relocate plugin dependencies` --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler (cherry picked from commit 4ffb34f550dffedeea32fc5b54384f425a9eb87a) (cherry picked from commit 7c76ebc0a12cbb1ae36fa926f8d17815750fbb9f) --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 +- .../shadow/ConfigurationCacheSpec.groovy | 6 +-- .../ConfigureShadowRelocationSpec.groovy | 2 +- .../plugins/shadow/PublishingSpec.groovy | 24 ++++----- .../plugins/shadow/RelocationSpec.groovy | 32 +++++------ .../plugins/shadow/ShadowPluginSpec.groovy | 54 +++++++++---------- .../caching/MinimizationCachingSpec.groovy | 6 +-- .../shadow/util/PluginSpecification.groovy | 2 +- 9 files changed, 65 insertions(+), 66 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 94113f200..e18bc253b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6d6..f3b75f3b0 100755 --- a/gradlew +++ b/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy index f05a6170b..461a82061 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy @@ -93,7 +93,7 @@ class ConfigurationCacheSpec extends PluginSpecification { """.stripIndent() file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } """.stripIndent() @@ -112,7 +112,7 @@ class ConfigurationCacheSpec extends PluginSpecification { } } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -151,7 +151,7 @@ class ConfigurationCacheSpec extends PluginSpecification { apply plugin: 'java' apply plugin: 'com.gradleup.shadow' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation "junit:junit:3.8.2" } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy index bcb1a6981..c7212ddbb 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy @@ -9,7 +9,7 @@ class ConfigureShadowRelocationSpec extends PluginSpecification { given: buildFile << """ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - enableRelocation true + enableRelocation = true } dependencies { diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy index d79a07c68..f23895394 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy @@ -35,12 +35,12 @@ class PublishingSpec extends PluginSpecification { implementation 'shadow:a:1.0' shadow 'shadow:b:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { archiveClassifier = '' archiveBaseName = 'maven-all' } - + publishing { publications { shadow(MavenPublication) { @@ -50,7 +50,7 @@ class PublishingSpec extends PluginSpecification { } repositories { maven { - url "${publishingRepo.uri}" + url = "${publishingRepo.uri}" } } } @@ -102,7 +102,7 @@ class PublishingSpec extends PluginSpecification { implementation 'shadow:a:1.0' shadow 'shadow:b:1.0' } - + publishing { publications { shadow(MavenPublication) { publication -> @@ -112,11 +112,11 @@ class PublishingSpec extends PluginSpecification { } repositories { maven { - url "${publishingRepo.uri}" + url = "${publishingRepo.uri}" } } } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { archiveClassifier = 'my-classifier' archiveExtension = 'my-ext' @@ -149,12 +149,12 @@ class PublishingSpec extends PluginSpecification { version = "1.0" group = 'shadow' - - repositories { maven { url "${repo.uri}" } } + + repositories { maven { url = "${repo.uri}" } } publishing { repositories { maven { - url "${publishingRepo.uri}" + url = "${publishingRepo.uri}" } } } @@ -184,7 +184,7 @@ class PublishingSpec extends PluginSpecification { plugins { id 'com.gradleup.shadow' } - + dependencies { implementation project(':a') shadow project(':b') @@ -194,7 +194,7 @@ class PublishingSpec extends PluginSpecification { archiveClassifier = '' archiveBaseName = 'maven-all' } - + publishing { publications { shadow(MavenPublication) { @@ -263,7 +263,7 @@ class PublishingSpec extends PluginSpecification { } repositories { maven { - url "${publishingRepo.uri}" + url = "${publishingRepo.uri}" } } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy index b9f522345..da4e1fb74 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy @@ -16,7 +16,7 @@ class RelocationSpec extends PluginSpecification { dependencies { implementation 'junit:junit:3.8.2' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { relocate 'junit.textui', 'a' relocate 'junit.framework', 'b' @@ -81,7 +81,7 @@ class RelocationSpec extends PluginSpecification { dependencies { implementation 'junit:junit:3.8.2' } - + // tag::relocateFilter[] tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { relocate('junit.textui', 'a') { @@ -138,7 +138,7 @@ class RelocationSpec extends PluginSpecification { dependencies { implementation 'junit:junit:3.8.2' } - + // tag::relocate[] tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { relocate 'junit.framework', 'shadow.junit' @@ -148,7 +148,7 @@ class RelocationSpec extends PluginSpecification { file('src/main/java/shadow/ShadowTest.java') << ''' package shadow; - + import junit.framework.Test; import junit.framework.TestResult; public class ShadowTest implements Test { @@ -185,8 +185,8 @@ class RelocationSpec extends PluginSpecification { given: 'Core project with dependency and resource' file('core/build.gradle') << """ apply plugin: 'java-library' - - repositories { maven { url "${repo.uri}" } } + + repositories { maven { url = "${repo.uri}" } } dependencies { api 'junit:junit:3.8.2' } """.stripIndent() @@ -194,9 +194,9 @@ class RelocationSpec extends PluginSpecification { file('core/src/main/resources/test.properties') << 'name=test' file('core/src/main/java/core/Core.java') << ''' package core; - + import junit.framework.Test; - + public class Core {} '''.stripIndent() @@ -204,10 +204,10 @@ class RelocationSpec extends PluginSpecification { file('app/build.gradle') << """ apply plugin: 'java' apply plugin: 'com.gradleup.shadow' - - repositories { maven { url "${repo.uri}" } } + + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':core') } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { relocate 'core', 'app.core' relocate 'junit.framework', 'app.junit.framework' @@ -217,10 +217,10 @@ class RelocationSpec extends PluginSpecification { file('app/src/main/resources/APP-TEST') << 'APP TEST RESOURCE' file('app/src/main/java/app/App.java') << ''' package app; - + import core.Core; import junit.framework.Test; - + public class App {} '''.stripIndent() @@ -255,7 +255,7 @@ class RelocationSpec extends PluginSpecification { .publish() file('src/main/java/foo/Foo.java') << ''' package foo; - + class Foo {} '''.stripIndent() file('src/main/resources/foo/foo.properties') << 'name=foo' @@ -264,7 +264,7 @@ class RelocationSpec extends PluginSpecification { dependencies { implementation 'shadow:dep:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { relocate 'foo', 'bar' } @@ -296,7 +296,7 @@ class RelocationSpec extends PluginSpecification { repositories { mavenCentral() maven { - url 'https://repository.mapr.com/nexus/content/groups/mapr-public/releases' + url = 'https://repository.mapr.com/nexus/content/groups/mapr-public/releases' } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy index a19284e5a..f4cdbb6fd 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy @@ -175,7 +175,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } """.stripIndent() @@ -191,7 +191,7 @@ class ShadowPluginSpec extends PluginSpecification { apply plugin: 'java' apply plugin: 'com.gradleup.shadow' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -227,7 +227,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } """.stripIndent() @@ -249,7 +249,7 @@ class ShadowPluginSpec extends PluginSpecification { minimize() } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -285,7 +285,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } """.stripIndent() @@ -304,7 +304,7 @@ class ShadowPluginSpec extends PluginSpecification { } } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -339,7 +339,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } """.stripIndent() file('server/src/main/java/server/Server.java') << """ @@ -357,7 +357,7 @@ class ShadowPluginSpec extends PluginSpecification { } } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -393,7 +393,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } """.stripIndent() @@ -412,7 +412,7 @@ class ShadowPluginSpec extends PluginSpecification { } } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -446,7 +446,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } """.stripIndent() @@ -465,7 +465,7 @@ class ShadowPluginSpec extends PluginSpecification { } } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -506,7 +506,7 @@ class ShadowPluginSpec extends PluginSpecification { file('lib/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } """.stripIndent() file('api/src/main/java/api/Entity.java') << """ @@ -522,7 +522,7 @@ class ShadowPluginSpec extends PluginSpecification { file('api/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' implementation project(':lib') @@ -543,7 +543,7 @@ class ShadowPluginSpec extends PluginSpecification { minimize() } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { api project(':api') } """.stripIndent() @@ -585,7 +585,7 @@ class ShadowPluginSpec extends PluginSpecification { file('lib/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } """.stripIndent() file('api/src/main/java/api/Entity.java') << """ @@ -601,7 +601,7 @@ class ShadowPluginSpec extends PluginSpecification { file('api/build.gradle') << """ apply plugin: 'java-library' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { api project(':lib') } """.stripIndent() @@ -619,7 +619,7 @@ class ShadowPluginSpec extends PluginSpecification { minimize() } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { api project(':api') } """.stripIndent() @@ -653,7 +653,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' apply plugin: 'com.gradleup.shadow' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { @@ -673,7 +673,7 @@ class ShadowPluginSpec extends PluginSpecification { file('server/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(path: ':client', configuration: 'shadow') } """.stripIndent() @@ -710,7 +710,7 @@ class ShadowPluginSpec extends PluginSpecification { file('client/build.gradle') << """ apply plugin: 'java' apply plugin: 'com.gradleup.shadow' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { @@ -731,7 +731,7 @@ class ShadowPluginSpec extends PluginSpecification { apply plugin: 'java' apply plugin: 'com.gradleup.shadow' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(path: ':client', configuration: 'shadow') } """.stripIndent() @@ -982,7 +982,7 @@ class ShadowPluginSpec extends PluginSpecification { dependencies { shadow 'junit:junit:3.8.2' } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - zip64 true + zip64 = true entryCompression = org.gradle.api.tasks.bundling.ZipEntryCompression.STORED } """.stripIndent() @@ -1004,7 +1004,7 @@ class ShadowPluginSpec extends PluginSpecification { file('lib/build.gradle') << """ apply plugin: 'java' version = '1.0' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } """.stripIndent() file('api/src/main/java/api/UnusedEntity.java') << """ @@ -1015,7 +1015,7 @@ class ShadowPluginSpec extends PluginSpecification { file('api/build.gradle') << """ apply plugin: 'java' version = '1.0' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' implementation project(':lib') @@ -1027,7 +1027,7 @@ class ShadowPluginSpec extends PluginSpecification { apply plugin: 'com.gradleup.shadow' version = '1.0' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { api project(':api') } shadowJar.minimize() @@ -1126,7 +1126,7 @@ class ShadowPluginSpec extends PluginSpecification { buildscript { repositories { maven { - url "https://maven.eveoh.nl/content/repositories/releases" + url = "https://maven.eveoh.nl/content/repositories/releases" } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy index a20ffdf74..013c8c936 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy @@ -20,7 +20,7 @@ class MinimizationCachingSpec extends AbstractCachingSpec { file('client/build.gradle') << """ apply plugin: 'java' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation 'junit:junit:3.8.2' } """.stripIndent() @@ -33,7 +33,7 @@ class MinimizationCachingSpec extends AbstractCachingSpec { apply plugin: 'java' apply plugin: 'com.gradleup.shadow' - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() @@ -61,7 +61,7 @@ class MinimizationCachingSpec extends AbstractCachingSpec { } } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } dependencies { implementation project(':client') } """.stripIndent() assertShadowJarExecutes() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index d33e95530..04514ec69 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -49,7 +49,7 @@ abstract class PluginSpecification extends Specification { integTest } - repositories { maven { url "${repo.uri}" } } + repositories { maven { url = "${repo.uri}" } } """.stripIndent() } From eea1451d844e056365f265ebc6ea601851dbbfaa Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 2 Feb 2025 17:54:22 +0800 Subject: [PATCH 05/72] Revert "Remove Develocity integration (#1014)" This reverts commit e316b14eb2d5606a88397b38a6cb0a5eacb30c65. --- src/docs/changes/README.md | 4 --- .../gradle/plugins/shadow/ShadowPlugin.groovy | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index d1d7af7c7..b9be1a5e6 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,10 +3,6 @@ ## [Unreleased] -**Removed** - -- **BREAKING CHANGE:** Remove Develocity integration. ([#1013](https://github.com/GradleUp/shadow/pull/1013)) - ## [v8.3.5] (2024-11-03) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.groovy index 63db72aab..b3e8b88ea 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPlugin.groovy @@ -25,6 +25,33 @@ class ShadowPlugin implements Plugin { // etc. if the user applies shadow before those plugins. However, this is fine, because this was also // the behavior with the old plugin when applying in that order. plugins.apply(LegacyShadowPlugin) + + boolean enableDevelocityIntegration = providers.gradleProperty( + "com.gradleup.shadow.enableDevelocityIntegration" + ).map { it.toBoolean() }.getOrElse(false) + if (enableDevelocityIntegration) { + // Legacy build scan support for Gradle Enterprise, users should migrate to develocity plugin. + rootProject.plugins.withId('com.gradle.enterprise') { + configureBuildScan(rootProject) + } + rootProject.plugins.withId('com.gradle.develocity') { + configureBuildScan(rootProject) + } + } + } + } + + private void configureBuildScan(Project rootProject) { + rootProject.buildScan.buildFinished { + def shadowTasks = tasks.withType(ShadowJar) + shadowTasks.each { task -> + if (task.didWork) { + task.stats.buildScanData.each { k, v -> + rootProject.buildScan.value "shadow.${task.path}.${k}", v.toString() + } + rootProject.buildScan.value "shadow.${task.path}.configurations", task.configurations*.name.join(", ") + } + } } } } From 79dd223ecce09c6c2d83bd4ae62f36e8e229a39f Mon Sep 17 00:00:00 2001 From: Goooler Date: Mon, 3 Feb 2025 02:08:53 +0800 Subject: [PATCH 06/72] Update dependency org.vafer:jdependency to v2.12 (#1222) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> (cherry picked from commit c24a57051cc2e46b68464a766dc0a7e9d3fcd351) --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index b34587e60..48a4a048a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { implementation("org.codehaus.plexus:plexus-utils:4.0.2") implementation("org.codehaus.plexus:plexus-xml:4.0.4") implementation("org.apache.logging.log4j:log4j-core:2.24.1") - implementation("org.vafer:jdependency:2.11") + implementation("org.vafer:jdependency:2.12") testImplementation("org.spockframework:spock-core:2.3-groovy-3.0") { exclude(group = "org.codehaus.groovy") From 360e9dbf41214791de71fb7477c10a6b849d2395 Mon Sep 17 00:00:00 2001 From: Goooler Date: Mon, 3 Feb 2025 02:14:18 +0800 Subject: [PATCH 07/72] Prepare changelog for version 8.3.6 --- src/docs/changes/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index b9be1a5e6..7eb20cbfd 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -4,6 +4,17 @@ ## [Unreleased] +## [v8.3.6] (2025-02-02) + +**Added** + +- Support Java 24. ([#1222](https://github.com/GradleUp/shadow/pull/1222)) + +**Changed** + +- Exclude kotlin-stdlib from plugin dependencies. ([#1093](https://github.com/GradleUp/shadow/pull/1093)) + + ## [v8.3.5] (2024-11-03) **Fixed** @@ -415,7 +426,8 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = " Date: Mon, 3 Feb 2025 02:16:07 +0800 Subject: [PATCH 08/72] Prepare version 8.3.6 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d41ad959d..4d8328d23 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.6-SNAPSHOT +VERSION_NAME=8.3.6 SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=DEFAULT From b6d6107fb93e2cf78b82cd2954cda70243d89c7f Mon Sep 17 00:00:00 2001 From: Goooler Date: Mon, 3 Feb 2025 02:17:31 +0800 Subject: [PATCH 09/72] Prepare next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4d8328d23..9aced36aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.6 +VERSION_NAME=8.3.7-SNAPSHOT SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=DEFAULT From 84467968ad1f71a94d181f120caa5be33d0b3d8c Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 23 Jan 2025 19:42:11 +0800 Subject: [PATCH 10/72] Update RELEASING.md (cherry picked from commit 5247c1ed5cb7e5682c27f6d89bb42da813ca3f76) --- RELEASING.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 8cd3e99a3..0c3a226e9 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -12,28 +12,28 @@ 4. Commit - ``` - $ git commit -am "Prepare version X.Y.Z" + ```sh + git commit -am "Prepare version X.Y.Z" ``` 5. Tag - ``` - $ git tag -am "Version X.Y.Z" X.Y.Z + ```sh + git tag -am "Version X.Y.Z" X.Y.Z ``` 6. Update the `VERSION_NAME` in `gradle.properties` to the next "SNAPSHOT" version. 7. Commit - ``` - $ git commit -am "Prepare next development version" + ```sh + git commit -am "Prepare next development version" ``` 8. Push! - ``` - $ git push && git push --tags + ```sh + git push && git push --tags ``` This will trigger a GitHub Action workflow which will create a GitHub release and upload the From 457d488cf1ef4757e804c7a861968083b868d7b1 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 4 Feb 2025 11:54:08 +0800 Subject: [PATCH 11/72] Don't note PR 1093 for 8.3.6 changes (cherry picked from commit 8cb05300396993749e814d7787249ae738a789b0) --- src/docs/changes/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 7eb20cbfd..057ebe57f 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -10,10 +10,6 @@ - Support Java 24. ([#1222](https://github.com/GradleUp/shadow/pull/1222)) -**Changed** - -- Exclude kotlin-stdlib from plugin dependencies. ([#1093](https://github.com/GradleUp/shadow/pull/1093)) - ## [v8.3.5] (2024-11-03) From ad64e942f7397dc5fa7f00290a6eac698f0e49b6 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Mon, 28 Apr 2025 10:51:46 +0800 Subject: [PATCH 12/72] Migrate credentials for publishing to Maven Central (#1414) https://central.sonatype.org/news/20250326_ossrh_sunset/ (cherry picked from commit bd52a19532787df2379d706e7629524a6440abe4) --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- gradle.properties | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a8c880da..504f245a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,5 +42,5 @@ jobs: # Disable CC due to https://github.com/gradle/gradle/issues/22779 - run: ./gradlew publish --no-configuration-cache env: - ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSSRH_USER }} - ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSSRH_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_PORTAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e2a1b6a10..e58cc9bc2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,8 +33,8 @@ jobs: GRGIT_USER: ${{ github.repository_owner }} # https://ajoberstar.org/grgit/main/grgit-authentication.html#_environment_variables GRGIT_PASS: ${{ secrets.GITHUB_TOKEN }} - ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSSRH_USER }} - ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSSRH_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_PORTAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }} ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_KEY_PASSWORD }} - name: Extract release notes diff --git a/gradle.properties b/gradle.properties index 9aced36aa..59c71b963 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ POM_ARTIFACT_ID=shadow-gradle-plugin VERSION_NAME=8.3.7-SNAPSHOT SONATYPE_AUTOMATIC_RELEASE=true -SONATYPE_HOST=DEFAULT +SONATYPE_HOST=CENTRAL_PORTAL RELEASE_SIGNING_ENABLED=true POM_NAME=Shadow Gradle Plugin From 8689f5bf24c2023257161078ed3a5fccf8131092 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Jun 2025 22:30:17 +0800 Subject: [PATCH 13/72] Update dependency gradle to v8.14.2 (#1459) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> (cherry picked from commit 17dc709496375c23bd5dbbd8f44ce25f4dad8ea1) --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e18bc253b..ff23a68d7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From ec4e2bd52d8ed7920f91a4826824e50f2c2dda66 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Sun, 30 Mar 2025 11:05:21 +0800 Subject: [PATCH 14/72] Back to ffurrer2/extract-release-notes@v2 (#1381) https://github.com/ffurrer2/extract-release-notes/releases/tag/v2.3.0 (cherry picked from commit dccc02d61ce56acb68f9712f460e3569f0db6239) --- .github/workflows/release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e58cc9bc2..fdb704419 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,8 +38,7 @@ jobs: ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }} ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_KEY_PASSWORD }} - name: Extract release notes - # TODO: replace this after https://github.com/ffurrer2/extract-release-notes/pull/355 is merged. - uses: Goooler/extract-release-notes@6e686e7a607d03716b7cff561371a82065b22c33 + uses: ffurrer2/extract-release-notes@v2 with: changelog_file: src/docs/changes/README.md release_notes_file: RELEASE_NOTES.md From 42c4665deb552bcb3a281cc1aeb13d054fd5a1c6 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Wed, 18 Jun 2025 16:52:21 +0800 Subject: [PATCH 15/72] Update RELEASING.md (cherry picked from commit 63ac51019fdc48cf44dfc19e9adcf6e140fda806) --- RELEASING.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 0c3a226e9..d2e3438fc 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -7,30 +7,27 @@ 2. Add a link URL to ensure the header link works. 3. Add a new `Unreleased` section to the top. -3. Update the `README.md` so the "Download" section reflects the new release version and the - snapshot section reflects the next "SNAPSHOT" version. - -4. Commit +3. Commit ```sh git commit -am "Prepare version X.Y.Z" ``` -5. Tag +4. Tag ```sh git tag -am "Version X.Y.Z" X.Y.Z ``` -6. Update the `VERSION_NAME` in `gradle.properties` to the next "SNAPSHOT" version. +5. Update the `VERSION_NAME` in `gradle.properties` to the next "SNAPSHOT" version. -7. Commit +6. Commit ```sh git commit -am "Prepare next development version" ``` -8. Push! +7. Push! ```sh git push && git push --tags From 1332a9900a189e7a047df964559f450199789270 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 19 Jun 2025 09:50:00 +0800 Subject: [PATCH 16/72] Update dependencies and remove deploy convention plugin --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 10 +---- build-logic/build.gradle.kts | 6 +-- .../shadow.convention.deploy.gradle.kts | 37 ------------------- build.gradle.kts | 22 ++++------- settings.gradle.kts | 2 +- 6 files changed, 12 insertions(+), 67 deletions(-) delete mode 100644 build-logic/src/main/kotlin/shadow.convention.deploy.gradle.kts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 504f245a4..c5a4d86e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: with: cache-read-only: true # Disable CC due to https://github.com/gradle/gradle/issues/22779 - - run: ./gradlew publish --no-configuration-cache + - run: ./gradlew publishToMavenCentral --no-configuration-cache env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_PORTAL_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fdb704419..8ff8a6a2e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,19 +20,11 @@ jobs: - uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true - - uses: actions/setup-node@v4 - with: - # Due to some limitations of https://github.com/node-gradle/gradle-node-plugin. - node-version: '16' # Disable CC due to https://github.com/gradle/gradle/issues/22779 - - run: ./gradlew release --no-configuration-cache + - run: ./gradlew publishToMavenCentral publishPlugins --no-configuration-cache env: GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_KEY }} GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_SECRET }} - # We must declare repository_owner as the user, workaround for https://github.com/ajoberstar/gradle-git-publish/issues/109. - GRGIT_USER: ${{ github.repository_owner }} - # https://ajoberstar.org/grgit/main/grgit-authentication.html#_environment_variables - GRGIT_PASS: ${{ secrets.GITHUB_TOKEN }} ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_PORTAL_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }} diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 1622a3797..c83900b4e 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -8,8 +8,6 @@ repositories { } dependencies { - implementation("com.gradle.publish:plugin-publish-plugin:1.3.0") - implementation("com.vanniktech:gradle-maven-publish-plugin:0.30.0") - implementation("org.ajoberstar.git-publish:gradle-git-publish:4.2.2") - implementation("com.github.node-gradle:gradle-node-plugin:7.1.0") + implementation("com.gradle.publish:plugin-publish-plugin:1.3.1") + implementation("com.vanniktech:gradle-maven-publish-plugin:0.32.0") } diff --git a/build-logic/src/main/kotlin/shadow.convention.deploy.gradle.kts b/build-logic/src/main/kotlin/shadow.convention.deploy.gradle.kts deleted file mode 100644 index 98c7b1ebe..000000000 --- a/build-logic/src/main/kotlin/shadow.convention.deploy.gradle.kts +++ /dev/null @@ -1,37 +0,0 @@ -import org.apache.tools.ant.filters.ReplaceTokens - -plugins { - id("org.ajoberstar.git-publish") - id("com.github.node-gradle.node") -} - -gitPublish { - repoUri = "https://github.com/GradleUp/shadow.git" - branch = "gh-pages" - contents { - from("build/site") - into("api") { - from(tasks.named("groovydoc")) - } - filter( - "tokens" to mapOf( - "version" to version, - "snapshot-version" to "$version-SNAPSHOT", - ), - ) - } -} - -node { - yarnVersion = "1.5.1" -} - -val yarnBuild = tasks.named("yarn_build") { - inputs.files(fileTree("src/docs")) - outputs.dir(file("build/site")) - dependsOn(tasks.yarn) -} - -tasks.gitPublishCopy { - dependsOn(yarnBuild, tasks.named("groovydoc")) -} diff --git a/build.gradle.kts b/build.gradle.kts index 48a4a048a..78d65f99a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,8 +2,7 @@ plugins { groovy `java-gradle-plugin` id("shadow.convention.publish") - id("shadow.convention.deploy") - id("com.diffplug.spotless") version "7.0.0.BETA4" + id("com.diffplug.spotless") version "7.0.4" } java { @@ -23,22 +22,22 @@ dependencies { compileOnly(localGroovy()) implementation("org.jdom:jdom2:2.0.6.1") - implementation("org.ow2.asm:asm-commons:9.7.1") - implementation("commons-io:commons-io:2.17.0") + implementation("org.ow2.asm:asm-commons:9.8") + implementation("commons-io:commons-io:2.19.0") implementation("org.apache.ant:ant:1.10.15") implementation("org.codehaus.plexus:plexus-utils:4.0.2") - implementation("org.codehaus.plexus:plexus-xml:4.0.4") + implementation("org.codehaus.plexus:plexus-xml:4.1.0") implementation("org.apache.logging.log4j:log4j-core:2.24.1") - implementation("org.vafer:jdependency:2.12") + implementation("org.vafer:jdependency:2.13") testImplementation("org.spockframework:spock-core:2.3-groovy-3.0") { exclude(group = "org.codehaus.groovy") exclude(group = "org.hamcrest") } - testImplementation("org.xmlunit:xmlunit-legacy:2.10.0") + testImplementation("org.xmlunit:xmlunit-legacy:2.10.2") testImplementation("org.apache.commons:commons-lang3:3.17.0") testImplementation("com.google.guava:guava:33.3.1-jre") - testImplementation(platform("org.junit:junit-bom:5.11.3")) + testImplementation(platform("org.junit:junit-bom:5.13.1")) testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.junit.platform:junit-platform-suite-engine") } @@ -71,10 +70,3 @@ tasks.withType().configureEach { "java.base/java.net=ALL-UNNAMED", ) } - -tasks.register("release") { - dependsOn( - tasks.publish, - tasks.publishPlugins, - ) -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 87569ed1f..dd59c00eb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,7 +8,7 @@ pluginManagement { } plugins { - id("com.gradle.develocity") version "3.18.2" + id("com.gradle.develocity") version "4.0.2" } develocity { From 3df0ea51607ea105a962a1a2886bf29c8f7c6f2d Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 19 Jun 2025 21:19:18 +0800 Subject: [PATCH 17/72] Revert "Run CI for 8.x branch" This reverts commit 12328c9b138afe9dff03b07e6825495b795b04cb. --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5a4d86e0..52751c37d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,10 +3,8 @@ name: CI on: push: branches: - - 8.x + - main pull_request: - branches: - - 8.x workflow_dispatch: jobs: @@ -29,7 +27,7 @@ jobs: publish-snapshot: needs: build runs-on: ubuntu-latest - if: github.repository == 'GradleUp/shadow' && github.ref == 'refs/heads/8.x' + if: github.repository == 'GradleUp/shadow' && github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 From 85a06460d0890f8048958ea02082b7e6c6e2d3cf Mon Sep 17 00:00:00 2001 From: Goooler Date: Fri, 20 Jun 2025 16:51:06 +0800 Subject: [PATCH 18/72] Eliminate convention plugin --- build-logic/build.gradle.kts | 13 ---- build-logic/gradle.properties | 1 - .../shadow.convention.publish.gradle.kts | 78 ------------------- build.gradle.kts | 70 ++++++++++++++++- settings.gradle.kts | 2 - 5 files changed, 67 insertions(+), 97 deletions(-) delete mode 100644 build-logic/build.gradle.kts delete mode 100644 build-logic/gradle.properties delete mode 100644 build-logic/src/main/kotlin/shadow.convention.publish.gradle.kts diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts deleted file mode 100644 index c83900b4e..000000000 --- a/build-logic/build.gradle.kts +++ /dev/null @@ -1,13 +0,0 @@ -plugins { - `kotlin-dsl` -} - -repositories { - mavenCentral() - gradlePluginPortal() -} - -dependencies { - implementation("com.gradle.publish:plugin-publish-plugin:1.3.1") - implementation("com.vanniktech:gradle-maven-publish-plugin:0.32.0") -} diff --git a/build-logic/gradle.properties b/build-logic/gradle.properties deleted file mode 100644 index 338c1c3fc..000000000 --- a/build-logic/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -org.gradle.kotlin.dsl.allWarningsAsErrors=true diff --git a/build-logic/src/main/kotlin/shadow.convention.publish.gradle.kts b/build-logic/src/main/kotlin/shadow.convention.publish.gradle.kts deleted file mode 100644 index 6282e8c30..000000000 --- a/build-logic/src/main/kotlin/shadow.convention.publish.gradle.kts +++ /dev/null @@ -1,78 +0,0 @@ -plugins { - id("com.gradle.plugin-publish") - id("com.vanniktech.maven.publish") -} - -version = providers.gradleProperty("VERSION_NAME").get() -group = providers.gradleProperty("GROUP").get() -description = providers.gradleProperty("POM_DESCRIPTION").get() - -java { - withSourcesJar() - withJavadocJar() -} - -gradlePlugin { - website = providers.gradleProperty("POM_URL") - vcsUrl = providers.gradleProperty("POM_URL") - - plugins { - create("shadowPlugin") { - id = "com.gradleup.shadow" - implementationClass = "com.github.jengelman.gradle.plugins.shadow.ShadowPlugin" - displayName = providers.gradleProperty("POM_NAME").get() - description = providers.gradleProperty("POM_DESCRIPTION").get() - tags = listOf("onejar", "shade", "fatjar", "uberjar") - } - } -} - -tasks.publishPlugins { - doFirst { - if (version.toString().endsWith("SNAPSHOT")) { - error("Cannot publish SNAPSHOT versions to Plugin Portal!") - } - } - notCompatibleWithConfigurationCache("https://github.com/gradle/gradle/issues/21283") -} - -tasks.withType().configureEach { - (options as? StandardJavadocDocletOptions)?.let { - it.links( - "https://docs.oracle.com/en/java/javase/17/docs/api/", - "https://docs.groovy-lang.org/2.4.7/html/gapi/", - ) - it.addStringOption("Xdoclint:none", "-quiet") - } -} - -configurations { - listOf( - apiElements, - runtimeElements, - named("javadocElements"), - named("sourcesElements"), - ).forEach { - it.configure { - outgoing { - // Main/current capability - capability("com.gradleup.shadow:shadow-gradle-plugin:$version") - - // Historical capabilities - capability("io.github.goooler.shadow:shadow-gradle-plugin:$version") - capability("com.github.johnrengelman:shadow:$version") - capability("gradle.plugin.com.github.jengelman.gradle.plugins:shadow:$version") - capability("gradle.plugin.com.github.johnrengelman:shadow:$version") - capability("com.github.jengelman.gradle.plugins:shadow:$version") - } - } - } -} - -publishing.publications.withType().configureEach { - // We don't care about capabilities being unmappable to Maven - suppressPomMetadataWarningsFor("apiElements") - suppressPomMetadataWarningsFor("runtimeElements") - suppressPomMetadataWarningsFor("javadocElements") - suppressPomMetadataWarningsFor("sourcesElements") -} diff --git a/build.gradle.kts b/build.gradle.kts index 78d65f99a..535838950 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,13 +1,39 @@ +import org.gradle.api.plugins.JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME +import org.gradle.api.plugins.JavaPlugin.JAVADOC_ELEMENTS_CONFIGURATION_NAME +import org.gradle.api.plugins.JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME +import org.gradle.api.plugins.JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME + plugins { groovy `java-gradle-plugin` - id("shadow.convention.publish") + id("com.vanniktech.maven.publish") version "0.32.0" id("com.diffplug.spotless") version "7.0.4" } +version = providers.gradleProperty("VERSION_NAME").get() +group = providers.gradleProperty("GROUP").get() +description = providers.gradleProperty("POM_DESCRIPTION").get() + java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 + withSourcesJar() + withJavadocJar() +} + +gradlePlugin { + website = providers.gradleProperty("POM_URL") + vcsUrl = providers.gradleProperty("POM_URL") + + plugins { + create("shadowPlugin") { + id = "com.gradleup.shadow" + implementationClass = "com.github.jengelman.gradle.plugins.shadow.ShadowPlugin" + displayName = providers.gradleProperty("POM_NAME").get() + description = providers.gradleProperty("POM_DESCRIPTION").get() + tags = listOf("onejar", "shade", "fatjar", "uberjar") + } + } } spotless { @@ -18,9 +44,37 @@ spotless { } } -dependencies { - compileOnly(localGroovy()) +configurations.configureEach { + when (name) { + API_ELEMENTS_CONFIGURATION_NAME, + RUNTIME_ELEMENTS_CONFIGURATION_NAME, + JAVADOC_ELEMENTS_CONFIGURATION_NAME, + SOURCES_ELEMENTS_CONFIGURATION_NAME, + -> { + outgoing { + // Main/current capability. + capability("com.gradleup.shadow:shadow-gradle-plugin:$version") + + // Historical capabilities. + capability("io.github.goooler.shadow:shadow-gradle-plugin:$version") + capability("com.github.johnrengelman:shadow:$version") + capability("gradle.plugin.com.github.jengelman.gradle.plugins:shadow:$version") + capability("gradle.plugin.com.github.johnrengelman:shadow:$version") + capability("com.github.jengelman.gradle.plugins:shadow:$version") + } + } + } +} + +publishing.publications.withType().configureEach { + // We don't care about capabilities being unmappable to Maven. + suppressPomMetadataWarningsFor(API_ELEMENTS_CONFIGURATION_NAME) + suppressPomMetadataWarningsFor(RUNTIME_ELEMENTS_CONFIGURATION_NAME) + suppressPomMetadataWarningsFor(JAVADOC_ELEMENTS_CONFIGURATION_NAME) + suppressPomMetadataWarningsFor(SOURCES_ELEMENTS_CONFIGURATION_NAME) +} +dependencies { implementation("org.jdom:jdom2:2.0.6.1") implementation("org.ow2.asm:asm-commons:9.8") implementation("commons-io:commons-io:2.19.0") @@ -42,6 +96,16 @@ dependencies { testImplementation("org.junit.platform:junit-platform-suite-engine") } +tasks.withType().configureEach { + (options as? StandardJavadocDocletOptions)?.let { + it.links( + "https://docs.oracle.com/en/java/javase/17/docs/api/", + "https://docs.groovy-lang.org/2.4.7/html/gapi/", + ) + it.addStringOption("Xdoclint:none", "-quiet") + } +} + val isCI = providers.environmentVariable("CI").isPresent tasks.withType().configureEach { diff --git a/settings.gradle.kts b/settings.gradle.kts index dd59c00eb..7583111ca 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,8 +3,6 @@ pluginManagement { mavenCentral() gradlePluginPortal() } - - includeBuild("build-logic") } plugins { From a0da04a75c706ee4c5cd4bfa59eece8c96d1cf17 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 24 Jun 2025 09:18:17 +0800 Subject: [PATCH 19/72] Make Shadow 8 be compatible with Gradle 9 (#1470) * Bump https://docs.gradle.org/9.0.0-rc-1/release-notes.html * Mark `ShadowJar` as abstract * Remove Java 11 and add Java 24 into test matrix * Replace `SelfResolvingDependency` with `FileCollectionDependency` * Remove `ShadowCopyAction.ArchiveFileTreeElement.getMode` * Mark `JavaJarExec` as abstract * org.spockframework:spock-core:2.3-groovy-4.0 * Remove static for `TransformerTestSupport.transformer` * Replace `org.gradle.api.UncheckedIOException` * Compat `dependencyProject` * Replace `mainClassName` with `mainClass` for `CreateStartScripts` * Compat `RelativeArchivePath.getParent` for Groovy 3 and 4 * Annotate `RelocatorRemapper` with `CompileStatic` * Update changelog * Revert "Remove `ShadowCopyAction.ArchiveFileTreeElement.getMode`" This reverts commit 5b9a54fa2522cd92c92294c751f216306b7c5a46. * Remove `@Override` for `getMode` * Add Gradle 8.3 into test matrix * Compat `RelocationUtil#configureRelocation` for Groovy 3 and 4 * Log info --- .github/workflows/ci.yml | 12 ++++++++--- build.gradle.kts | 8 +++++++- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 45457 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 8 ++++---- gradlew.bat | 4 ++-- src/docs/changes/README.md | 4 ++++ .../shadow/ShadowApplicationPlugin.groovy | 2 +- .../shadow/impl/RelocatorRemapper.groovy | 2 ++ .../internal/DefaultZipCompressor.groovy | 1 - .../shadow/internal/JavaJarExec.groovy | 2 +- .../shadow/internal/RelocationUtil.groovy | 5 ++++- .../shadow/internal/UnusedTracker.groovy | 19 ++++++++++++++---- .../shadow/tasks/ShadowCopyAction.groovy | 7 ++++--- .../plugins/shadow/tasks/ShadowJar.java | 2 +- .../docs/executer/GradleBuildExecuter.groovy | 6 +++++- ...ceResourceTransformerParameterTests.groovy | 2 +- .../TransformerTestSupport.groovy | 2 +- .../gradle/plugins/shadow/util/HashUtil.java | 2 +- .../shadow/util/PluginSpecification.groovy | 3 +++ 20 files changed, 66 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52751c37d..09a95beb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,14 @@ jobs: strategy: matrix: os: [ ubuntu-latest, windows-latest ] - # Always test on the latest version and all LTS. - java: [ 11, 17, 21, 23 ] + # Always test on the latest version and some LTS. + java: [ 17, 21, 24 ] + # Test on the minimum Gradle version and the latest. + gradle: [ 8.3, current ] + exclude: + # Gradle 8.3 doesn't support Java 24. + - gradle: 8.3 + java: 24 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -22,7 +28,7 @@ jobs: distribution: 'zulu' java-version: ${{ matrix.java }} - uses: gradle/actions/setup-gradle@v4 - - run: ./gradlew build + - run: ./gradlew build --info "-PtestGradleVersion=${{ matrix.gradle }}" publish-snapshot: needs: build diff --git a/build.gradle.kts b/build.gradle.kts index 535838950..cf83f8152 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -84,7 +84,7 @@ dependencies { implementation("org.apache.logging.log4j:log4j-core:2.24.1") implementation("org.vafer:jdependency:2.13") - testImplementation("org.spockframework:spock-core:2.3-groovy-3.0") { + testImplementation("org.spockframework:spock-core:2.3-groovy-4.0") { exclude(group = "org.codehaus.groovy") exclude(group = "org.hamcrest") } @@ -111,6 +111,12 @@ val isCI = providers.environmentVariable("CI").isPresent tasks.withType().configureEach { useJUnitPlatform() + val testGradleVersion = providers.gradleProperty("testGradleVersion").orNull.let { + if (it == null || it == "current") GradleVersion.current().version else it + } + logger.info("Using test Gradle version: $testGradleVersion") + systemProperty("TEST_GRADLE_VERSION", testGradleVersion) + maxParallelForks = Runtime.getRuntime().availableProcessors() if (isCI) { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..8bdaf60c75ab801e22807dde59e12a8735a34077 100644 GIT binary patch delta 37330 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68d7..407c905d9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-rc-1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f3b75f3b0..ef07e0162 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -205,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019c7..5eed7ee84 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 057ebe57f..d3b52123f 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,10 @@ ## [Unreleased] +**Fixed** + +- Fix compatibility for Gradle 9.0.0 RC1. ([#1470](https://github.com/GradleUp/shadow/pull/1470)) + ## [v8.3.6] (2025-02-02) 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 7a57952ae..3da91aab1 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 @@ -84,7 +84,7 @@ class ShadowApplicationPlugin implements Plugin { startScripts.description = 'Creates OS specific scripts to run the project as a JVM application using the shadow jar' startScripts.group = ApplicationPlugin.APPLICATION_GROUP startScripts.classpath = project.files(jar) - startScripts.conventionMapping.mainClassName = { javaApplication.mainClass.get() } + startScripts.mainClass.set(javaApplication.mainClass) startScripts.conventionMapping.applicationName = { javaApplication.applicationName } startScripts.conventionMapping.outputDir = { new File(project.layout.buildDirectory.asFile.get(), 'scriptsShadow') } startScripts.conventionMapping.defaultJvmOpts = { javaApplication.applicationDefaultJvmArgs } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy index 5e23269e4..31fafab21 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy @@ -24,6 +24,7 @@ import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContex import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowCopyAction.RelativeArchivePath +import groovy.transform.CompileStatic import org.objectweb.asm.commons.Remapper import java.util.regex.Matcher @@ -34,6 +35,7 @@ import java.util.regex.Pattern * * @author John Engelman */ +@CompileStatic class RelocatorRemapper extends Remapper { private final Pattern classPattern = Pattern.compile("(\\[*)?L(.+)") diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy index a2248e6a2..829ab294c 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy @@ -17,7 +17,6 @@ package com.github.jengelman.gradle.plugins.shadow.internal import org.apache.tools.zip.Zip64Mode import org.apache.tools.zip.ZipOutputStream -import org.gradle.api.UncheckedIOException class DefaultZipCompressor implements ZipCompressor { private final int entryCompressionMethod diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy index 2affa9fbe..28ed02308 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy @@ -4,7 +4,7 @@ import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.TaskAction -class JavaJarExec extends JavaExec { +abstract class JavaJarExec extends JavaExec { @InputFile File jarFile diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy index f94ab89ed..f3d55385b 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy @@ -12,7 +12,10 @@ class RelocationUtil { JarFile jf = new JarFile(jar) jf.entries().each { entry -> if (entry.name.endsWith(".class") && entry.name != "module-info.class") { - packages << entry.name[0..entry.name.lastIndexOf('/') - 1].replaceAll('/', '.') + def i = entry.name.lastIndexOf('/') + if (i != -1) { + packages << entry.name.take(i).replaceAll('/', '.') + } } } jf.close() diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy index fcfbe6ea1..5ff88aec2 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy @@ -3,10 +3,11 @@ package com.github.jengelman.gradle.plugins.shadow.internal import org.gradle.api.Project import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.FileCollectionDependency import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.artifacts.SelfResolvingDependency import org.gradle.api.file.FileCollection import org.gradle.api.tasks.InputFiles +import org.gradle.util.GradleVersion import org.vafer.jdependency.Clazz import org.vafer.jdependency.Clazzpath import org.vafer.jdependency.ClazzpathUnit @@ -70,10 +71,10 @@ class UnusedTracker { def apiJars = new LinkedList() apiDependencies.each { dep -> if (dep instanceof ProjectDependency) { - apiJars.addAll(getApiJarsFromProject(dep.dependencyProject)) + apiJars.addAll(getApiJarsFromProject(dependencyProjectCompat(dep, project))) addJar(runtimeConfiguration, dep, apiJars) - } else if (dep instanceof SelfResolvingDependency) { - apiJars.addAll(dep.resolve()) + } else if (dep instanceof FileCollectionDependency) { + apiJars.addAll(dep.files) } else { addJar(runtimeConfiguration, dep, apiJars) apiJars.add(runtimeConfiguration.find { it.name.startsWith("${dep.name}-") } as File) @@ -82,4 +83,14 @@ class UnusedTracker { return project.files(apiJars) } + + /** + * TODO: this could be removed after bumping the min Gradle requirement to 8.11 or above. + */ + private static dependencyProjectCompat(ProjectDependency projectDependency, Project project) { + if (GradleVersion.current() >= GradleVersion.version("8.11")) { + return project.project(projectDependency.path) + } + return projectDependency.dependencyProject + } } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy index 128dc3cce..3fb9eaef4 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy @@ -17,7 +17,6 @@ import org.apache.tools.zip.ZipFile import org.apache.tools.zip.ZipOutputStream import org.gradle.api.Action import org.gradle.api.GradleException -import org.gradle.api.UncheckedIOException import org.gradle.api.file.FileCopyDetails import org.gradle.api.file.FilePermissions import org.gradle.api.file.FileTreeElement @@ -460,7 +459,7 @@ class ShadowCopyAction implements CopyAction { return null } else { //Parent is always a directory so add / to the end of the path - String path = segments[0..-2].join('/') + '/' + String path = segments.take(segments.length - 1).join('/') + '/' return new RelativeArchivePath(setArchiveTimes(new ZipEntry(path))) } } @@ -528,7 +527,9 @@ class ShadowCopyAction implements CopyAction { return archivePath } - @Override + /** + * This method should be annotated with @Override, but the parent has been removed from Gradle 9. + */ int getMode() { return archivePath.entry.unixMode } 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 dc4cfe9e3..ab45dbee9 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 @@ -25,7 +25,7 @@ import java.util.concurrent.Callable; @CacheableTask -public class ShadowJar extends Jar implements ShadowSpec { +public abstract class ShadowJar extends Jar implements ShadowSpec { private List transformers; private List relocators; diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy index 5e5bfd63e..579e7dc5f 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy @@ -54,7 +54,11 @@ include 'api', 'main' buildFile.text = replaceTokens(fullSnippet) - GradleRunner runner = GradleRunner.create().withProjectDir(tempDir).withPluginClasspath().forwardOutput() + GradleRunner runner = GradleRunner.create() + .withGradleVersion(PluginSpecification.TEST_GRADLE_VERSION) + .withProjectDir(tempDir) + .withPluginClasspath() + .forwardOutput() runner.withArguments(":main:build", "-m").build() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy index 7f93dca88..dce305c9d 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy @@ -77,7 +77,7 @@ class ApacheNoticeResourceTransformerParameterTests extends TransformerTestSuppo processAndFailOnNullPointer("\n") } - private static void processAndFailOnNullPointer(final String noticeText) { + private void processAndFailOnNullPointer(final String noticeText) { try { final ByteArrayInputStream noticeInputStream = new ByteArrayInputStream(noticeText.getBytes()) final List emptyList = Collections.emptyList() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerTestSupport.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerTestSupport.groovy index dda89681d..15b67798f 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerTestSupport.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerTestSupport.groovy @@ -5,7 +5,7 @@ import org.gradle.api.file.RelativePath import org.gradle.api.internal.file.DefaultFileTreeElement abstract class TransformerTestSupport { - protected static T transformer + protected T transformer protected static FileTreeElement getFileElement(String path) { return new DefaultFileTreeElement(null, RelativePath.parse(true, path), null, null) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/HashUtil.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/HashUtil.java index c3c41596d..0df14fa09 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/HashUtil.java +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/HashUtil.java @@ -1,6 +1,5 @@ package com.github.jengelman.gradle.plugins.shadow.util; -import org.gradle.api.UncheckedIOException; import org.gradle.internal.UncheckedException; import java.io.ByteArrayInputStream; import java.io.File; @@ -8,6 +7,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index 04514ec69..aa7d6967c 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -18,6 +18,8 @@ abstract class PluginSpecification extends Specification { public static final String SHADOW_VERSION = System.getProperty("shadowVersion") + public static final String TEST_GRADLE_VERSION = System.getProperty("TEST_GRADLE_VERSION") + AppendableMavenFileRepository repo def setup() { @@ -55,6 +57,7 @@ abstract class PluginSpecification extends Specification { GradleRunner getRunner() { GradleRunner.create() + .withGradleVersion(TEST_GRADLE_VERSION) .withProjectDir(dir.toFile()) .forwardOutput() .withPluginClasspath() From badabadc2b6c8de66178426974808a1cf12f01f5 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 24 Jun 2025 09:21:05 +0800 Subject: [PATCH 20/72] Prepare version 8.3.7 --- build.gradle.kts | 1 + gradle.properties | 2 +- src/docs/changes/README.md | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index cf83f8152..54a0ed8cb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,6 +6,7 @@ import org.gradle.api.plugins.JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME plugins { groovy `java-gradle-plugin` + id("com.gradle.plugin-publish") version "1.3.1" id("com.vanniktech.maven.publish") version "0.32.0" id("com.diffplug.spotless") version "7.0.4" } diff --git a/gradle.properties b/gradle.properties index 59c71b963..155b89885 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.7-SNAPSHOT +VERSION_NAME=8.3.7 SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=CENTRAL_PORTAL diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index d3b52123f..b86b3306f 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,9 @@ ## [Unreleased] + +## [v8.3.7] (2025-06-24) + **Fixed** - Fix compatibility for Gradle 9.0.0 RC1. ([#1470](https://github.com/GradleUp/shadow/pull/1470)) @@ -426,7 +429,8 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = " Date: Tue, 24 Jun 2025 09:21:42 +0800 Subject: [PATCH 21/72] Prepare next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 155b89885..45250ed2f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.7 +VERSION_NAME=8.3.8-SNAPSHOT SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=CENTRAL_PORTAL From e3876a3552e03341588b47a5b11549de8bcb39d6 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 24 Jun 2025 10:02:27 +0800 Subject: [PATCH 22/72] Update changelog --- src/docs/changes/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index b86b3306f..e0b99255e 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -6,6 +6,9 @@ ## [v8.3.7] (2025-06-24) +> [!WARNING] +> Only Gradle 9 support is being backported to this version. No additional features or crucial bug fixes will be included in the 8.x line. Please migrate to Shadow 9 as soon as possible. + **Fixed** - Fix compatibility for Gradle 9.0.0 RC1. ([#1470](https://github.com/GradleUp/shadow/pull/1470)) @@ -429,7 +432,7 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = " Date: Tue, 24 Jun 2025 10:03:32 +0800 Subject: [PATCH 23/72] Update README.md --- README.md | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b9c94e745..0c4475b66 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,42 @@ -# Gradle Shadow +# Shadow Gradle plugin for creating fat/uber JARs with support for package relocation. > [!NOTE]\ -> Previously this plugin was developed by [@johnrengelman](https://github.com/johnrengelman) and published under the ID [`com.github.johnrengelman.shadow`](https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow) -> before maintenance was transferred to the [GradleUp organization](https://github.com/GradleUp) to ensure future development, see [#908](https://github.com/GradleUp/shadow/issues/908). +> Previously this plugin was developed by [@johnrengelman](https://github.com/johnrengelman) and published under the +> ID [`com.github.johnrengelman.shadow`][johnrengelman's] +> before maintenance was transferred to the [GradleUp organization](https://github.com/GradleUp) to ensure future +> development, see [#908](https://github.com/GradleUp/shadow/issues/908). > -> If you are still using the old plugin ID in your build script, we recommend to switch to the new plugin ID [`com.gradleup.shadow`](https://plugins.gradle.org/plugin/com.gradleup.shadow) +> If you are still using the old plugin ID in your build script, we recommend to switch to the new plugin ID [ +`com.gradleup.shadow`][gradleup's] > and update to the latest version to receive all the latest bug fixes and improvements. ## Documentation -Read the [User Guide](https://gradleup.com/shadow/)! +- [User Guide](https://gradleup.com/shadow/) +- [Change Log](src/docs/changes/README.md) ## Current Status [![Maven Central](https://img.shields.io/maven-central/v/com.gradleup.shadow/shadow-gradle-plugin)](https://central.sonatype.com/artifact/com.gradleup.shadow/shadow-gradle-plugin) [![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/com.gradleup.shadow/shadow-gradle-plugin?&server=https://oss.sonatype.org/)](https://oss.sonatype.org/content/repositories/snapshots/com/gradleup/shadow/) [![Plugin Portal](https://img.shields.io/gradle-plugin-portal/v/com.gradleup.shadow)](https://plugins.gradle.org/plugin/com.gradleup.shadow) -[![CI](https://github.com/GradleUp/shadow/actions/workflows/ci.yml/badge.svg?branch=main&event=push)](https://github.com/GradleUp/shadow/actions/workflows/ci.yml?query=branch:main+event:push) +[![CI](https://github.com/GradleUp/shadow/actions/workflows/build.yml/badge.svg?branch=main&event=push)](https://github.com/GradleUp/shadow/actions/workflows/build.yml?query=branch:main+event:push) [![License](https://img.shields.io/github/license/GradleUp/shadow.svg)](LICENSE) -## Latest Test Compatibility +## Compatibility Matrix -| Gradle Version | Shadow Version | -|----------------|----------------| -| 5.x | 5.2.0 - 6.0.0 | -| 6.x | 5.2.0 - 6.1.0 | -| 7.x | 7.0.0+ | -| 8.0 - 8.2.x | 8.0.0 - 8.1.1 | -| 8.3+ | 8.3.0+ | +| Shadow Version | Min Gradle Version | Min Java Version | Plugin ID | +|----------------|--------------------|------------------|------------------------------------------------------| +| 5.2.0 - 6.1.0 | 5.x - 6.x | 7 | [`com.github.johnrengelman.shadow`][johnrengelman's] | +| 6.1.0+ | 6.x | 8 | [`com.github.johnrengelman.shadow`][johnrengelman's] | +| 7.0.0+ | 7.x | 8 | [`com.github.johnrengelman.shadow`][johnrengelman's] | +| 8.0.0+ | 8.0 | 8 | [`com.github.johnrengelman.shadow`][johnrengelman's] | +| 8.3.0+ | 8.3 | 8 | [`com.gradleup.shadow`][gradleup's] | +| 9.0.0+ | 8.3 | 11 | [`com.gradleup.shadow`][gradleup's] | -**NOTE**: Shadow v5.+ is compatible with Gradle 5.x - 6.x and Java 7 - 15 _only_, v6.1.0+ requires Java 8+. + + +[johnrengelman's]: https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow +[gradleup's]: https://plugins.gradle.org/plugin/com.gradleup.shadow From c0512b1d815f9ebf3076ab613bcd222118afac41 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Thu, 26 Jun 2025 16:06:17 +0800 Subject: [PATCH 24/72] Expose Ant as compile scope (#1488) (cherry picked from commit 8eeb64e969ce68ba82d864602cc2d120898866bd) --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 54a0ed8cb..2b0380c73 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -76,10 +76,10 @@ publishing.publications.withType().configureEach { } dependencies { + api("org.apache.ant:ant:1.10.15") // Types from Ant are exposed in the public API. implementation("org.jdom:jdom2:2.0.6.1") implementation("org.ow2.asm:asm-commons:9.8") implementation("commons-io:commons-io:2.19.0") - implementation("org.apache.ant:ant:1.10.15") implementation("org.codehaus.plexus:plexus-utils:4.0.2") implementation("org.codehaus.plexus:plexus-xml:4.1.0") implementation("org.apache.logging.log4j:log4j-core:2.24.1") From 0b5d946de6496885b77958edb1433d4e72ba8dd3 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 26 Jun 2025 16:14:09 +0800 Subject: [PATCH 25/72] Update changelog --- src/docs/changes/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index e0b99255e..3c0dcabd4 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,10 @@ ## [Unreleased] +**Changed** + +- Expose Ant as `compile` scope. ([#1488](https://github.com/GradleUp/shadow/pull/1488)) + ## [v8.3.7] (2025-06-24) From 00df3c966e2ac1fa4cc73d077290dae4dc1aa572 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 1 Jul 2025 18:44:47 +0800 Subject: [PATCH 26/72] Update workflow trigger and names --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09a95beb4..d6b210bb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,12 +3,13 @@ name: CI on: push: branches: - - main + - 8.x pull_request: workflow_dispatch: jobs: build: + name: OS=${{ matrix.os }}, Java=${{ matrix.java }}, Gradle=${{ matrix.gradle }} strategy: matrix: os: [ ubuntu-latest, windows-latest ] From d59d947f73dbb6c4486da691b8ec897b496de979 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 1 Jul 2025 21:10:36 +0800 Subject: [PATCH 27/72] Fix the regression of `PropertiesFileTransformer` in `8.3.7` (#1493) Defaults `PropertiesFileTransformer.keyTransformer` to a copy of `Closure.IDENTITY`. We can't use `Closure.IDENTITY` instead, as it is not compatible with Groovy 3 and 4. --- .github/workflows/ci.yml | 2 + src/docs/changes/README.md | 4 + .../shadow/internal/CleanProperties.groovy | 3 + .../PropertiesFileTransformer.groovy | 7 +- .../PropertiesFileTransformerSpec.groovy | 212 ++++++++++++++++++ .../plugins/shadow/ShadowPluginSpec.groovy | 8 +- .../plugins/shadow/TransformerSpec.groovy | 33 ++- .../shadow/caching/AbstractCachingSpec.groovy | 4 - .../shadow/util/PluginSpecification.groovy | 4 + 9 files changed, 247 insertions(+), 30 deletions(-) create mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6b210bb6..13088e37d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,8 @@ on: branches: - 8.x pull_request: + branches: + - 8.x workflow_dispatch: jobs: diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 3c0dcabd4..398928e25 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,10 @@ ## [Unreleased] +**Fixed** + +- Fix the regression of `PropertiesFileTransformer` in `8.3.7`. ([#1493](https://github.com/GradleUp/shadow/pull/1493)) + **Changed** - Expose Ant as `compile` scope. ([#1488](https://github.com/GradleUp/shadow/pull/1488)) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy index b54b5271b..689bac593 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy @@ -1,5 +1,8 @@ package com.github.jengelman.gradle.plugins.shadow.internal +import groovy.transform.CompileStatic + +@CompileStatic class CleanProperties extends Properties { private static class StripCommentsWithTimestampBufferedWriter extends BufferedWriter { diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy index 044e3dbaa..dde1869ec 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy @@ -136,7 +136,9 @@ class PropertiesFileTransformer implements Transformer { String charset = 'ISO_8859_1' @Internal - Closure keyTransformer = IDENTITY + Closure keyTransformer = new Closure("") { + String doCall(Object arguments) { arguments } // We can't use Closure#IDENTITY instead, as it is not compatible with Groovy 3 and 4. + } @Override boolean canTransformResource(FileTreeElement element) { @@ -192,6 +194,9 @@ class PropertiesFileTransformer implements Transformer { } private Properties transformKeys(Properties properties) { + if (keyTransformer == null) { + throw new IllegalStateException("keyTransformer must not be null.") + } if (keyTransformer == IDENTITY) { return properties } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy new file mode 100644 index 000000000..34ace1f52 --- /dev/null +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy @@ -0,0 +1,212 @@ +package com.github.jengelman.gradle.plugins.shadow + +import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer +import com.github.jengelman.gradle.plugins.shadow.util.PluginSpecification +import spock.lang.Issue +import spock.lang.Unroll + +class PropertiesFileTransformerSpec extends PluginSpecification { + + @Unroll + def 'merge properties with different strategies: #mergeStrategy'() { + given: + File one = buildJar('one.jar') + .insertFile('test.properties', + 'key1=one\nkey2=one').write() + + File two = buildJar('two.jar') + .insertFile('test.properties', + 'key2=two\nkey3=two').write() + + buildFile << """ + import ${PropertiesFileTransformer.name} + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + from('${escapedPath(one)}') + from('${escapedPath(two)}') + } + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + transform(PropertiesFileTransformer) { + paths = ['test.properties'] + mergeSeparator = ";" + mergeStrategy = '${mergeStrategy}' + } + } + """.stripIndent() + + when: + run('shadowJar') + + then: + assert output.exists() + + and: + String text = getJarFileContents(output, 'test.properties') + def lines = text.replace('#', '').trim().split("\\r?\\n").toList() + assert lines.size() == 3 + switch (mergeStrategy) { + case 'first': + assert lines.containsAll(['key1=one', 'key2=one', 'key3=two']) + break + case 'latest': + assert lines.containsAll(['key1=one', 'key2=two', 'key3=two']) + break + case 'append': + assert lines.containsAll(['key1=one', 'key2=one;two', 'key3=two']) + break + default: + assert false: "Unknown mergeStrategy: $mergeStrategy" + } + + where: + mergeStrategy << ['first', 'latest', 'append'] + } + + def 'merge properties with key transformer'() { + given: + File one = buildJar('one.jar') + .insertFile('META-INF/test.properties', 'foo=bar') + .write() + + File two = buildJar('two.jar') + .insertFile('META-INF/test.properties', 'FOO=baz') + .write() + + buildFile << """ + import ${PropertiesFileTransformer.name} + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + from('${escapedPath(one)}') + from('${escapedPath(two)}') + } + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + transform(PropertiesFileTransformer) { + paths = ['META-INF/test.properties'] + mergeStrategy = 'append' + keyTransformer = { key -> key.toUpperCase() } + } + } + """.stripIndent() + + when: + run('shadowJar') + + then: + output.exists() + String text = getJarFileContents(output, 'META-INF/test.properties') + text.contains('FOO=bar,baz') + } + + def 'merge properties with specified charset'() { + given: + File one = buildJar('one.jar') + .insertFile('META-INF/utf8.properties', 'foo=第一') + .write() + + File two = buildJar('two.jar') + .insertFile('META-INF/utf8.properties', 'foo=第二') + .write() + + buildFile << """ + import ${PropertiesFileTransformer.name} + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + from('${escapedPath(one)}') + from('${escapedPath(two)}') + } + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + transform(PropertiesFileTransformer) { + paths = ['META-INF/utf8.properties'] + mergeStrategy = 'append' + charset = 'UTF-8' + } + } + """.stripIndent() + + when: + run('shadowJar') + + then: + output.exists() + String text = getJarFileContents(output, 'META-INF/utf8.properties') + text.contains('foo=第一,第二') + } + + def 'merge properties with mappings'() { + given: + File one = buildJar('one.jar') + .insertFile('META-INF/foo.properties', 'foo=1') + .insertFile('META-INF/bar.properties', 'bar=2') + .write() + + File two = buildJar('two.jar') + .insertFile('META-INF/foo.properties', 'foo=3') + .insertFile('META-INF/bar.properties', 'bar=4') + .write() + + buildFile << """ + import ${PropertiesFileTransformer.name} + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + from('${escapedPath(one)}') + from('${escapedPath(two)}') + } + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + transform(PropertiesFileTransformer) { + mappings = [ + 'META-INF/foo.properties': [mergeStrategy: 'append', mergeSeparator: ';'], + 'META-INF/bar.properties': [mergeStrategy: 'latest'] + ] + } + } + """.stripIndent() + + when: + run('shadowJar') + + then: + output.exists() + + and: + String fooText = getJarFileContents(output, 'META-INF/foo.properties') + fooText.contains('foo=1;3') + + and: + String barText = getJarFileContents(output, 'META-INF/bar.properties') + barText.contains('bar=4') + } + + @Issue( + ['https://github.com/GradleUp/shadow/issues/622', + 'https://github.com/GradleUp/shadow/issues/856' + ] + ) + def 'merged properties dont contain date comment'() { + given: + File one = buildJar('one.jar') + .insertFile('META-INF/test.properties', 'foo=one') + .write() + + File two = buildJar('two.jar') + .insertFile('META-INF/test.properties', 'foo=two') + .write() + + buildFile << """ + import ${PropertiesFileTransformer.name} + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + from('${escapedPath(one)}') + from('${escapedPath(two)}') + } + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + transform(PropertiesFileTransformer) { + paths = ['META-INF/test.properties'] + mergeStrategy = 'append' + } + } + """.stripIndent() + + when: + run('shadowJar') + + then: + output.exists() + String text = getJarFileContents(output, 'META-INF/test.properties') + text.replace('#', '').trim() == 'foo=one,two' + } +} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy index f4cdbb6fd..4f55f520b 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy @@ -387,7 +387,7 @@ class ShadowPluginSpec extends PluginSpecification { package client; import junit.framework.TestCase; public class Client extends TestCase { - public static void main(String[] args) {} + public static void main(String[] args) {} } """.stripIndent() @@ -1029,7 +1029,7 @@ class ShadowPluginSpec extends PluginSpecification { version = '1.0' repositories { maven { url = "${repo.uri}" } } dependencies { api project(':api') } - + shadowJar.minimize() """.stripIndent() @@ -1247,8 +1247,4 @@ class ShadowPluginSpec extends PluginSpecification { JarFile jar = new JarFile(output) assert jar.entries().collect().findAll { it.name.endsWith('.class') }.size() == 1 } - - private String escapedPath(File file) { - file.path.replaceAll('\\\\', '\\\\\\\\') - } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy index 2835108e8..aae6148d3 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy @@ -251,7 +251,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() implementation 'shadow:two:1.0' implementation files('${escapedPath(one)}') } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { mergeServiceFiles() } @@ -349,9 +349,9 @@ two # NOTE: No newline terminates this line/file File main = file('src/main/java/shadow/Main.java') main << ''' package shadow; - + public class Main { - + public static void main(String[] args) { } } '''.stripIndent() @@ -386,9 +386,9 @@ two # NOTE: No newline terminates this line/file File main = file('src/main/java/shadow/Main.java') main << ''' package shadow; - + public class Main { - + public static void main(String[] args) { } } '''.stripIndent() @@ -400,7 +400,7 @@ two # NOTE: No newline terminates this line/file attributes 'Test-Entry': 'FAILED' } } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { manifest { attributes 'Test-Entry': 'PASSED' @@ -430,7 +430,7 @@ two # NOTE: No newline terminates this line/file given: File xml1 = buildJar('xml1.jar').insertFile('properties.xml', ''' - + val1 @@ -439,7 +439,7 @@ two # NOTE: No newline terminates this line/file File xml2 = buildJar('xml2.jar').insertFile('properties.xml', ''' - + val2 @@ -485,9 +485,9 @@ two # NOTE: No newline terminates this line/file File main = file('src/main/java/shadow/Main.java') main << ''' package shadow; - + public class Main { - + public static void main(String[] args) { } } '''.stripIndent() @@ -499,7 +499,7 @@ two # NOTE: No newline terminates this line/file attributes 'Test-Entry': 'FAILED' } } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { manifest { attributes 'Test-Entry': 'PASSED' @@ -545,9 +545,9 @@ two # NOTE: No newline terminates this line/file File main = file('src/main/java/shadow/Main.java') main << ''' package shadow; - + public class Main { - + public static void main(String[] args) { } } '''.stripIndent() @@ -559,7 +559,7 @@ two # NOTE: No newline terminates this line/file attributes 'Test-Entry': 'FAILED' } } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { manifest { attributes 'Test-Entry': 'PASSED' @@ -762,12 +762,7 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( 'Log4j2PluginsCacheFileTransformer' | '' 'ManifestAppenderTransformer' | '' 'ManifestResourceTransformer' | '' - 'PropertiesFileTransformer' | '{ keyTransformer = { it.toLowerCase() } }' 'ServiceFileTransformer' | '' 'XmlAppendingTransformer' | '' } - - private String escapedPath(File file) { - file.path.replaceAll('\\\\', '\\\\\\\\') - } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy index bd33ca03d..d0e5e1cb6 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy @@ -45,10 +45,6 @@ abstract class AbstractCachingSpec extends PluginSpecification { return runner.withProjectDir(alternateDir.toFile()).withArguments(cacheArguments).build() } - private String escapedPath(File file) { - file.path.replaceAll('\\\\', '\\\\\\\\') - } - void assertShadowJarHasResult(TaskOutcome expectedOutcome) { def result = runWithCacheEnabled(shadowJarTask) assert result.task(shadowJarTask).outcome == expectedOutcome diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index aa7d6967c..59b68847b 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -180,6 +180,10 @@ abstract class PluginSpecification extends Specification { return new File(this.class.classLoader.getResource(name).toURI()) } + protected String escapedPath(File file) { + file.path.replaceAll('\\\\', '\\\\\\\\') + } + static File getTestKitDir() { def gradleUserHome = System.getenv("GRADLE_USER_HOME") if (!gradleUserHome) { From 6861d79fed99bbeb94576a467b60cc92daa31850 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 1 Jul 2025 21:12:27 +0800 Subject: [PATCH 28/72] Prepare version 8.3.8 --- gradle.properties | 2 +- src/docs/changes/README.md | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 45250ed2f..e798c1313 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.8-SNAPSHOT +VERSION_NAME=8.3.8 SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=CENTRAL_PORTAL diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 398928e25..92890e195 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,7 +1,10 @@ # Change Log -## [Unreleased] +## [v8.3.8] (2025-07-01) + +> [!WARNING] +> Only Gradle 9 support is being backported to this version. No additional features or crucial bug fixes will be included in the 8.x line. Please migrate to Shadow 9 as soon as possible. **Fixed** @@ -440,7 +443,8 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = " Date: Tue, 1 Jul 2025 21:13:34 +0800 Subject: [PATCH 29/72] Prepare next development version --- gradle.properties | 2 +- src/docs/changes/README.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e798c1313..bc6f72492 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.8 +VERSION_NAME=8.3.9-SNAPSHOT SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=CENTRAL_PORTAL diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 92890e195..a58a1f91d 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,6 +1,9 @@ # Change Log +## [Unreleased] + + ## [v8.3.8] (2025-07-01) > [!WARNING] From be4e01414b615bf5c1c7525d99f1db2502b3c884 Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 2 Jul 2025 19:26:44 +0800 Subject: [PATCH 30/72] Don't set 8.x release as the latest --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8ff8a6a2e..77d6da030 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,6 +35,6 @@ jobs: changelog_file: src/docs/changes/README.md release_notes_file: RELEASE_NOTES.md - name: Create release - run: gh release create ${{ github.ref_name }} --notes-file RELEASE_NOTES.md + run: gh release create ${{ github.ref_name }} --latest=false --notes-file RELEASE_NOTES.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 73933ea22e66314cb979ec4d67e7d162b3dcfe7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 08:37:29 +0800 Subject: [PATCH 31/72] Update dependency gradle to v9.0.0 (#1557) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> (cherry picked from commit fd0570512fee4aab170b85f2d53e0c7718d56c6d) --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 407c905d9..2a84e188b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-rc-1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 218c78ac9a113d66515e678bbbacb1e2043a5d76 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 5 Aug 2025 11:44:37 +1000 Subject: [PATCH 32/72] Use BufferedOutputStream when writing the Zip file to improve performance (#1579) * fix: use buffered writes for performance When not using STORED entries use a BufferedOutputStream to avoid lots of small writes to the file system. Testing this with a 300mb jar build I see the total build time going from 40s to 30s. Note that it is not possible to do this with STORED entries as the implementation requires a RandomAccessFile to update the CRC after write. * Cleanup --------- Co-authored-by: Goooler --- src/docs/changes/README.md | 3 +++ .../plugins/shadow/internal/DefaultZipCompressor.groovy | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index a58a1f91d..5fb6e527a 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,9 @@ ## [Unreleased] +**Changed** + +- Use `BufferedOutputStream` when writing the Zip file to improve performance. ([#1579](https://github.com/GradleUp/shadow/pull/1579)) ## [v8.3.8] (2025-07-01) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy index 829ab294c..1e6dfa8b0 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy @@ -30,7 +30,10 @@ class DefaultZipCompressor implements ZipCompressor { @Override ZipOutputStream createArchiveOutputStream(File destination) { try { - ZipOutputStream zipOutputStream = new ZipOutputStream(destination) + ZipOutputStream zipOutputStream = entryCompressionMethod == ZipOutputStream.STORED ? + new ZipOutputStream(destination) : + // It is not possible to do this with STORED entries as the implementation requires a RandomAccessFile to update the CRC after write. + new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destination))) zipOutputStream.setUseZip64(zip64Mode) zipOutputStream.setMethod(entryCompressionMethod) return zipOutputStream From 2adc2d7379b8efc3facb42103414cc0f2141d167 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 5 Aug 2025 09:46:15 +0800 Subject: [PATCH 33/72] Prepare version 8.3.9 --- gradle.properties | 2 +- src/docs/changes/README.md | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index bc6f72492..f481d1547 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.9-SNAPSHOT +VERSION_NAME=8.3.9 SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=CENTRAL_PORTAL diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 5fb6e527a..603ea73d0 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,12 +1,16 @@ # Change Log -## [Unreleased] +## [v8.3.9] (2025-08-05) + +> [!WARNING] +> Only Gradle 9 support is being backported to this version. No additional features or crucial bug fixes will be included in the 8.x line. Please migrate to Shadow 9 as soon as possible. **Changed** - Use `BufferedOutputStream` when writing the Zip file to improve performance. ([#1579](https://github.com/GradleUp/shadow/pull/1579)) + ## [v8.3.8] (2025-07-01) > [!WARNING] @@ -449,7 +453,8 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = " Date: Tue, 5 Aug 2025 09:50:25 +0800 Subject: [PATCH 34/72] Prepare next development version --- gradle.properties | 2 +- src/docs/changes/README.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f481d1547..79ad451a1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.gradle.parallel=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.9 +VERSION_NAME=8.3.10-SNAPSHOT SONATYPE_AUTOMATIC_RELEASE=true SONATYPE_HOST=CENTRAL_PORTAL diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 603ea73d0..1a67c9a95 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,6 +1,9 @@ # Change Log +## [Unreleased] + + ## [v8.3.9] (2025-08-05) > [!WARNING] From 35318cd5b2bb5a75291fd225b0325adbb0091d37 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 12 Aug 2025 10:54:00 +0800 Subject: [PATCH 35/72] Fix resolving BOM dependencies when minimize is enabled (#1638) Ports 0187e753f555f32c8a829abc42a68bbe030eb0ea. --- src/docs/changes/README.md | 3 +++ .../gradle/plugins/shadow/internal/UnusedTracker.groovy | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 1a67c9a95..5f244b493 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,9 @@ ## [Unreleased] +**Fixed** + +- Fix resolving BOM dependencies when `minimize` is enabled. ([#1638](https://github.com/GradleUp/shadow/pull/1638)) ## [v8.3.9] (2025-08-05) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy index 5ff88aec2..e1402f2b4 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy @@ -77,7 +77,10 @@ class UnusedTracker { apiJars.addAll(dep.files) } else { addJar(runtimeConfiguration, dep, apiJars) - apiJars.add(runtimeConfiguration.find { it.name.startsWith("${dep.name}-") } as File) + def jarFile = runtimeConfiguration.find { it.name.startsWith("${dep.name}-") } + if (jarFile != null) { + apiJars.add(jarFile) + } } } From 81e1305bab9b52677f95d9b1bab81ac7275e0923 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Wed, 13 Aug 2025 20:39:24 +0800 Subject: [PATCH 36/72] Remove override of maxParallelForks (#1652) Ports aabf6526b3c062440cc3df7a531cc36ccf3afbbf --- build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2b0380c73..09ce6cc72 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -118,8 +118,6 @@ tasks.withType().configureEach { logger.info("Using test Gradle version: $testGradleVersion") systemProperty("TEST_GRADLE_VERSION", testGradleVersion) - maxParallelForks = Runtime.getRuntime().availableProcessors() - if (isCI) { testLogging.showStandardStreams = true minHeapSize = "1g" From 13c7f52a386e65fc07b8e3c46ca718429f03c9a4 Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 13 Aug 2025 21:08:22 +0800 Subject: [PATCH 37/72] Disable ManualCodeSnippetTests --- .../gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy index 76173de2e..4ee13e69f 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy @@ -8,6 +8,7 @@ import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.TestCod import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.SnippetExecuter import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.GroovyScriptFixture import com.google.common.base.StandardSystemProperty +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.DynamicTest import org.junit.jupiter.api.TestFactory import org.junit.jupiter.api.io.TempDir @@ -21,6 +22,7 @@ class ManualCodeSnippetTests { "groovy no-run": new NoopExecuter() ] + @Disabled("We have to run doc tests on main branch only") @TestFactory List provideDynamicTests(@TempDir Path tempDir) { File cwd = new File(StandardSystemProperty.USER_DIR.value()) From ceabb8854a9a9238ba99c4bed1e7c4b12203fa22 Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 13 Aug 2025 21:25:45 +0800 Subject: [PATCH 38/72] Polish stuff --- build.gradle.kts | 30 ++----------------- gradle.properties | 6 ++-- .../docs/executer/GradleBuildExecuter.groovy | 2 +- .../shadow/util/PluginSpecification.groovy | 4 +-- 4 files changed, 8 insertions(+), 34 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 09ce6cc72..4ec1095f0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,8 +7,8 @@ plugins { groovy `java-gradle-plugin` id("com.gradle.plugin-publish") version "1.3.1" - id("com.vanniktech.maven.publish") version "0.32.0" - id("com.diffplug.spotless") version "7.0.4" + id("com.vanniktech.maven.publish") version "0.34.0" + id("com.diffplug.spotless") version "7.2.1" } version = providers.gradleProperty("VERSION_NAME").get() @@ -18,8 +18,6 @@ description = providers.gradleProperty("POM_DESCRIPTION").get() java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 - withSourcesJar() - withJavadocJar() } gradlePlugin { @@ -40,8 +38,6 @@ gradlePlugin { spotless { kotlinGradle { ktlint() - target("**/*.kts") - targetExclude("build-logic/build/**") } } @@ -97,35 +93,15 @@ dependencies { testImplementation("org.junit.platform:junit-platform-suite-engine") } -tasks.withType().configureEach { - (options as? StandardJavadocDocletOptions)?.let { - it.links( - "https://docs.oracle.com/en/java/javase/17/docs/api/", - "https://docs.groovy-lang.org/2.4.7/html/gapi/", - ) - it.addStringOption("Xdoclint:none", "-quiet") - } -} - -val isCI = providers.environmentVariable("CI").isPresent - tasks.withType().configureEach { useJUnitPlatform() val testGradleVersion = providers.gradleProperty("testGradleVersion").orNull.let { if (it == null || it == "current") GradleVersion.current().version else it } - logger.info("Using test Gradle version: $testGradleVersion") + logger.lifecycle("Using test Gradle version: $testGradleVersion") systemProperty("TEST_GRADLE_VERSION", testGradleVersion) - if (isCI) { - testLogging.showStandardStreams = true - minHeapSize = "1g" - maxHeapSize = "1g" - } - - systemProperty("shadowVersion", version) - // Required to test configuration cache in tests when using withDebug() // https://github.com/gradle/gradle/issues/22765#issuecomment-1339427241 jvmArgs( diff --git a/gradle.properties b/gradle.properties index 79ad451a1..04e7e3b4f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,9 +13,9 @@ GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin VERSION_NAME=8.3.10-SNAPSHOT -SONATYPE_AUTOMATIC_RELEASE=true -SONATYPE_HOST=CENTRAL_PORTAL -RELEASE_SIGNING_ENABLED=true +mavenCentralAutomaticPublishing=true +mavenCentralPublishing=true +signAllPublications=true POM_NAME=Shadow Gradle Plugin POM_DESCRIPTION=Gradle plugin to create fat/uber JARs, apply file transforms, and relocate packages for applications and libraries. Gradle version of Maven's Shade plugin. diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy index 579e7dc5f..d727eb562 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy @@ -82,6 +82,6 @@ repositories { } private static String replaceTokens(String snippet) { - return snippet.replaceAll("@version@", PluginSpecification.SHADOW_VERSION + '-SNAPSHOT') + return snippet.replaceAll("@version@", 'latest') } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index 59b68847b..623138bb2 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -16,8 +16,6 @@ abstract class PluginSpecification extends Specification { @TempDir Path dir - public static final String SHADOW_VERSION = System.getProperty("shadowVersion") - public static final String TEST_GRADLE_VERSION = System.getProperty("TEST_GRADLE_VERSION") AppendableMavenFileRepository repo @@ -41,7 +39,7 @@ abstract class PluginSpecification extends Specification { return """ plugins { id '${javaPlugin}' - id 'com.gradleup.shadow' version '${SHADOW_VERSION}' + id 'com.gradleup.shadow' } version = "1.0" From 70f0be9f4338afdaeebeaad2862f246c925de55f Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 16 Sep 2025 16:13:09 +0800 Subject: [PATCH 39/72] Reformat all Java and Groovy code (#1751) --- .editorconfig | 4 +- .../shadow/ShadowApplicationPlugin.groovy | 4 +- .../plugins/shadow/ShadowJavaPlugin.groovy | 4 +- .../gradle/plugins/shadow/ShadowStats.groovy | 8 +- .../internal/AbstractDependencyFilter.groovy | 6 +- .../shadow/internal/CleanProperties.groovy | 4 +- .../internal/DefaultZipCompressor.groovy | 2 +- .../internal/MinimizeDependencyFilter.groovy | 4 +- .../shadow/internal/RelocationUtil.groovy | 1 + .../shadow/internal/UnusedTracker.groovy | 2 +- .../shadow/relocation/SimpleRelocator.groovy | 10 +- .../plugins/shadow/tasks/ShadowJar.java | 53 ++-- .../plugins/shadow/tasks/ShadowSpec.java | 1 + .../ApacheLicenseResourceTransformer.groovy | 2 +- .../ApacheNoticeResourceTransformer.groovy | 6 +- .../ComponentsXmlResourceTransformer.groovy | 4 +- .../GroovyExtensionModuleTransformer.groovy | 4 +- .../PropertiesFileTransformer.groovy | 3 +- .../ServiceFileTransformer.groovy | 20 +- .../XmlAppendingTransformer.groovy | 2 +- .../plugins/shadow/ApplicationSpec.groovy | 50 ++-- .../shadow/ConfigurationCacheSpec.groovy | 18 +- .../ConfigureShadowRelocationSpec.groovy | 32 +-- .../plugins/shadow/FilteringSpec.groovy | 96 +++---- .../plugins/shadow/PublishingSpec.groovy | 34 +-- .../plugins/shadow/RelocationSpec.groovy | 144 +++++----- .../plugins/shadow/ShadowPluginSpec.groovy | 132 +++++----- .../plugins/shadow/TransformerSpec.groovy | 248 +++++++++--------- .../shadow/caching/AbstractCachingSpec.groovy | 7 +- .../caching/MinimizationCachingSpec.groovy | 14 +- .../caching/RelocationCachingSpec.groovy | 16 +- .../caching/ShadowJarCachingSpec.groovy | 30 +-- .../caching/TransformCachingSpec.groovy | 68 ++--- .../shadow/docs/ManualCodeSnippetTests.groovy | 6 +- .../extractor/ManualSnippetExtractor.groovy | 2 +- .../plugins/shadow/docs/internal/Block.java | 14 +- .../internal/snippets/TestCodeSnippet.java | 1 + .../snippets/executer/CompileException.java | 20 +- .../executer/ExceptionTransformer.groovy | 58 ++-- .../snippets/executer/SnippetExecuter.java | 6 +- .../fixture/GroovyScriptFixture.groovy | 8 +- .../snippets/fixture/SnippetFixture.java | 30 +-- .../SimpleRelocatorParameterTest.groovy | 2 +- .../relocation/SimpleRelocatorTest.groovy | 16 +- ...pacheLicenseResourceTransformerTest.groovy | 3 +- ...ceResourceTransformerParameterTests.groovy | 2 +- ...ApacheNoticeResourceTransformerTest.groovy | 3 +- .../AppendingTransformerTest.groovy | 3 +- ...omponentsXmlResourceTransformerTest.groovy | 33 ++- ...g4j2PluginsCacheFileTransformerSpec.groovy | 1 - .../ManifestAppenderTransformerTest.groovy | 4 +- .../PropertiesFileTransformerSpec.groovy | 4 +- .../PropertiesFileTransformerTest.groovy | 6 +- .../ServiceFileTransformerSpec.groovy | 60 ++--- .../XmlAppendingTransformerTest.groovy | 3 +- .../gradle/plugins/shadow/util/HashUtil.java | 1 + .../shadow/util/PluginSpecification.groovy | 13 +- .../plugins/shadow/util/file/TestFile.java | 31 ++- .../shadow/util/file/TestFileHelper.groovy | 4 +- .../util/file/TestWorkspaceBuilder.groovy | 3 +- .../repo/maven/AbstractMavenModule.groovy | 6 +- .../repo/maven/DefaultMavenMetaData.groovy | 2 +- .../shadow/util/repo/maven/MavenPom.groovy | 12 +- 63 files changed, 721 insertions(+), 669 deletions(-) diff --git a/.editorconfig b/.editorconfig index 97c1b8453..a348d9bab 100755 --- a/.editorconfig +++ b/.editorconfig @@ -7,8 +7,10 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -[*.{groovy,java}] +[*.{java,groovy}] indent_size = 4 +ij_java_class_count_to_use_import_on_demand = 999 +ij_groovy_class_count_to_use_import_on_demand = 999 [*.{kt,kts}] ij_kotlin_imports_layout = * 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 3da91aab1..4b403b586 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 @@ -98,8 +98,8 @@ class ShadowApplicationPlugin implements Plugin { if (task.destinationDir.directory) { if (task.destinationDir.listFiles().size() != 0 && (!new File(task.destinationDir, 'lib').directory || !new File(task.destinationDir, 'bin').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." + "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/ShadowJavaPlugin.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy index 7a904a218..47a81c9db 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy @@ -97,8 +97,8 @@ class ShadowJavaPlugin implements Plugin { } shadow.from(sourceSets.main.output) shadow.configurations = [ - project.configurations.findByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME) ?: - project.configurations.runtime, + project.configurations.findByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME) ?: + project.configurations.runtime, ] shadow.exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class') } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowStats.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowStats.groovy index 8813dc61b..31cc56ee9 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowStats.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowStats.groovy @@ -19,7 +19,7 @@ class ShadowStats { String getRelocationString() { def maxLength = relocations.keySet().collect { it.length() }.max() - relocations.collect { k, v -> "${k} ${separator(k, maxLength)} ${v}"}.sort().join("\n") + relocations.collect { k, v -> "${k} ${separator(k, maxLength)} ${v}" }.sort().join("\n") } static String separator(String key, int max) { @@ -60,7 +60,7 @@ class ShadowStats { double getAverageTimeSecsPerJar() { averageTimePerJar / 1000 } - + String toString() { StringBuilder sb = new StringBuilder() sb.append "*******************\n" @@ -74,8 +74,8 @@ class ShadowStats { Map getBuildScanData() { [ - dependencies: jarCount, - relocations : relocationString, + dependencies: jarCount, + relocations : relocationString, ] as Map } } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy index 3232a9af9..2e401301b 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy @@ -105,8 +105,8 @@ abstract class AbstractDependencyFilter implements DependencyFilter { Spec dependency(Dependency dependency) { this.dependency({ ResolvedDependency it -> (!dependency.group || it.moduleGroup.matches(dependency.group)) && - (!dependency.name || it.moduleName.matches(dependency.name)) && - (!dependency.version || it.moduleVersion.matches(dependency.version)) + (!dependency.name || it.moduleName.matches(dependency.name)) && + (!dependency.version || it.moduleVersion.matches(dependency.version)) }) } @@ -117,7 +117,7 @@ abstract class AbstractDependencyFilter implements DependencyFilter { */ @Override Spec dependency(Closure spec) { - return Specs.convertClosureToSpec(spec) + return Specs. convertClosureToSpec(spec) } protected boolean isIncluded(ResolvedDependency dependency) { diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy index 689bac593..b94a779cc 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy @@ -25,8 +25,8 @@ class CleanProperties extends Properties { private boolean couldBeCommentWithTimestamp(final String str) { return str != null && - str.startsWith("#") && - str.length() == lengthOfExpectedTimestamp + str.startsWith("#") && + str.length() == lengthOfExpectedTimestamp } } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy index 1e6dfa8b0..103d46de3 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy @@ -22,7 +22,7 @@ class DefaultZipCompressor implements ZipCompressor { private final int entryCompressionMethod private final Zip64Mode zip64Mode - DefaultZipCompressor(boolean allowZip64Mode, int entryCompressionMethod) { + DefaultZipCompressor(boolean allowZip64Mode, int entryCompressionMethod) { this.entryCompressionMethod = entryCompressionMethod zip64Mode = allowZip64Mode ? Zip64Mode.AsNeeded : Zip64Mode.Never } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.groovy index 4853c3a77..d38d40ae2 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.groovy @@ -6,7 +6,7 @@ import org.gradle.api.artifacts.ResolvedDependency @Slf4j class MinimizeDependencyFilter extends AbstractDependencyFilter { - + MinimizeDependencyFilter(Project project) { super(project) } @@ -26,4 +26,4 @@ class MinimizeDependencyFilter extends AbstractDependencyFilter { private static boolean isParentExcluded(Set excludedDependencies, ResolvedDependency dependency) { excludedDependencies.any { dependency.parents.contains(it) } } -} \ No newline at end of file +} diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy index f3d55385b..43d1b855f 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/RelocationUtil.groovy @@ -1,6 +1,7 @@ package com.github.jengelman.gradle.plugins.shadow.internal import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + import java.util.jar.JarFile class RelocationUtil { diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy index e1402f2b4..16968b9c0 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy @@ -53,7 +53,7 @@ class UnusedTracker { def dependencyName = dep.name return (fileName == "${dependencyName}.jar") || - (fileName.startsWith("${dependencyName}-") && fileName.endsWith('.jar')) + (fileName.startsWith("${dependencyName}-") && fileName.endsWith('.jar')) } private static void addJar(Configuration config, Dependency dep, List result) { diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.groovy index 4f4ec7688..90e3e7234 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.groovy @@ -46,7 +46,7 @@ class SimpleRelocator implements Relocator { private final Set includes private final Set excludes - + private final boolean rawString SimpleRelocator() { @@ -58,7 +58,7 @@ class SimpleRelocator implements Relocator { } SimpleRelocator(String patt, String shadedPattern, List includes, List excludes, - boolean rawString) { + boolean rawString) { this.rawString = rawString if (rawString) { @@ -170,7 +170,7 @@ class SimpleRelocator implements Relocator { // Allow for annoying option of an extra / on the front of a path. See MSHADE-119 comes from getClass().getResource("/a/b/c.properties"). boolean pathStartsWithPattern = - path.charAt(0) == '/' ? path.startsWith(pathPattern, 1) : path.startsWith(pathPattern) + path.charAt(0) == '/' ? path.startsWith(pathPattern, 1) : path.startsWith(pathPattern) if (pathStartsWithPattern) { return isIncluded(path) && !isExcluded(path) } @@ -180,8 +180,8 @@ class SimpleRelocator implements Relocator { @Override boolean canRelocateClass(String className) { return !rawString && - className.indexOf('/') < 0 && - canRelocatePath(className.replace('.', '/')) + className.indexOf('/') < 0 && + canRelocatePath(className.replace('.', '/')) } @Override 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 ab45dbee9..bc25af4f7 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 @@ -1,11 +1,22 @@ package com.github.jengelman.gradle.plugins.shadow.tasks; import com.github.jengelman.gradle.plugins.shadow.ShadowStats; -import com.github.jengelman.gradle.plugins.shadow.internal.*; +import com.github.jengelman.gradle.plugins.shadow.internal.DefaultDependencyFilter; +import com.github.jengelman.gradle.plugins.shadow.internal.DependencyFilter; +import com.github.jengelman.gradle.plugins.shadow.internal.GradleVersionUtil; +import com.github.jengelman.gradle.plugins.shadow.internal.MinimizeDependencyFilter; +import com.github.jengelman.gradle.plugins.shadow.internal.RelocationUtil; +import com.github.jengelman.gradle.plugins.shadow.internal.UnusedTracker; +import com.github.jengelman.gradle.plugins.shadow.internal.ZipCompressor; import com.github.jengelman.gradle.plugins.shadow.relocation.CacheableRelocator; import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator; import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator; -import com.github.jengelman.gradle.plugins.shadow.transformers.*; +import com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer; +import com.github.jengelman.gradle.plugins.shadow.transformers.CacheableTransformer; +import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer; +import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer; +import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer; + import org.gradle.api.Action; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DuplicatesStrategy; @@ -13,7 +24,18 @@ import org.gradle.api.internal.DocumentationRegistry; import org.gradle.api.internal.file.FileResolver; import org.gradle.api.internal.file.copy.CopyAction; -import org.gradle.api.tasks.*; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.bundling.Jar; import org.gradle.api.tasks.util.PatternSet; import org.jetbrains.annotations.NotNull; @@ -107,16 +129,16 @@ protected CopyAction createCopyAction() { DocumentationRegistry documentationRegistry = getServices().get(DocumentationRegistry.class); final UnusedTracker unusedTracker = minimizeJar ? UnusedTracker.forProject(getApiJars(), getSourceSetsClassesDirs().getFiles(), getToMinimize()) : null; return new ShadowCopyAction(getArchiveFile().get().getAsFile(), getInternalCompressor(), documentationRegistry, - this.getMetadataCharset(), transformers, relocators, getRootPatternSet(), shadowStats, - isPreserveFileTimestamps(), minimizeJar, unusedTracker); + this.getMetadataCharset(), transformers, relocators, getRootPatternSet(), shadowStats, + isPreserveFileTimestamps(), minimizeJar, unusedTracker); } @Classpath FileCollection getToMinimize() { if (toMinimize == null) { toMinimize = minimizeJar - ? dependencyFilterForMinimize.resolve(configurations).minus(getApiJars()) - : getProject().getObjects().fileCollection(); + ? dependencyFilterForMinimize.resolve(configurations).minus(getApiJars()) + : getProject().getObjects().fileCollection(); } return toMinimize; } @@ -126,8 +148,8 @@ FileCollection getToMinimize() { FileCollection getApiJars() { if (apiJars == null) { apiJars = minimizeJar - ? UnusedTracker.getApiJarsFromProject(getProject()) - : getProject().getObjects().fileCollection(); + ? UnusedTracker.getApiJarsFromProject(getProject()) + : getProject().getObjects().fileCollection(); } return apiJars; } @@ -209,7 +231,7 @@ public ShadowJar transform(Class clazz) throws Instantiat * Add a Transformer instance for modifying JAR resources and configure. * * @param clazz the transformer class to add. Must have no-arg constructor - * @param c the configuration for the transformer + * @param c the configuration for the transformer * @return this */ @Override @@ -321,7 +343,7 @@ public ShadowJar append(final String resourcePath) { /** * Add a class relocator that maps each class in the pattern to the provided destination. * - * @param pattern the source pattern to relocate + * @param pattern the source pattern to relocate * @param destination the destination package * @return this */ @@ -333,9 +355,9 @@ public ShadowJar relocate(String pattern, String destination) { /** * Add a class relocator that maps each class in the pattern to the provided destination. * - * @param pattern the source pattern to relocate + * @param pattern the source pattern to relocate * @param destination the destination package - * @param configure the configuration of the relocator + * @param configure the configuration of the relocator * @return this */ @Override @@ -380,7 +402,7 @@ private void addRelocator(R relocator, Action configure * Add a relocator of the provided class and configure. * * @param relocatorClass the relocator class to add. Must have a no-arg constructor - * @param configure the configuration for the relocator + * @param configure the configuration for the relocator * @return this */ @Override @@ -412,7 +434,8 @@ public void setRelocators(List relocators) { this.relocators = relocators; } - @Classpath @Optional + @Classpath + @Optional public List getConfigurations() { return this.configurations; } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowSpec.java b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowSpec.java index cc86e4e5c..0d1d853b7 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowSpec.java +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowSpec.java @@ -6,6 +6,7 @@ import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator; import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer; import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer; + import org.gradle.api.Action; import org.gradle.api.file.CopySpec; diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.groovy index 569066ae1..42d16e2bd 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformer.groovy @@ -39,7 +39,7 @@ class ApacheLicenseResourceTransformer implements Transformer { boolean canTransformResource(FileTreeElement element) { def path = element.relativePath.pathString return LICENSE_PATH.equalsIgnoreCase(path) || - LICENSE_TXT_PATH.regionMatches(true, 0, path, 0, LICENSE_TXT_PATH.length()) + LICENSE_TXT_PATH.regionMatches(true, 0, path, 0, LICENSE_TXT_PATH.length()) } @Override 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 77ef87fbc..f7a8add39 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 @@ -49,8 +49,8 @@ class ApacheNoticeResourceTransformer implements Transformer { @Input String preamble1 = "// ------------------------------------------------------------------\n" + - "// NOTICE file corresponding to the section 4d of The Apache License,\n" + - "// Version 2.0, in this case for " + "// NOTICE file corresponding to the section 4d of The Apache License,\n" + + "// Version 2.0, in this case for " @Input String preamble2 = "\n// ------------------------------------------------------------------\n" @@ -130,7 +130,7 @@ class ApacheNoticeResourceTransformer implements Transformer { if (trimedLine.startsWith("- ")) { //resource-bundle 1.3 mode if (lineCount == 1 - && sb.toString().indexOf("This product includes/uses software(s) developed by") != -1) { + && sb.toString().indexOf("This product includes/uses software(s) developed by") != -1) { currentOrg = organizationEntries.get(sb.toString().trim()) if (currentOrg == null) { currentOrg = new TreeSet() diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.groovy index 58483d3cf..f0024c68e 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformer.groovy @@ -57,7 +57,7 @@ class ComponentsXmlResourceTransformer implements Transformer { try { BufferedInputStream bis = new BufferedInputStream(context.is) { void close() - throws IOException { + throws IOException { // leave ZIP open } } @@ -136,7 +136,7 @@ class ComponentsXmlResourceTransformer implements Transformer { } private byte[] getTransformedResource() - throws IOException { + throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 4) try (Writer writer = new XmlStreamWriter(baos)) { diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.groovy index 62255f3df..d378a9cd3 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformer.groovy @@ -43,9 +43,9 @@ import org.gradle.api.file.FileTreeElement class GroovyExtensionModuleTransformer implements Transformer { private static final GROOVY_LEGACY_EXTENSION_MODULE_DESCRIPTOR_PATH = - "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" + "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" private static final GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATH = - "META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule" + "META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule" private static final MODULE_NAME_KEY = 'moduleName' private static final MODULE_VERSION_KEY = 'moduleVersion' diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy index dde1869ec..a8e5dc58c 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy @@ -137,7 +137,8 @@ class PropertiesFileTransformer implements Transformer { @Internal Closure keyTransformer = new Closure("") { - String doCall(Object arguments) { arguments } // We can't use Closure#IDENTITY instead, as it is not compatible with Groovy 3 and 4. + String doCall(Object arguments) { arguments } + // We can't use Closure#IDENTITY instead, as it is not compatible with Groovy 3 and 4. } @Override diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.groovy index b2153a3f9..7c19c1ae5 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformer.groovy @@ -23,12 +23,12 @@ import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContex import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowCopyAction import org.apache.tools.zip.ZipEntry import org.apache.tools.zip.ZipOutputStream +import org.codehaus.plexus.util.IOUtil import org.gradle.api.file.FileTreeElement import org.gradle.api.specs.Spec import org.gradle.api.tasks.Input import org.gradle.api.tasks.util.PatternFilterable import org.gradle.api.tasks.util.PatternSet -import org.codehaus.plexus.util.IOUtil /** * Modified from org.apache.maven.plugins.shade.resource.ServiceResourceTransformer.java @@ -49,12 +49,12 @@ class ServiceFileTransformer implements Transformer, PatternFilterable { private static final String SERVICES_PATTERN = "META-INF/services/**" private static final String GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATTERN = - "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" + "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" private Map serviceEntries = [:].withDefault { new ServiceStream() } private final PatternSet patternSet = - new PatternSet().include(SERVICES_PATTERN).exclude(GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATTERN) + new PatternSet().include(SERVICES_PATTERN).exclude(GROOVY_EXTENSION_MODULE_DESCRIPTOR_PATTERN) void setPath(String path) { patternSet.setIncludes(["${path}/**"]) @@ -70,7 +70,7 @@ class ServiceFileTransformer implements Transformer, PatternFilterable { void transform(TransformerContext context) { def lines = context.is.readLines() def targetPath = context.path - context.relocators.each {rel -> + context.relocators.each { rel -> if (rel.canRelocateClass(new File(targetPath).name)) { targetPath = rel.relocateClass(RelocateClassContext.builder().className(targetPath).stats(context.stats).build()) } @@ -81,7 +81,7 @@ class ServiceFileTransformer implements Transformer, PatternFilterable { } } } - lines.each {line -> serviceEntries[targetPath].append(new ByteArrayInputStream(line.getBytes()))} + lines.each { line -> serviceEntries[targetPath].append(new ByteArrayInputStream(line.getBytes())) } } @Override @@ -102,12 +102,12 @@ class ServiceFileTransformer implements Transformer, PatternFilterable { static class ServiceStream extends ByteArrayOutputStream { - ServiceStream(){ - super( 1024 ) + ServiceStream() { + super(1024) } - void append(InputStream is ) throws IOException { - if ( super.count > 0 && super.buf[super.count - 1] != '\n' && super.buf[super.count - 1] != '\r' ) { + void append(InputStream is) throws IOException { + if (super.count > 0 && super.buf[super.count - 1] != '\n' && super.buf[super.count - 1] != '\r') { byte[] newline = '\n'.bytes write(newline, 0, newline.length) } @@ -115,7 +115,7 @@ class ServiceFileTransformer implements Transformer, PatternFilterable { } InputStream toInputStream() { - return new ByteArrayInputStream( super.buf, 0, super.count ) + return new ByteArrayInputStream(super.buf, 0, super.count) } } diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.groovy index 76e12f06d..4d7efad8e 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformer.groovy @@ -76,7 +76,7 @@ class XmlAppendingTransformer implements Transformer { if (ignoreDtd) { builder.setEntityResolver(new EntityResolver() { InputSource resolveEntity(String publicId, String systemId) - throws SAXException, IOException { + throws SAXException, IOException { return new InputSource(new StringReader("")) } }) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy index 00f2c51fc..ff6f72cb6 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy @@ -13,9 +13,9 @@ class ApplicationSpec extends PluginSpecification { def 'integration with application plugin'() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() file('src/main/java/myapp/Main.java') << """ package myapp; @@ -32,11 +32,11 @@ class ApplicationSpec extends PluginSpecification { application { mainClass = 'myapp.Main' } - + dependencies { implementation 'shadow:a:1.0' } - + runShadow { args 'foo' } @@ -76,9 +76,9 @@ class ApplicationSpec extends PluginSpecification { def 'integration with application plugin and java toolchains'() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() file('src/main/java/myapp/Main.java') << """ package myapp; @@ -91,35 +91,35 @@ class ApplicationSpec extends PluginSpecification { buildFile << """ apply plugin: 'application' - + application { mainClass = 'myapp.Main' } - + dependencies { implementation 'shadow:a:1.0' } - + java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } - + runShadow { args 'foo' doFirst { logger.lifecycle("Running application with JDK \${it.javaLauncher.get().metadata.languageVersion.asInt()}") } - } + } """.stripIndent() - settingsFile.write """ + settingsFile.write """ plugins { // https://docs.gradle.org/8.0.1/userguide/toolchains.html#sub:download_repositories id("org.gradle.toolchains.foojay-resolver-convention") version("0.7.0") } - + rootProject.name = 'myapp' """.stripIndent() @@ -157,9 +157,9 @@ class ApplicationSpec extends PluginSpecification { def 'shadow application distributions should use shadow jar'() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() file('src/main/java/myapp/Main.java') << """ package myapp; @@ -176,11 +176,11 @@ class ApplicationSpec extends PluginSpecification { application { mainClass = 'myapp.Main' } - + dependencies { shadow 'shadow:a:1.0' } - + runShadow { args 'foo' } @@ -209,9 +209,9 @@ class ApplicationSpec extends PluginSpecification { def 'installShadow does not execute dependent shadow task'() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() file('src/main/java/myapp/Main.java') << """ package myapp; @@ -228,11 +228,11 @@ class ApplicationSpec extends PluginSpecification { application { mainClass = 'myapp.Main' } - + dependencies { implementation 'shadow:a:1.0' } - + runShadow { args 'foo' } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy index 461a82061..9bb5ef2a0 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy @@ -7,12 +7,12 @@ class ConfigurationCacheSpec extends PluginSpecification { @Override def setup() { repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('b.properties', 'b') - .publish() + .insertFile('b.properties', 'b') + .publish() buildFile << """ dependencies { @@ -39,11 +39,11 @@ class ConfigurationCacheSpec extends PluginSpecification { application { mainClass = 'myapp.Main' } - + dependencies { implementation 'shadow:a:1.0' } - + runShadow { args 'foo' } @@ -127,8 +127,8 @@ class ConfigurationCacheSpec extends PluginSpecification { then: output.exists() contains(output, [ - 'server/Server.class', - 'junit/framework/Test.class' + 'server/Server.class', + 'junit/framework/Test.class' ]) doesNotContain(output, ['client/Client.class']) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy index c7212ddbb..2c5af9c15 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy @@ -22,22 +22,22 @@ class ConfigureShadowRelocationSpec extends PluginSpecification { then: contains(output, [ - 'META-INF/MANIFEST.MF', - 'shadow/junit/textui/ResultPrinter.class', - 'shadow/junit/textui/TestRunner.class', - 'shadow/junit/framework/Assert.class', - 'shadow/junit/framework/AssertionFailedError.class', - 'shadow/junit/framework/ComparisonCompactor.class', - 'shadow/junit/framework/ComparisonFailure.class', - 'shadow/junit/framework/Protectable.class', - 'shadow/junit/framework/Test.class', - 'shadow/junit/framework/TestCase.class', - 'shadow/junit/framework/TestFailure.class', - 'shadow/junit/framework/TestListener.class', - 'shadow/junit/framework/TestResult$1.class', - 'shadow/junit/framework/TestResult.class', - 'shadow/junit/framework/TestSuite$1.class', - 'shadow/junit/framework/TestSuite.class' + 'META-INF/MANIFEST.MF', + 'shadow/junit/textui/ResultPrinter.class', + 'shadow/junit/textui/TestRunner.class', + 'shadow/junit/framework/Assert.class', + 'shadow/junit/framework/AssertionFailedError.class', + 'shadow/junit/framework/ComparisonCompactor.class', + 'shadow/junit/framework/ComparisonFailure.class', + 'shadow/junit/framework/Protectable.class', + 'shadow/junit/framework/Test.class', + 'shadow/junit/framework/TestCase.class', + 'shadow/junit/framework/TestFailure.class', + 'shadow/junit/framework/TestListener.class', + 'shadow/junit/framework/TestResult$1.class', + 'shadow/junit/framework/TestResult.class', + 'shadow/junit/framework/TestSuite$1.class', + 'shadow/junit/framework/TestSuite.class' ]) } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy index 7958c3656..970e33e8b 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy @@ -11,12 +11,12 @@ class FilteringSpec extends PluginSpecification { @Override def setup() { repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('b.properties', 'b') - .publish() + .insertFile('b.properties', 'b') + .publish() buildFile << """ dependencies { @@ -58,19 +58,19 @@ class FilteringSpec extends PluginSpecification { def "exclude dependency"() { given: repo.module('shadow', 'c', '1.0') - .insertFile('c.properties', 'c') - .publish() + .insertFile('c.properties', 'c') + .publish() repo.module('shadow', 'd', '1.0') - .insertFile('d.properties', 'd') - .dependsOn('c') - .publish() + .insertFile('d.properties', 'd') + .dependsOn('c') + .publish() buildFile << ''' // tag::excludeDep[] dependencies { implementation 'shadow:d:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { dependencies { exclude(dependency('shadow:d:1.0')) @@ -93,19 +93,19 @@ class FilteringSpec extends PluginSpecification { def "exclude dependency using wildcard syntax"() { given: repo.module('shadow', 'c', '1.0') - .insertFile('c.properties', 'c') - .publish() + .insertFile('c.properties', 'c') + .publish() repo.module('shadow', 'd', '1.0') - .insertFile('d.properties', 'd') - .dependsOn('c') - .publish() + .insertFile('d.properties', 'd') + .dependsOn('c') + .publish() buildFile << ''' // tag::excludeDepWildcard[] dependencies { implementation 'shadow:d:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { dependencies { exclude(dependency('shadow:d:.*')) @@ -129,18 +129,18 @@ class FilteringSpec extends PluginSpecification { def "dependency exclusions affect UP-TO-DATE check"() { given: repo.module('shadow', 'c', '1.0') - .insertFile('c.properties', 'c') - .publish() + .insertFile('c.properties', 'c') + .publish() repo.module('shadow', 'd', '1.0') - .insertFile('d.properties', 'd') - .dependsOn('c') - .publish() + .insertFile('d.properties', 'd') + .dependsOn('c') + .publish() buildFile << ''' dependencies { implementation 'shadow:d:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { dependencies { exclude(dependency('shadow:d:1.0')) @@ -159,7 +159,7 @@ class FilteringSpec extends PluginSpecification { when: 'Update build file shadowJar dependency exclusion' buildFile.text = buildFile.text.replace('exclude(dependency(\'shadow:d:1.0\'))', - 'exclude(dependency(\'shadow:c:1.0\'))') + 'exclude(dependency(\'shadow:c:1.0\'))') BuildResult result = run('shadowJar') @@ -178,18 +178,18 @@ class FilteringSpec extends PluginSpecification { def "project exclusions affect UP-TO-DATE check"() { given: repo.module('shadow', 'c', '1.0') - .insertFile('c.properties', 'c') - .publish() + .insertFile('c.properties', 'c') + .publish() repo.module('shadow', 'd', '1.0') - .insertFile('d.properties', 'd') - .dependsOn('c') - .publish() + .insertFile('d.properties', 'd') + .dependsOn('c') + .publish() buildFile << ''' dependencies { implementation 'shadow:d:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { dependencies { exclude(dependency('shadow:d:1.0')) @@ -228,12 +228,12 @@ class FilteringSpec extends PluginSpecification { def "include dependency, excluding all others"() { given: repo.module('shadow', 'c', '1.0') - .insertFile('c.properties', 'c') - .publish() + .insertFile('c.properties', 'c') + .publish() repo.module('shadow', 'd', '1.0') - .insertFile('d.properties', 'd') - .dependsOn('c') - .publish() + .insertFile('d.properties', 'd') + .dependsOn('c') + .publish() file('src/main/java/shadow/Passed.java') << ''' package shadow; @@ -244,7 +244,7 @@ class FilteringSpec extends PluginSpecification { dependencies { implementation 'shadow:d:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { dependencies { include(dependency('shadow:d:1.0')) @@ -293,7 +293,7 @@ class FilteringSpec extends PluginSpecification { dependencies { implementation project(':client') } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { dependencies { exclude(project(':client')) @@ -310,7 +310,7 @@ class FilteringSpec extends PluginSpecification { then: serverOutput.exists() doesNotContain(serverOutput, [ - 'client/Client.class', + 'client/Client.class', ]) and: @@ -364,13 +364,13 @@ class FilteringSpec extends PluginSpecification { then: serverOutput.exists() doesNotContain(serverOutput, [ - 'junit/framework/Test.class' + 'junit/framework/Test.class' ]) and: contains(serverOutput, [ - 'client/Client.class', - 'server/Server.class']) + 'client/Client.class', + 'server/Server.class']) } //http://mail-archives.apache.org/mod_mbox/ant-user/200506.mbox/%3C001d01c57756$6dc35da0$dc00a8c0@CTEGDOMAIN.COM%3E @@ -400,19 +400,19 @@ class FilteringSpec extends PluginSpecification { def "handle exclude with circular dependency"() { given: repo.module('shadow', 'c', '1.0') - .insertFile('c.properties', 'c') - .dependsOn('d') - .publish() + .insertFile('c.properties', 'c') + .dependsOn('d') + .publish() repo.module('shadow', 'd', '1.0') - .insertFile('d.properties', 'd') - .dependsOn('c') - .publish() + .insertFile('d.properties', 'd') + .dependsOn('c') + .publish() buildFile << ''' dependencies { implementation 'shadow:d:1.0' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { dependencies { exclude(dependency('shadow:d:1.0')) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy index f23895394..6ce01faff 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy @@ -20,12 +20,12 @@ class PublishingSpec extends PluginSpecification { def "publish shadow jar with maven-publish plugin"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('b.properties', 'b') - .publish() + .insertFile('b.properties', 'b') + .publish() settingsFile << "rootProject.name = 'maven'" buildFile << """ @@ -81,18 +81,18 @@ class PublishingSpec extends PluginSpecification { } @Issue([ - "https://github.com/GradleUp/shadow/issues/860", - "https://github.com/GradleUp/shadow/issues/945", + "https://github.com/GradleUp/shadow/issues/860", + "https://github.com/GradleUp/shadow/issues/945", ]) def "publish shadow jar with maven-publish plugin using custom classifier and extension"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('b.properties', 'b') - .publish() + .insertFile('b.properties', 'b') + .publish() settingsFile << "rootProject.name = 'maven'" buildFile << """ @@ -232,12 +232,12 @@ class PublishingSpec extends PluginSpecification { def "publish shadow jar with maven-publish plugin and Gradle metadata"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('b.properties', 'b') - .publish() + .insertFile('b.properties', 'b') + .publish() settingsFile << """ rootProject.name = 'maven' diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy index da4e1fb74..a72008197 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy @@ -31,41 +31,41 @@ class RelocationSpec extends PluginSpecification { then: contains(output, [ - 'META-INF/MANIFEST.MF', - 'a/ResultPrinter.class', - 'a/TestRunner.class', - 'b/Assert.class', - 'b/AssertionFailedError.class', - 'b/ComparisonCompactor.class', - 'b/ComparisonFailure.class', - 'b/Protectable.class', - 'b/Test.class', - 'b/TestCase.class', - 'b/TestFailure.class', - 'b/TestListener.class', - 'b/TestResult$1.class', - 'b/TestResult.class', - 'b/TestSuite$1.class', - 'b/TestSuite.class' + 'META-INF/MANIFEST.MF', + 'a/ResultPrinter.class', + 'a/TestRunner.class', + 'b/Assert.class', + 'b/AssertionFailedError.class', + 'b/ComparisonCompactor.class', + 'b/ComparisonFailure.class', + 'b/Protectable.class', + 'b/Test.class', + 'b/TestCase.class', + 'b/TestFailure.class', + 'b/TestListener.class', + 'b/TestResult$1.class', + 'b/TestResult.class', + 'b/TestSuite$1.class', + 'b/TestSuite.class' ]) and: doesNotContain(output, [ - 'junit/textui/ResultPrinter.class', - 'junit/textui/TestRunner.class', - 'junit/framework/Assert.class', - 'junit/framework/AssertionFailedError.class', - 'junit/framework/ComparisonCompactor.class', - 'junit/framework/ComparisonFailure.class', - 'junit/framework/Protectable.class', - 'junit/framework/Test.class', - 'junit/framework/TestCase.class', - 'junit/framework/TestFailure.class', - 'junit/framework/TestListener.class', - 'junit/framework/TestResult$1.class', - 'junit/framework/TestResult.class', - 'junit/framework/TestSuite$1.class', - 'junit/framework/TestSuite.class' + 'junit/textui/ResultPrinter.class', + 'junit/textui/TestRunner.class', + 'junit/framework/Assert.class', + 'junit/framework/AssertionFailedError.class', + 'junit/framework/ComparisonCompactor.class', + 'junit/framework/ComparisonFailure.class', + 'junit/framework/Protectable.class', + 'junit/framework/Test.class', + 'junit/framework/TestCase.class', + 'junit/framework/TestFailure.class', + 'junit/framework/TestListener.class', + 'junit/framework/TestResult$1.class', + 'junit/framework/TestResult.class', + 'junit/framework/TestSuite$1.class', + 'junit/framework/TestSuite.class' ]) and: 'Test that manifest file exists with contents' @@ -99,35 +99,35 @@ class RelocationSpec extends PluginSpecification { then: contains(output, [ - 'a/ResultPrinter.class', - 'b/Test.class', - 'b/TestCase.class', - 'b/TestFailure.class', - 'b/TestListener.class', - 'b/TestResult$1.class', - 'b/TestResult.class', - 'b/TestSuite$1.class', - 'b/TestSuite.class' + 'a/ResultPrinter.class', + 'b/Test.class', + 'b/TestCase.class', + 'b/TestFailure.class', + 'b/TestListener.class', + 'b/TestResult$1.class', + 'b/TestResult.class', + 'b/TestSuite$1.class', + 'b/TestSuite.class' ]) and: doesNotContain(output, [ - 'a/TestRunner.class', - 'b/Assert.class', - 'b/AssertionFailedError.class', - 'b/ComparisonCompactor.class', - 'b/ComparisonFailure.class', - 'b/Protectable.class' + 'a/TestRunner.class', + 'b/Assert.class', + 'b/AssertionFailedError.class', + 'b/ComparisonCompactor.class', + 'b/ComparisonFailure.class', + 'b/Protectable.class' ]) and: contains(output, [ - 'junit/textui/TestRunner.class', - 'junit/framework/Assert.class', - 'junit/framework/AssertionFailedError.class', - 'junit/framework/ComparisonCompactor.class', - 'junit/framework/ComparisonFailure.class', - 'junit/framework/Protectable.class' + 'junit/textui/TestRunner.class', + 'junit/framework/Assert.class', + 'junit/framework/AssertionFailedError.class', + 'junit/framework/ComparisonCompactor.class', + 'junit/framework/ComparisonFailure.class', + 'junit/framework/Protectable.class' ]) } @@ -162,21 +162,21 @@ class RelocationSpec extends PluginSpecification { then: contains(output, [ - 'shadow/ShadowTest.class', - 'shadow/junit/Test.class', - 'shadow/junit' + 'shadow/ShadowTest.class', + 'shadow/junit/Test.class', + 'shadow/junit' ]) and: doesNotContain(output, [ - 'junit/framework', - 'junit/framework/Test.class' + 'junit/framework', + 'junit/framework/Test.class' ]) and: 'check that the class can be loaded. If the file was not relocated properly, we should get a NoDefClassFound' // Isolated class loader with only the JVM system jars and the output jar from the test project URLClassLoader classLoader = new URLClassLoader([output.toURI().toURL()] as URL[], - ClassLoader.systemClassLoader.parent) + ClassLoader.systemClassLoader.parent) classLoader.loadClass('shadow.ShadowTest') } @@ -238,12 +238,12 @@ class RelocationSpec extends PluginSpecification { and: contains(appOutput, [ - 'TEST', - 'APP-TEST', - 'test.properties', - 'app/core/Core.class', - 'app/App.class', - 'app/junit/framework/Test.class' + 'TEST', + 'APP-TEST', + 'test.properties', + 'app/core/Core.class', + 'app/App.class', + 'app/junit/framework/Test.class' ]) } @@ -251,8 +251,8 @@ class RelocationSpec extends PluginSpecification { def "relocate resource files"() { given: repo.module('shadow', 'dep', '1.0') - .insertFile('foo/dep.properties', 'c') - .publish() + .insertFile('foo/dep.properties', 'c') + .publish() file('src/main/java/foo/Foo.java') << ''' package foo; @@ -275,16 +275,16 @@ class RelocationSpec extends PluginSpecification { then: contains(output, [ - 'bar/Foo.class', - 'bar/foo.properties', - 'bar/dep.properties' + 'bar/Foo.class', + 'bar/foo.properties', + 'bar/dep.properties' ]) and: doesNotContain(output, [ - 'foo/Foo.class', - 'foo/foo.properties', - 'foo/dep.properties' + 'foo/Foo.class', + 'foo/foo.properties', + 'foo/dep.properties' ]) } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy index 4f55f520b..fda372688 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy @@ -63,10 +63,10 @@ class ShadowPluginSpec extends PluginSpecification { def 'Compatible with Gradle #version'() { given: File one = buildJar('one.jar').insertFile('META-INF/services/shadow.Shadow', - 'one # NOTE: No newline terminates this line/file').write() + 'one # NOTE: No newline terminates this line/file').write() repo.module('shadow', 'two', '1.0').insertFile('META-INF/services/shadow.Shadow', - 'two # NOTE: No newline terminates this line/file').publish() + 'two # NOTE: No newline terminates this line/file').publish() buildFile << """ dependencies { @@ -204,9 +204,9 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'client/Client.class', - 'server/Server.class', - 'junit/framework/Test.class' + 'client/Client.class', + 'server/Server.class', + 'junit/framework/Test.class' ]) } @@ -261,8 +261,8 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'client/Client.class', - 'server/Server.class' + 'client/Client.class', + 'server/Server.class' ]) doesNotContain(serverOutput, ['junit/framework/Test.class']) } @@ -316,8 +316,8 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'server/Server.class', - 'junit/framework/Test.class' + 'server/Server.class', + 'junit/framework/Test.class' ]) doesNotContain(serverOutput, ['client/Client.class']) } @@ -368,8 +368,8 @@ class ShadowPluginSpec extends PluginSpecification { then: contains(serverOutput, [ - 'client/Client.class', - 'server/Server.class' + 'client/Client.class', + 'server/Server.class' ]) } @@ -423,9 +423,9 @@ class ShadowPluginSpec extends PluginSpecification { then: contains(serverOutput, [ - 'client/Client.class', - 'server/Server.class', - 'junit/framework/TestCase.class' + 'client/Client.class', + 'server/Server.class', + 'junit/framework/TestCase.class' ]) } @@ -476,9 +476,9 @@ class ShadowPluginSpec extends PluginSpecification { then: contains(serverOutput, [ - 'client/Client.class', - 'server/Server.class', - 'junit/framework/TestCase.class' + 'client/Client.class', + 'server/Server.class', + 'junit/framework/TestCase.class' ]) } @@ -555,10 +555,10 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'impl/SimpleEntity.class', - 'api/Entity.class', - 'api/UnusedEntity.class', - 'lib/LibEntity.class', + 'impl/SimpleEntity.class', + 'api/Entity.class', + 'api/UnusedEntity.class', + 'lib/LibEntity.class', ]) doesNotContain(serverOutput, ['junit/framework/Test.class', 'lib/UnusedLibEntity.class']) } @@ -631,11 +631,11 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'impl/SimpleEntity.class', - 'api/Entity.class', - 'api/UnusedEntity.class', - 'lib/LibEntity.class', - 'lib/UnusedLibEntity.class' + 'impl/SimpleEntity.class', + 'api/Entity.class', + 'api/UnusedEntity.class', + 'lib/LibEntity.class', + 'lib/UnusedLibEntity.class' ]) } @@ -685,14 +685,14 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'server/Server.class' + 'server/Server.class' ]) and: doesNotContain(serverOutput, [ - 'client/Client.class', - 'junit/framework/Test.class', - 'client/junit/framework/Test.class' + 'client/Client.class', + 'junit/framework/Test.class', + 'client/junit/framework/Test.class' ]) } @@ -743,27 +743,27 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'client/Client.class', - 'client/junit/framework/Test.class', - 'server/Server.class', + 'client/Client.class', + 'client/junit/framework/Test.class', + 'server/Server.class', ]) and: doesNotContain(serverOutput, [ - 'junit/framework/Test.class' + 'junit/framework/Test.class' ]) } def "exclude INDEX.LIST, *.SF, *.DSA, and *.RSA by default"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('META-INF/INDEX.LIST', 'JarIndex-Version: 1.0') - .insertFile('META-INF/a.SF', 'Signature File') - .insertFile('META-INF/a.DSA', 'DSA Signature Block') - .insertFile('META-INF/a.RSA', 'RSA Signature Block') - .insertFile('META-INF/a.properties', 'key=value') - .publish() + .insertFile('a.properties', 'a') + .insertFile('META-INF/INDEX.LIST', 'JarIndex-Version: 1.0') + .insertFile('META-INF/a.SF', 'Signature File') + .insertFile('META-INF/a.DSA', 'DSA Signature Block') + .insertFile('META-INF/a.RSA', 'RSA Signature Block') + .insertFile('META-INF/a.properties', 'key=value') + .publish() file('src/main/java/shadow/Passed.java') << ''' package shadow; @@ -787,12 +787,12 @@ class ShadowPluginSpec extends PluginSpecification { def "include runtime configuration by default"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .publish() + .insertFile('a.properties', 'a') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('b.properties', 'b') - .publish() + .insertFile('b.properties', 'b') + .publish() buildFile << """ dependencies { @@ -814,21 +814,21 @@ class ShadowPluginSpec extends PluginSpecification { def "include java-library configurations by default"() { given: repo.module('shadow', 'api', '1.0') - .insertFile('api.properties', 'api') - .publish() + .insertFile('api.properties', 'api') + .publish() repo.module('shadow', 'implementation-dep', '1.0') - .insertFile('implementation-dep.properties', 'implementation-dep') - .publish() + .insertFile('implementation-dep.properties', 'implementation-dep') + .publish() repo.module('shadow', 'implementation', '1.0') - .insertFile('implementation.properties', 'implementation') - .dependsOn('implementation-dep') - .publish() + .insertFile('implementation.properties', 'implementation') + .dependsOn('implementation-dep') + .publish() repo.module('shadow', 'runtimeOnly', '1.0') - .insertFile('runtimeOnly.properties', 'runtimeOnly') - .publish() + .insertFile('runtimeOnly.properties', 'runtimeOnly') + .publish() buildFile.text = getDefaultBuildScript('java-library') buildFile << """ @@ -850,12 +850,12 @@ class ShadowPluginSpec extends PluginSpecification { def "doesn't include compileOnly configuration by default"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .publish() + .insertFile('a.properties', 'a') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('b.properties', 'b') - .publish() + .insertFile('b.properties', 'b') + .publish() buildFile << """ dependencies { @@ -877,12 +877,12 @@ class ShadowPluginSpec extends PluginSpecification { def "default copying strategy"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('META-INF/MANIFEST.MF', 'MANIFEST A') - .publish() + .insertFile('META-INF/MANIFEST.MF', 'MANIFEST A') + .publish() repo.module('shadow', 'b', '1.0') - .insertFile('META-INF/MANIFEST.MF', 'MANIFEST B') - .publish() + .insertFile('META-INF/MANIFEST.MF', 'MANIFEST B') + .publish() buildFile << """ dependencies { @@ -1041,7 +1041,7 @@ class ShadowPluginSpec extends PluginSpecification { then: serverOutput.exists() contains(serverOutput, [ - 'api/UnusedEntity.class', + 'api/UnusedEntity.class', ]) } @@ -1050,9 +1050,9 @@ class ShadowPluginSpec extends PluginSpecification { def "check large zip files with zip64 enabled"() { given: repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() + .insertFile('a.properties', 'a') + .insertFile('a2.properties', 'a2') + .publish() file('src/main/java/myapp/Main.java') << """ package myapp; diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy index aae6148d3..7bed060ce 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy @@ -16,16 +16,16 @@ class TransformerSpec extends PluginSpecification { def 'service resource transformer'() { given: File one = buildJar('one.jar') - .insertFile('META-INF/services/org.apache.maven.Shade', - 'one # NOTE: No newline terminates this line/file') - .insertFile('META-INF/services/com.acme.Foo', 'one') - .write() + .insertFile('META-INF/services/org.apache.maven.Shade', + 'one # NOTE: No newline terminates this line/file') + .insertFile('META-INF/services/com.acme.Foo', 'one') + .write() File two = buildJar('two.jar') - .insertFile('META-INF/services/org.apache.maven.Shade', - 'two # NOTE: No newline terminates this line/file') - .insertFile('META-INF/services/com.acme.Foo', 'two') - .write() + .insertFile('META-INF/services/org.apache.maven.Shade', + 'two # NOTE: No newline terminates this line/file') + .insertFile('META-INF/services/com.acme.Foo', 'two') + .write() buildFile << """ import ${ServiceFileTransformer.name} @@ -50,7 +50,7 @@ class TransformerSpec extends PluginSpecification { String text1 = getJarFileContents(output, 'META-INF/services/org.apache.maven.Shade') assert text1.split("\\r?\\n").size() == 2 assert text1 == -'''one # NOTE: No newline terminates this line/file + '''one # NOTE: No newline terminates this line/file two # NOTE: No newline terminates this line/file'''.stripIndent() and: @@ -61,13 +61,13 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() def 'service resource transformer alternate path'() { given: - File one = buildJar('one.jar').insertFile('META-INF/foo/org.apache.maven.Shade', - 'one # NOTE: No newline terminates this line/file').write() + File one = buildJar('one.jar').insertFile('META-INF/foo/org.apache.maven.Shade', + 'one # NOTE: No newline terminates this line/file').write() - File two = buildJar('two.jar').insertFile('META-INF/foo/org.apache.maven.Shade', - 'two # NOTE: No newline terminates this line/file').write() + File two = buildJar('two.jar').insertFile('META-INF/foo/org.apache.maven.Shade', + 'two # NOTE: No newline terminates this line/file').write() - buildFile << """ + buildFile << """ import ${ServiceFileTransformer.name} tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { from('${escapedPath(one)}') @@ -81,32 +81,32 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() """.stripIndent() when: - run('shadowJar') + run('shadowJar') then: - assert output.exists() + assert output.exists() and: - String text = getJarFileContents(output, 'META-INF/foo/org.apache.maven.Shade') - assert text.split("\\r?\\n").size() == 2 - assert text == -'''one # NOTE: No newline terminates this line/file + String text = getJarFileContents(output, 'META-INF/foo/org.apache.maven.Shade') + assert text.split("\\r?\\n").size() == 2 + assert text == + '''one # NOTE: No newline terminates this line/file two # NOTE: No newline terminates this line/file'''.stripIndent() } def 'service resource transformer short syntax'() { given: - File one = buildJar('one.jar') - .insertFile('META-INF/services/org.apache.maven.Shade', - 'one # NOTE: No newline terminates this line/file') - .insertFile('META-INF/services/com.acme.Foo', 'one') - .write() - - File two = buildJar('two.jar') - .insertFile('META-INF/services/org.apache.maven.Shade', - 'two # NOTE: No newline terminates this line/file') - .insertFile('META-INF/services/com.acme.Foo', 'two') - .write() + File one = buildJar('one.jar') + .insertFile('META-INF/services/org.apache.maven.Shade', + 'one # NOTE: No newline terminates this line/file') + .insertFile('META-INF/services/com.acme.Foo', 'one') + .write() + + File two = buildJar('two.jar') + .insertFile('META-INF/services/org.apache.maven.Shade', + 'two # NOTE: No newline terminates this line/file') + .insertFile('META-INF/services/com.acme.Foo', 'two') + .write() buildFile << """ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { @@ -127,39 +127,39 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() assert output.exists() and: - String text1 = getJarFileContents(output, 'META-INF/services/org.apache.maven.Shade') - assert text1.split("\\r?\\n").size() == 2 - assert text1 == -'''one # NOTE: No newline terminates this line/file + String text1 = getJarFileContents(output, 'META-INF/services/org.apache.maven.Shade') + assert text1.split("\\r?\\n").size() == 2 + assert text1 == + '''one # NOTE: No newline terminates this line/file two # NOTE: No newline terminates this line/file'''.stripIndent() and: - String text2 = getJarFileContents(output, 'META-INF/services/com.acme.Foo') - assert text2.split("\\r?\\n").size() == 1 - assert text2 == 'one' + String text2 = getJarFileContents(output, 'META-INF/services/com.acme.Foo') + assert text2.split("\\r?\\n").size() == 1 + assert text2 == 'one' } def 'service resource transformer short syntax relocation'() { given: File one = buildJar('one.jar') - .insertFile('META-INF/services/java.sql.Driver', -'''oracle.jdbc.OracleDriver + .insertFile('META-INF/services/java.sql.Driver', + '''oracle.jdbc.OracleDriver org.apache.hive.jdbc.HiveDriver'''.stripIndent()) - .insertFile('META-INF/services/org.apache.axis.components.compiler.Compiler', + .insertFile('META-INF/services/org.apache.axis.components.compiler.Compiler', 'org.apache.axis.components.compiler.Javac') - .insertFile('META-INF/services/org.apache.commons.logging.LogFactory', + .insertFile('META-INF/services/org.apache.commons.logging.LogFactory', 'org.apache.commons.logging.impl.LogFactoryImpl') - .write() + .write() File two = buildJar('two.jar') - .insertFile('META-INF/services/java.sql.Driver', -'''org.apache.derby.jdbc.AutoloadedDriver + .insertFile('META-INF/services/java.sql.Driver', + '''org.apache.derby.jdbc.AutoloadedDriver com.mysql.jdbc.Driver'''.stripIndent()) - .insertFile('META-INF/services/org.apache.axis.components.compiler.Compiler', + .insertFile('META-INF/services/org.apache.axis.components.compiler.Compiler', 'org.apache.axis.components.compiler.Jikes') - .insertFile('META-INF/services/org.apache.commons.logging.LogFactory', + .insertFile('META-INF/services/org.apache.commons.logging.LogFactory', 'org.mortbay.log.Factory') - .write() + .write() buildFile << """ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { @@ -185,7 +185,7 @@ com.mysql.jdbc.Driver'''.stripIndent()) String text1 = getJarFileContents(output, 'META-INF/services/java.sql.Driver') assert text1.split("\\r?\\n").size() == 4 assert text1 == -'''oracle.jdbc.OracleDriver + '''oracle.jdbc.OracleDriver myapache.hive.jdbc.HiveDriver myapache.derby.jdbc.AutoloadedDriver com.mysql.jdbc.Driver'''.stripIndent() @@ -194,26 +194,26 @@ com.mysql.jdbc.Driver'''.stripIndent() String text2 = getJarFileContents(output, 'META-INF/services/myapache.axis.components.compiler.Compiler') assert text2.split("\\r?\\n").size() == 2 assert text2 == -'''myapache.axis.components.compiler.Javac + '''myapache.axis.components.compiler.Javac org.apache.axis.components.compiler.Jikes'''.stripIndent() and: String text3 = getJarFileContents(output, 'META-INF/services/org.apache.commons.logging.LogFactory') assert text3.split("\\r?\\n").size() == 2 assert text3 == -'''myapache.commons.logging.impl.LogFactoryImpl + '''myapache.commons.logging.impl.LogFactoryImpl org.mortbay.log.Factory'''.stripIndent() } def 'service resource transformer short syntax alternate path'() { given: - File one = buildJar('one.jar').insertFile('META-INF/foo/org.apache.maven.Shade', - 'one # NOTE: No newline terminates this line/file').write() + File one = buildJar('one.jar').insertFile('META-INF/foo/org.apache.maven.Shade', + 'one # NOTE: No newline terminates this line/file').write() - File two = buildJar('two.jar').insertFile('META-INF/foo/org.apache.maven.Shade', - 'two # NOTE: No newline terminates this line/file').write() + File two = buildJar('two.jar').insertFile('META-INF/foo/org.apache.maven.Shade', + 'two # NOTE: No newline terminates this line/file').write() - buildFile << """ + buildFile << """ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { from('${escapedPath(one)}') from('${escapedPath(two)}') @@ -224,16 +224,16 @@ org.mortbay.log.Factory'''.stripIndent() """.stripIndent() when: - run('shadowJar') + run('shadowJar') then: - assert output.exists() + assert output.exists() and: - String text = getJarFileContents(output, 'META-INF/foo/org.apache.maven.Shade') - assert text.split("\\r?\\n").size() == 2 - assert text == -'''one # NOTE: No newline terminates this line/file + String text = getJarFileContents(output, 'META-INF/foo/org.apache.maven.Shade') + assert text.split("\\r?\\n").size() == 2 + assert text == + '''one # NOTE: No newline terminates this line/file two # NOTE: No newline terminates this line/file'''.stripIndent() } @@ -241,10 +241,10 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() def 'apply transformers to project resources'() { given: File one = buildJar('one.jar').insertFile('META-INF/services/shadow.Shadow', - 'one # NOTE: No newline terminates this line/file').write() + 'one # NOTE: No newline terminates this line/file').write() repo.module('shadow', 'two', '1.0').insertFile('META-INF/services/shadow.Shadow', - 'two # NOTE: No newline terminates this line/file').publish() + 'two # NOTE: No newline terminates this line/file').publish() buildFile << """ dependencies { @@ -258,7 +258,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() """.stripIndent() file('src/main/resources/META-INF/services/shadow.Shadow') << - 'three # NOTE: No newline terminates this line/file' + 'three # NOTE: No newline terminates this line/file' when: run('shadowJar') @@ -270,7 +270,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() String text = getJarFileContents(output, 'META-INF/services/shadow.Shadow') assert text.split("\\r?\\n").size() == 3 assert text == -'''three # NOTE: No newline terminates this line/file + '''three # NOTE: No newline terminates this line/file one # NOTE: No newline terminates this line/file two # NOTE: No newline terminates this line/file'''.stripIndent() } @@ -278,10 +278,10 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() def 'appending transformer'() { given: File one = buildJar('one.jar').insertFile('test.properties', - 'one # NOTE: No newline terminates this line/file').write() + 'one # NOTE: No newline terminates this line/file').write() File two = buildJar('two.jar').insertFile('test.properties', - 'two # NOTE: No newline terminates this line/file').write() + 'two # NOTE: No newline terminates this line/file').write() buildFile << """ import ${AppendingTransformer.name} @@ -306,7 +306,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() String text = getJarFileContents(output, 'test.properties') assert text.split("\\r?\\n").size() == 2 assert text == -'''one # NOTE: No newline terminates this line/file + '''one # NOTE: No newline terminates this line/file two # NOTE: No newline terminates this line/file '''.stripIndent() } @@ -314,10 +314,10 @@ two # NOTE: No newline terminates this line/file def 'appending transformer short syntax'() { given: File one = buildJar('one.jar').insertFile('test.properties', - 'one # NOTE: No newline terminates this line/file').write() + 'one # NOTE: No newline terminates this line/file').write() File two = buildJar('two.jar').insertFile('test.properties', - 'two # NOTE: No newline terminates this line/file').write() + 'two # NOTE: No newline terminates this line/file').write() buildFile << """ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { @@ -339,7 +339,7 @@ two # NOTE: No newline terminates this line/file String text = getJarFileContents(output, 'test.properties') assert text.split("\\r?\\n").size() == 2 assert text == -'''one # NOTE: No newline terminates this line/file + '''one # NOTE: No newline terminates this line/file two # NOTE: No newline terminates this line/file '''.stripIndent() } @@ -429,7 +429,7 @@ two # NOTE: No newline terminates this line/file def 'append xml files'() { given: File xml1 = buildJar('xml1.jar').insertFile('properties.xml', -''' + ''' val1 @@ -438,7 +438,7 @@ two # NOTE: No newline terminates this line/file ).write() File xml2 = buildJar('xml2.jar').insertFile('properties.xml', -''' + ''' val2 @@ -470,7 +470,7 @@ two # NOTE: No newline terminates this line/file and: String text = getJarFileContents(output, 'properties.xml') assert text.replaceAll('\r\n', '\n') == -''' + ''' val1 @@ -601,21 +601,21 @@ two # NOTE: No newline terminates this line/file def 'Groovy extension module transformer'() { given: - def one = buildJar('one.jar') - .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', -'''moduleName=foo + def one = buildJar('one.jar') + .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', + '''moduleName=foo moduleVersion=1.0.5 extensionClasses=com.acme.foo.FooExtension,com.acme.foo.BarExtension staticExtensionClasses=com.acme.foo.FooStaticExtension'''.stripIndent()).write() - def two = buildJar('two.jar') - .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', -'''moduleName=bar + def two = buildJar('two.jar') + .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', + '''moduleName=bar moduleVersion=2.3.5 extensionClasses=com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write() - buildFile << """ + buildFile << """ import ${GroovyExtensionModuleTransformer.name} tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { from('${escapedPath(one)}') @@ -628,38 +628,38 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( """.stripIndent() when: - run('shadowJar') + run('shadowJar') then: - assert output.exists() + assert output.exists() and: - def text = getJarFileContents(output, 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule') - def props = new Properties() - props.load(new StringReader(text)) - assert props.getProperty('moduleName') == 'MergedByShadowJar' - assert props.getProperty('moduleVersion') == '1.0.0' - assert props.getProperty('extensionClasses') == 'com.acme.foo.FooExtension,com.acme.foo.BarExtension,com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension' - assert props.getProperty('staticExtensionClasses') == 'com.acme.foo.FooStaticExtension,com.acme.bar.SomeStaticExtension' + def text = getJarFileContents(output, 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule') + def props = new Properties() + props.load(new StringReader(text)) + assert props.getProperty('moduleName') == 'MergedByShadowJar' + assert props.getProperty('moduleVersion') == '1.0.0' + assert props.getProperty('extensionClasses') == 'com.acme.foo.FooExtension,com.acme.foo.BarExtension,com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension' + assert props.getProperty('staticExtensionClasses') == 'com.acme.foo.FooStaticExtension,com.acme.bar.SomeStaticExtension' } def 'Groovy extension module transformer works for Groovy2_5+'() { given: - def one = buildJar('one.jar') - .insertFile('META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule', -'''moduleName=foo + def one = buildJar('one.jar') + .insertFile('META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule', + '''moduleName=foo moduleVersion=1.0.5 extensionClasses=com.acme.foo.FooExtension,com.acme.foo.BarExtension staticExtensionClasses=com.acme.foo.FooStaticExtension'''.stripIndent()).write() - def two = buildJar('two.jar') - .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', -'''moduleName=bar + def two = buildJar('two.jar') + .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', + '''moduleName=bar moduleVersion=2.3.5 extensionClasses=com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write() - buildFile << """ + buildFile << """ import ${GroovyExtensionModuleTransformer.name} tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { from('${escapedPath(one)}') @@ -672,39 +672,39 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( """.stripIndent() when: - run('shadowJar') + run('shadowJar') then: - output.exists() + output.exists() and: - def text = getJarFileContents(output, 'META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule') - def props = new Properties() - props.load(new StringReader(text)) - props.getProperty('moduleName') == 'MergedByShadowJar' - props.getProperty('moduleVersion') == '1.0.0' - props.getProperty('extensionClasses') == 'com.acme.foo.FooExtension,com.acme.foo.BarExtension,com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension' - props.getProperty('staticExtensionClasses') == 'com.acme.foo.FooStaticExtension,com.acme.bar.SomeStaticExtension' - doesNotContain(output, ['META-INF/services/org.codehaus.groovy.runtime.ExtensionModule']) + def text = getJarFileContents(output, 'META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule') + def props = new Properties() + props.load(new StringReader(text)) + props.getProperty('moduleName') == 'MergedByShadowJar' + props.getProperty('moduleVersion') == '1.0.0' + props.getProperty('extensionClasses') == 'com.acme.foo.FooExtension,com.acme.foo.BarExtension,com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension' + props.getProperty('staticExtensionClasses') == 'com.acme.foo.FooStaticExtension,com.acme.bar.SomeStaticExtension' + doesNotContain(output, ['META-INF/services/org.codehaus.groovy.runtime.ExtensionModule']) } def 'Groovy extension module transformer short syntax'() { given: - def one = buildJar('one.jar') - .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', -'''moduleName=foo + def one = buildJar('one.jar') + .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', + '''moduleName=foo moduleVersion=1.0.5 extensionClasses=com.acme.foo.FooExtension,com.acme.foo.BarExtension staticExtensionClasses=com.acme.foo.FooStaticExtension'''.stripIndent()).write() - def two = buildJar('two.jar') - .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', -'''moduleName=bar + def two = buildJar('two.jar') + .insertFile('META-INF/services/org.codehaus.groovy.runtime.ExtensionModule', + '''moduleName=bar moduleVersion=2.3.5 extensionClasses=com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write() - buildFile << """ + buildFile << """ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { from('${escapedPath(one)}') from('${escapedPath(two)}') @@ -715,19 +715,19 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( """.stripIndent() when: - run('shadowJar') + run('shadowJar') then: - assert output.exists() + assert output.exists() and: - def text = getJarFileContents(output, 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule') - def props = new Properties() - props.load(new StringReader(text)) - assert props.getProperty('moduleName') == 'MergedByShadowJar' - assert props.getProperty('moduleVersion') == '1.0.0' - assert props.getProperty('extensionClasses') == 'com.acme.foo.FooExtension,com.acme.foo.BarExtension,com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension' - assert props.getProperty('staticExtensionClasses') == 'com.acme.foo.FooStaticExtension,com.acme.bar.SomeStaticExtension' + def text = getJarFileContents(output, 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule') + def props = new Properties() + props.load(new StringReader(text)) + assert props.getProperty('moduleName') == 'MergedByShadowJar' + assert props.getProperty('moduleVersion') == '1.0.0' + assert props.getProperty('extensionClasses') == 'com.acme.foo.FooExtension,com.acme.foo.BarExtension,com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension' + assert props.getProperty('staticExtensionClasses') == 'com.acme.foo.FooStaticExtension,com.acme.bar.SomeStaticExtension' } @Unroll diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy index d0e5e1cb6..3c0ed8c9b 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy @@ -12,7 +12,8 @@ import static org.gradle.testkit.runner.TaskOutcome.FROM_CACHE import static org.gradle.testkit.runner.TaskOutcome.SUCCESS abstract class AbstractCachingSpec extends PluginSpecification { - @TempDir Path alternateDir + @TempDir + Path alternateDir @Override def setup() { @@ -33,13 +34,13 @@ abstract class AbstractCachingSpec extends PluginSpecification { } BuildResult runWithCacheEnabled(String... arguments) { - List cacheArguments = [ '--build-cache' ] + List cacheArguments = ['--build-cache'] cacheArguments.addAll(arguments) return run(cacheArguments) } BuildResult runInAlternateDirWithCacheEnabled(String... arguments) { - List cacheArguments = [ '--build-cache' ] + List cacheArguments = ['--build-cache'] cacheArguments.addAll(arguments) // TODO: Use PluginSpecification.run here to reuse flags, but cache tests failed for now, need to investigate. return runner.withProjectDir(alternateDir.toFile()).withArguments(cacheArguments).build() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy index 013c8c936..460fcc108 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/MinimizationCachingSpec.groovy @@ -45,9 +45,9 @@ class MinimizationCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'junit/framework/Test.class', - 'client/Client.class' + 'server/Server.class', + 'junit/framework/Test.class', + 'client/Client.class' ]) when: @@ -69,8 +69,8 @@ class MinimizationCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'junit/framework/Test.class' + 'server/Server.class', + 'junit/framework/Test.class' ]) doesNotContain(output, ['client/Client.class']) @@ -80,8 +80,8 @@ class MinimizationCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'junit/framework/Test.class' + 'server/Server.class', + 'junit/framework/Test.class' ]) doesNotContain(output, ['client/Client.class']) } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/RelocationCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/RelocationCachingSpec.groovy index c0a75c537..9a43e7270 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/RelocationCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/RelocationCachingSpec.groovy @@ -24,8 +24,8 @@ class RelocationCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'junit/framework/Test.class' + 'server/Server.class', + 'junit/framework/Test.class' ]) when: @@ -41,13 +41,13 @@ class RelocationCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/junit/framework/Test.class' + 'server/Server.class', + 'foo/junit/framework/Test.class' ]) and: doesNotContain(output, [ - 'junit/framework/Test.class' + 'junit/framework/Test.class' ]) when: @@ -56,13 +56,13 @@ class RelocationCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/junit/framework/Test.class' + 'server/Server.class', + 'foo/junit/framework/Test.class' ]) and: doesNotContain(output, [ - 'junit/framework/Test.class' + 'junit/framework/Test.class' ]) } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/ShadowJarCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/ShadowJarCachingSpec.groovy index 0d6a2d741..def98418c 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/ShadowJarCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/ShadowJarCachingSpec.groovy @@ -84,7 +84,7 @@ class ShadowJarCachingSpec extends AbstractCachingSpec { given: buildFile << """ dependencies { implementation 'junit:junit:3.8.2' } - + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { exclude 'junit/*' } @@ -112,8 +112,8 @@ class ShadowJarCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'server/Util.class' + 'server/Server.class', + 'server/Util.class' ]) when: @@ -130,13 +130,13 @@ class ShadowJarCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) and: doesNotContain(output, [ - 'server/Util.class', - 'junit/framework/Test.class' + 'server/Util.class', + 'junit/framework/Test.class' ]) when: @@ -145,13 +145,13 @@ class ShadowJarCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) and: doesNotContain(output, [ - 'server/Util.class', - 'junit/framework/Test.class' + 'server/Util.class', + 'junit/framework/Test.class' ]) } @@ -178,8 +178,8 @@ class ShadowJarCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'junit/framework/Test.class' + 'server/Server.class', + 'junit/framework/Test.class' ]) when: @@ -197,12 +197,12 @@ class ShadowJarCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) and: doesNotContain(output, [ - 'junit/framework/Test.class' + 'junit/framework/Test.class' ]) when: @@ -211,12 +211,12 @@ class ShadowJarCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) and: doesNotContain(output, [ - 'junit/framework/Test.class' + 'junit/framework/Test.class' ]) } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/TransformCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/TransformCachingSpec.groovy index 93cf1477a..a8507c9af 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/TransformCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/TransformCachingSpec.groovy @@ -23,26 +23,26 @@ class TransformCachingSpec extends AbstractCachingSpec { import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement - + class CustomTransformer implements Transformer { @Override boolean canTransformResource(FileTreeElement element) { return false } - + @Override void transform(TransformerContext context) { - + } - + @Override boolean hasTransformedResource() { return false } - + @Override void modifyOutputStream(ZipOutputStream jos, boolean preserveFileTimestamps) { - + } } @@ -58,7 +58,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -67,7 +67,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) } @@ -89,7 +89,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -106,7 +106,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -115,7 +115,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -132,7 +132,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -141,7 +141,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) } @@ -164,7 +164,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -181,8 +181,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/bar.properties' + 'server/Server.class', + 'foo/bar.properties' ]) when: @@ -191,8 +191,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/bar.properties' + 'server/Server.class', + 'foo/bar.properties' ]) when: @@ -211,8 +211,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/baz.properties' + 'server/Server.class', + 'foo/baz.properties' ]) when: @@ -221,8 +221,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/baz.properties' + 'server/Server.class', + 'foo/baz.properties' ]) } @@ -245,7 +245,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -262,8 +262,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/bar.xml' + 'server/Server.class', + 'foo/bar.xml' ]) when: @@ -272,8 +272,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/bar.xml' + 'server/Server.class', + 'foo/bar.xml' ]) when: @@ -292,8 +292,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/baz.xml' + 'server/Server.class', + 'foo/baz.xml' ]) when: @@ -302,8 +302,8 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class', - 'foo/baz.xml' + 'server/Server.class', + 'foo/baz.xml' ]) } @@ -325,7 +325,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -340,7 +340,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) when: @@ -349,7 +349,7 @@ class TransformCachingSpec extends AbstractCachingSpec { then: output.exists() contains(output, [ - 'server/Server.class' + 'server/Server.class' ]) } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy index 4ee13e69f..b937059aa 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy @@ -17,9 +17,9 @@ import java.nio.file.Path class ManualCodeSnippetTests { public static final LinkedHashMap FIXTURES = [ - "groovy": new GradleBuildExecuter("build.gradle", new GroovyDslFixture(), new GroovyDslFixture.ImportsExtractor()), - "groovy no-plugins": new GradleBuildExecuter("build.gradle", new GroovyScriptFixture(), new GroovyDslFixture.ImportsExtractor()), - "groovy no-run": new NoopExecuter() + "groovy" : new GradleBuildExecuter("build.gradle", new GroovyDslFixture(), new GroovyDslFixture.ImportsExtractor()), + "groovy no-plugins": new GradleBuildExecuter("build.gradle", new GroovyScriptFixture(), new GroovyDslFixture.ImportsExtractor()), + "groovy no-run" : new NoopExecuter() ] @Disabled("We have to run doc tests on main branch only") diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy index 99d84ca20..7f1f85aa1 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy @@ -26,7 +26,7 @@ class ManualSnippetExtractor { private static void addSnippets(Path tempDir, List snippets, File file, Pattern snippetBlockPattern, SnippetExecuter executer) { def source = file.text - String testName = file.parentFile.name + "/" +file.name + String testName = file.parentFile.name + "/" + file.name Map snippetsByLine = findSnippetsByLine(source, snippetBlockPattern) snippetsByLine.each { lineNumber, snippet -> diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java index 6be5676e3..133d8cdf4 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java @@ -2,10 +2,10 @@ public interface Block { - /** - * Execute the action. - * - * @throws Exception any - */ - void execute() throws Exception; -} \ No newline at end of file + /** + * Execute the action. + * + * @throws Exception any + */ + void execute() throws Exception; +} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java index e3539c1cb..50ad397ab 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java @@ -2,6 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.ExceptionTransformer; import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.SnippetExecuter; + import org.junit.jupiter.api.function.Executable; import java.nio.file.Path; diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java index 90768b3f3..eeab7a2d4 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java @@ -2,17 +2,17 @@ public class CompileException extends RuntimeException { - private static final long serialVersionUID = 0; + private static final long serialVersionUID = 0; - private final int lineNo; + private final int lineNo; - public CompileException(Throwable cause, int lineNo) { - super(cause); - this.lineNo = lineNo; - } + public CompileException(Throwable cause, int lineNo) { + super(cause); + this.lineNo = lineNo; + } - public int getLineNo() { - return lineNo; - } + public int getLineNo() { + return lineNo; + } -} \ No newline at end of file +} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy index cee765c2c..15331d0ef 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy @@ -2,38 +2,38 @@ package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.execut class ExceptionTransformer { - final String sourceClassName - final String sourceFileName - final Integer lineNumber + final String sourceClassName + final String sourceFileName + final Integer lineNumber - ExceptionTransformer(String sourceClassName, String sourceFileName, Integer lineNumber) { - this.sourceClassName = sourceClassName - this.sourceFileName = sourceFileName - this.lineNumber = lineNumber - } + ExceptionTransformer(String sourceClassName, String sourceFileName, Integer lineNumber) { + this.sourceClassName = sourceClassName + this.sourceFileName = sourceFileName + this.lineNumber = lineNumber + } - Throwable transform(Throwable throwable, Integer offset) throws Exception { - def errorLine = 0 + Throwable transform(Throwable throwable, Integer offset) throws Exception { + def errorLine = 0 - if (throwable instanceof CompileException) { - errorLine = throwable.lineNo - } else { - def frame = throwable.getStackTrace().find { it.fileName == sourceClassName } - if (frame) { - errorLine = frame.lineNumber - } else { - frame = throwable.getStackTrace().find { it.fileName == "Example.java" } - if (frame) { - errorLine = frame.lineNumber + if (throwable instanceof CompileException) { + errorLine = throwable.lineNo + } else { + def frame = throwable.getStackTrace().find { it.fileName == sourceClassName } + if (frame) { + errorLine = frame.lineNumber + } else { + frame = throwable.getStackTrace().find { it.fileName == "Example.java" } + if (frame) { + errorLine = frame.lineNumber + } + } } - } + errorLine = errorLine - offset + StackTraceElement[] stack = throwable.getStackTrace() + List newStack = new ArrayList(stack.length + 1) + newStack.add(new StackTraceElement(sourceClassName, "javadoc", sourceFileName, lineNumber + errorLine)) + newStack.addAll(stack) + throwable.setStackTrace(newStack as StackTraceElement[]) + throwable } - errorLine = errorLine - offset - StackTraceElement[] stack = throwable.getStackTrace() - List newStack = new ArrayList(stack.length + 1) - newStack.add(new StackTraceElement(sourceClassName, "javadoc", sourceFileName, lineNumber + errorLine)) - newStack.addAll(stack) - throwable.setStackTrace(newStack as StackTraceElement[]) - throwable - } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java index 1276fb9ae..a78fc8ab8 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java @@ -1,14 +1,14 @@ package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer; -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.SnippetFixture; import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.TestCodeSnippet; +import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.SnippetFixture; import java.io.File; public interface SnippetExecuter { - SnippetFixture getFixture(); + SnippetFixture getFixture(); - void execute(File tempDir, TestCodeSnippet snippet) throws Exception; + void execute(File tempDir, TestCodeSnippet snippet) throws Exception; } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy index deff8e9f0..04fdccd67 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy @@ -2,9 +2,9 @@ package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixtur class GroovyScriptFixture extends SnippetFixture { - @Override - String post() { - "\n;0;" - } + @Override + String post() { + "\n;0;" + } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java index b59402d40..cf29db97c 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java @@ -4,24 +4,24 @@ public class SnippetFixture { - public void around(Block action) throws Exception { - action.execute(); - } + public void around(Block action) throws Exception { + action.execute(); + } - public String transform(String text) { - return text; - } + public String transform(String text) { + return text; + } - public String pre() { - return ""; - } + public String pre() { + return ""; + } - public String post() { - return ""; - } + public String post() { + return ""; + } - public Integer getOffset() { - return pre().split("\n").length; - } + public Integer getOffset() { + return pre().split("\n").length; + } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorParameterTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorParameterTest.groovy index c757308e9..87a8ea0e2 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorParameterTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorParameterTest.groovy @@ -21,7 +21,7 @@ package com.github.jengelman.gradle.plugins.shadow.relocation import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.fail /** diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.groovy index 18c7911ab..ba04bfb51 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.groovy @@ -23,7 +23,7 @@ import com.github.jengelman.gradle.plugins.shadow.ShadowStats import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.assertEquals /** * Test for {@link SimpleRelocator}. @@ -42,7 +42,7 @@ class SimpleRelocatorTest { @BeforeEach void setUp() { - stats = new ShadowStats() + stats = new ShadowStats() } @Test @@ -64,7 +64,7 @@ class SimpleRelocatorTest { assertEquals(false, relocator.canRelocatePath("/org/Foo/Class.class")) relocator = new SimpleRelocator("org.foo", null, null, Arrays.asList( - [ "org.foo.Excluded", "org.foo.public.*", "org.foo.recurse.**", "org.foo.Public*Stuff" ] as String[])) + ["org.foo.Excluded", "org.foo.public.*", "org.foo.recurse.**", "org.foo.Public*Stuff"] as String[])) assertEquals(true, relocator.canRelocatePath("org/foo/Class")) assertEquals(true, relocator.canRelocatePath("org/foo/Class.class")) assertEquals(true, relocator.canRelocatePath("org/foo/excluded")) @@ -99,8 +99,8 @@ class SimpleRelocatorTest { assertEquals(true, relocator.canRelocatePath("/org/f")) // equal to path pattern with / } - @Test - void testCanRelocatePathWithRegex() { + @Test + void testCanRelocatePathWithRegex() { SimpleRelocator relocator // Include with Regex @@ -126,12 +126,12 @@ class SimpleRelocatorTest { // Include with Regex and normal pattern relocator = new SimpleRelocator("org.foo", null, - Arrays.asList("%regex[org/foo/.*Factory[0-9].*]", "org.foo.public.*"), null) + Arrays.asList("%regex[org/foo/.*Factory[0-9].*]", "org.foo.public.*"), null) assertEquals(true, relocator.canRelocatePath("org/foo/Factory1.class")) assertEquals(true, relocator.canRelocatePath("org/foo/public/Bar.class")) assertEquals(false, relocator.canRelocatePath("org/foo/Factory.class")) assertEquals(false, relocator.canRelocatePath("org/foo/R.class")) - } + } @Test void testCanRelocateClass() { @@ -144,7 +144,7 @@ class SimpleRelocatorTest { assertEquals(false, relocator.canRelocateClass("org.Foo.Class")) relocator = new SimpleRelocator("org.foo", null, null, Arrays.asList( - [ "org.foo.Excluded", "org.foo.public.*", "org.foo.recurse.**", "org.foo.Public*Stuff" ] as String[])) + ["org.foo.Excluded", "org.foo.public.*", "org.foo.recurse.**", "org.foo.Public*Stuff"] as String[])) assertEquals(true, relocator.canRelocateClass("org.foo.Class")) assertEquals(true, relocator.canRelocateClass("org.foo.excluded")) assertEquals(false, relocator.canRelocateClass("org.foo.Excluded")) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.groovy index 59a6c62dc..bd2a7b04c 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.groovy @@ -22,7 +22,8 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.assertFalse +import static org.junit.jupiter.api.Assertions.assertTrue /** * Test for {@link ApacheLicenseResourceTransformer}. diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy index dce305c9d..221bdeb9b 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerParameterTests.groovy @@ -24,7 +24,7 @@ import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.fail /** * Tests {@link ApacheLicenseResourceTransformer} parameters. diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.groovy index 65778420c..0b2646aa8 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.groovy @@ -22,7 +22,8 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.assertFalse +import static org.junit.jupiter.api.Assertions.assertTrue /** * Test for {@link ApacheNoticeResourceTransformer}. diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.groovy index 3797bc85a..dc18c3611 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.groovy @@ -22,7 +22,8 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.assertFalse +import static org.junit.jupiter.api.Assertions.assertTrue /** * Test for {@link AppendingTransformer}. diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.groovy index b62fd1bc8..aac341cbd 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.groovy @@ -20,12 +20,11 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import com.github.jengelman.gradle.plugins.shadow.ShadowStats - +import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator +import org.codehaus.plexus.util.IOUtil import org.custommonkey.xmlunit.Diff import org.custommonkey.xmlunit.XMLAssert import org.custommonkey.xmlunit.XMLUnit -import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator -import org.codehaus.plexus.util.IOUtil import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -52,22 +51,22 @@ class ComponentsXmlResourceTransformerTest extends TransformerTestSupport emptyList()) - .stats(stats) - .build()) + TransformerContext.builder() + .path("components-1.xml") + .is(getClass().getResourceAsStream("/components-1.xml")) + .relocators(Collections. emptyList()) + .stats(stats) + .build()) transformer.transform( - TransformerContext.builder() - .path("components-1.xml") - .is(getClass().getResourceAsStream("/components-2.xml")) - .relocators(Collections. emptyList()) - .stats(stats) - .build()) + TransformerContext.builder() + .path("components-1.xml") + .is(getClass().getResourceAsStream("/components-2.xml")) + .relocators(Collections. emptyList()) + .stats(stats) + .build()) Diff diff = XMLUnit.compareXML( - IOUtil.toString(getClass().getResourceAsStream("/components-expected.xml"), "UTF-8"), - IOUtil.toString(transformer.getTransformedResource(), "UTF-8")) + IOUtil.toString(getClass().getResourceAsStream("/components-expected.xml"), "UTF-8"), + IOUtil.toString(transformer.getTransformedResource(), "UTF-8")) //assertEquals( IOUtil.toString( getClass().getResourceAsStream( "/components-expected.xml" ), "UTF-8" ), // IOUtil.toString( transformer.getTransformedResource(), "UTF-8" ).replaceAll("\r\n", "\n") ) XMLAssert.assertXMLIdentical(diff, true) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy index becdaf25e..a9659a85e 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy @@ -7,7 +7,6 @@ import org.apache.logging.log4j.core.config.plugins.processor.PluginCache import org.apache.tools.zip.ZipOutputStream import spock.lang.Specification - import static java.util.Collections.singletonList import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.groovy index b99a4fb39..1da4856ae 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.groovy @@ -72,7 +72,7 @@ class ManifestAppenderTransformerTest extends TransformerTestSupportemptyList(), new ShadowStats())) + transform(new TransformerContext(MANIFEST_NAME, getResourceStream(MANIFEST_NAME), Collections. emptyList(), new ShadowStats())) } def testableZipFile = File.createTempFile("testable-zip-file-", ".jar") @@ -104,7 +104,7 @@ class ManifestAppenderTransformerTest extends TransformerTestSupportemptyList(), new ShadowStats())) + transformer.transform(new TransformerContext(MANIFEST_NAME, getResourceStream(MANIFEST_NAME), Collections. emptyList(), new ShadowStats())) def testableZipFile = File.createTempFile("testable-zip-file-", ".jar") def fileOutputStream = new FileOutputStream(testableZipFile) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy index 333048ac4..578d4a1df 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy @@ -158,7 +158,7 @@ class PropertiesFileTransformerSpec extends TransformerSpecSupport { output == toMap(transformer.propertiesEntries[path]) where: - path | charset | input || output - 'utf8.properties' | 'utf-8' | ['foo': '传傳磨宿说説'] || ['foo': '传傳磨宿说説'] + path | charset | input || output + 'utf8.properties' | 'utf-8' | ['foo': '传傳磨宿说説'] || ['foo': '传傳磨宿说説'] } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy index 2d186a00e..c322029ad 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy @@ -35,7 +35,7 @@ final class PropertiesFileTransformerTest extends TransformerTestSupportemptyList(), new ShadowStats())) + transformer.transform(new TransformerContext(MANIFEST_NAME, getResourceStream(MANIFEST_NAME), Collections. emptyList(), new ShadowStats())) def testableZipFile = doTransformAndGetTransformedFile(transformer, false) def targetLines = readFrom(testableZipFile, MANIFEST_NAME) @@ -47,7 +47,7 @@ final class PropertiesFileTransformerTest extends TransformerTestSupportemptyList(), new ShadowStats())) + transformer.transform(new TransformerContext(MANIFEST_NAME, getResourceStream(MANIFEST_NAME), Collections. emptyList(), new ShadowStats())) def firstRunTransformedFile = doTransformAndGetTransformedFile(transformer, true) def firstRunTargetLines = readFrom(firstRunTransformedFile, MANIFEST_NAME) @@ -60,7 +60,7 @@ final class PropertiesFileTransformerTest extends TransformerTestSupport tasks) { @@ -93,7 +94,7 @@ abstract class PluginSpecification extends Specification { static boolean containsDeprecationWarning(String output) { output.contains("has been deprecated and is scheduled to be removed in Gradle") || - output.contains("has been deprecated. This is scheduled to be removed in Gradle") + output.contains("has been deprecated. This is scheduled to be removed in Gradle") } File getBuildFile() { diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFile.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFile.java index c18966cda..90ce4ecf4 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFile.java +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFile.java @@ -16,7 +16,11 @@ package com.github.jengelman.gradle.plugins.shadow.util.file; -import groovy.lang.Closure; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.apache.commons.io.FileUtils; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; @@ -25,17 +29,29 @@ import org.apache.tools.ant.types.EnumeratedAttribute; import org.codehaus.groovy.runtime.ResourceGroovyMethods; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectStreamException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.Charset; import java.security.MessageDigest; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Formatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; import java.util.jar.JarFile; import java.util.jar.Manifest; -import static org.junit.jupiter.api.Assertions.*; +import groovy.lang.Closure; public class TestFile extends File { private boolean useNativeTools; @@ -203,7 +219,7 @@ public void copyTo(File target) { FileUtils.copyDirectory(this, target); } catch (IOException e) { throw new RuntimeException(String.format("Could not copy test directory '%s' to '%s'", this, - target), e); + target), e); } } else { try { @@ -394,7 +410,7 @@ public TestFile createDir() { return this; } throw new AssertionError("Problems creating dir: " + this - + ". Diagnostics: exists=" + this.exists() + ", isFile=" + this.isFile() + ", isDirectory=" + this.isDirectory()); + + ". Diagnostics: exists=" + this.exists() + ", isFile=" + this.isFile() + ", isDirectory=" + this.isDirectory()); } public TestFile createDir(Object path) { @@ -408,6 +424,7 @@ public TestFile deleteDir() { /** * Attempts to delete this directory, ignoring failures to do so. + * * @return this */ public TestFile maybeDeleteDir() { @@ -444,7 +461,7 @@ public TestFile createZip(Object path) { return zipFile; } - public TestFile zipTo(TestFile zipFile){ + public TestFile zipTo(TestFile zipFile) { new TestFileHelper(this).zipTo(zipFile, useNativeTools); return this; } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFileHelper.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFileHelper.groovy index c9c9db88f..414f09132 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFileHelper.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestFileHelper.groovy @@ -10,7 +10,7 @@ import org.apache.tools.ant.taskdefs.Zip import java.util.zip.ZipInputStream -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.assertTrue class TestFileHelper { TestFile file @@ -21,7 +21,7 @@ class TestFileHelper { void unzipTo(File target, boolean nativeTools) { // Check that each directory in hierarchy is present - file.withInputStream {InputStream instr -> + file.withInputStream { InputStream instr -> def dirs = [] as Set def zipStr = new ZipInputStream(instr) def entry diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestWorkspaceBuilder.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestWorkspaceBuilder.groovy index 34ca1ff23..2af22f3e9 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestWorkspaceBuilder.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/file/TestWorkspaceBuilder.groovy @@ -31,8 +31,7 @@ class TestWorkspaceBuilder { def methodMissing(String name, Object args) { if (args.length == 1 && args[0] instanceof Closure) { baseDir.file(name).create(args[0]) - } - else { + } else { throw new MissingMethodException(name, getClass(), args) } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/AbstractMavenModule.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/AbstractMavenModule.groovy index c9aa10403..16a2fffd6 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/AbstractMavenModule.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/AbstractMavenModule.groovy @@ -4,6 +4,7 @@ import com.github.jengelman.gradle.plugins.shadow.util.file.TestFile import com.github.jengelman.gradle.plugins.shadow.util.repo.AbstractModule import groovy.xml.MarkupBuilder import groovy.xml.XmlParser + import java.text.SimpleDateFormat abstract class AbstractMavenModule extends AbstractModule implements MavenModule { @@ -166,7 +167,7 @@ abstract class AbstractMavenModule extends AbstractModule implements MavenModule for (name in artifactNames) { assert actual.remove(name) - if(publishesHashFiles()) { + if (publishesHashFiles()) { assert actual.remove("${name}.md5" as String) assert actual.remove("${name}.sha1" as String) } @@ -299,7 +300,7 @@ abstract class AbstractMavenModule extends AbstractModule implements MavenModule } } else { versions { - allVersions.each {currVersion -> + allVersions.each { currVersion -> version(currVersion) } } @@ -339,5 +340,6 @@ abstract class AbstractMavenModule extends AbstractModule implements MavenModule } protected abstract boolean publishesMetaDataFile() + protected abstract boolean publishesHashFiles() } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/DefaultMavenMetaData.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/DefaultMavenMetaData.groovy index ab2ab217f..bccdb40f1 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/DefaultMavenMetaData.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/DefaultMavenMetaData.groovy @@ -5,7 +5,7 @@ import groovy.xml.XmlParser /** * http://maven.apache.org/ref/3.0.1/maven-repository-metadata/repository-metadata.html */ -class DefaultMavenMetaData implements MavenMetaData{ +class DefaultMavenMetaData implements MavenMetaData { String text diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenPom.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenPom.groovy index 4838f4ab8..9aa3d1ba4 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenPom.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/repo/maven/MavenPom.groovy @@ -11,7 +11,7 @@ class MavenPom { final Map scopes = [:] MavenPom(File pomFile) { - if (pomFile.exists()){ + if (pomFile.exists()) { def pom = new XmlParser().parse(pomFile) groupId = pom.groupId[0]?.text() @@ -29,11 +29,11 @@ class MavenPom { scopes[scopeName] = scope } MavenDependency mavenDependency = new MavenDependency( - groupId: dep.groupId.text(), - artifactId: dep.artifactId.text(), - version: dep.version.text(), - classifier: dep.classifier ? dep.classifier.text() : null, - type: dep.type ? dep.type.text() : null + groupId: dep.groupId.text(), + artifactId: dep.artifactId.text(), + version: dep.version.text(), + classifier: dep.classifier ? dep.classifier.text() : null, + type: dep.type ? dep.type.text() : null ) def key = "${mavenDependency.groupId}:${mavenDependency.artifactId}:${mavenDependency.version}" key += mavenDependency.classifier ? ":${mavenDependency.classifier}" : "" From ff07ac17a2b36cd3368c59b502d41bd19d5e0f9d Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 16 Sep 2025 16:14:54 +0800 Subject: [PATCH 40/72] Stop using start script templates bundled in Shadow (#1750) * Remove `unixStartScriptGenerator` and `windowsStartScriptGenerator` overrides * Update changelog * Fix tests --- src/docs/changes/README.md | 4 + .../shadow/ShadowApplicationPlugin.groovy | 2 - .../shadow/internal/unixStartScript.txt | 183 ------------------ .../shadow/internal/windowsStartScript.txt | 85 -------- .../plugins/shadow/ApplicationSpec.groovy | 2 - 5 files changed, 4 insertions(+), 272 deletions(-) delete mode 100644 src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/unixStartScript.txt delete mode 100644 src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/windowsStartScript.txt diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 5f244b493..cfba8f9bd 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,10 @@ ## [Unreleased] +**Changed** + +- Stop using start script templates bundled in Shadow. ([#1750](https://github.com/GradleUp/shadow/pull/1750)) + **Fixed** - Fix resolving BOM dependencies when `minimize` is enabled. ([#1638](https://github.com/GradleUp/shadow/pull/1638)) 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 4b403b586..9fdc54bc8 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 @@ -79,8 +79,6 @@ class ShadowApplicationPlugin implements Plugin { protected void addCreateScriptsTask(Project project) { project.tasks.register(SHADOW_SCRIPTS_TASK_NAME, CreateStartScripts) { startScripts -> - startScripts.unixStartScriptGenerator.template = project.resources.text.fromString(this.class.getResource("internal/unixStartScript.txt").text) - startScripts.windowsStartScriptGenerator.template = project.resources.text.fromString(this.class.getResource("internal/windowsStartScript.txt").text) startScripts.description = 'Creates OS specific scripts to run the project as a JVM application using the shadow jar' startScripts.group = ApplicationPlugin.APPLICATION_GROUP startScripts.classpath = project.files(jar) diff --git a/src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/unixStartScript.txt b/src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/unixStartScript.txt deleted file mode 100644 index 83526b7f4..000000000 --- a/src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/unixStartScript.txt +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## ${applicationName} start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: \$0 may be a link -PRG="\$0" -# Need this for relative symlinks. -while [ -h "\$PRG" ] ; do - ls=`ls -ld "\$PRG"` - link=`expr "\$ls" : '.*-> \\(.*\\)\$'` - if expr "\$link" : '/.*' > /dev/null; then - PRG="\$link" - else - PRG=`dirname "\$PRG"`"/\$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"\$PRG\"`/${appHomeRelativePath}" >/dev/null -APP_HOME="`pwd -P`" -cd "\$SAVED" >/dev/null - -APP_NAME="${applicationName}" -APP_BASE_NAME=`basename "\$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script. -DEFAULT_JVM_OPTS=${defaultJvmOpts} - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "\$*" -} - -die () { - echo - echo "\$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$classpath - -# Determine the Java command to use to start the JVM. -if [ -n "\$JAVA_HOME" ] ; then - if [ -x "\$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="\$JAVA_HOME/jre/sh/java" - else - JAVACMD="\$JAVA_HOME/bin/java" - fi - if [ ! -x "\$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: \$JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "\$cygwin" = "false" -a "\$darwin" = "false" -a "\$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ \$? -eq 0 ] ; then - if [ "\$MAX_FD" = "maximum" -o "\$MAX_FD" = "max" ] ; then - MAX_FD="\$MAX_FD_LIMIT" - fi - ulimit -n \$MAX_FD - if [ \$? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: \$MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: \$MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if \$darwin; then - GRADLE_OPTS="\$GRADLE_OPTS \\"-Xdock:name=\$APP_NAME\\" \\"-Xdock:icon=\$APP_HOME/media/gradle.icns\\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "\$cygwin" = "true" -o "\$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "\$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "\$CLASSPATH"` - JAVACMD=`cygpath --unix "\$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in \$ROOTDIRSRAW ; do - ROOTDIRS="\$ROOTDIRS\$SEP\$dir" - SEP="|" - done - OURCYGPATTERN="(^(\$ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "\$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="\$OURCYGPATTERN|(\$GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "\$@" ; do - CHECK=`echo "\$arg"|egrep -c "\$OURCYGPATTERN" -` - CHECK2=`echo "\$arg"|egrep -c "^-"` ### Determine if an option - - if [ \$CHECK -ne 0 ] && [ \$CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args\$i`=`cygpath --path --ignore --mixed "\$arg"` - else - eval `echo args\$i`="\"\$arg\"" - fi - i=`expr \$i + 1` - done - case \$i in - 0) set -- ;; - 1) set -- "\$args0" ;; - 2) set -- "\$args0" "\$args1" ;; - 3) set -- "\$args0" "\$args1" "\$args2" ;; - 4) set -- "\$args0" "\$args1" "\$args2" "\$args3" ;; - 5) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" ;; - 6) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" ;; - 7) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" ;; - 8) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" "\$args7" ;; - 9) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" "\$args7" "\$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\\\n "\$i" | sed "s/'/'\\\\\\\\''/g;1s/^/'/;\\\$s/\\\$/' \\\\\\\\/" ; done - echo " " -} -APP_ARGS=`save "\$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-jar "\"\$CLASSPATH\"" "\$APP_ARGS" - -exec "\$JAVACMD" "\$@" \ No newline at end of file diff --git a/src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/windowsStartScript.txt b/src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/windowsStartScript.txt deleted file mode 100644 index 71f72e7e3..000000000 --- a/src/main/resources/com/github/jengelman/gradle/plugins/shadow/internal/windowsStartScript.txt +++ /dev/null @@ -1,85 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem ${applicationName} startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=.\ - -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME%${appHomeRelativePath} - -@rem Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script. -set DEFAULT_JVM_OPTS=${defaultJvmOpts} - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=$classpath - -@rem Execute ${applicationName} -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %${optsEnvironmentVar}% <% if ( appNameSystemProperty ) { %>"-D${appNameSystemProperty}=%APP_BASE_NAME%"<% } %> -jar "%CLASSPATH%" %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable ${exitEnvironmentVar} if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%${exitEnvironmentVar}%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega \ No newline at end of file diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy index ff6f72cb6..724d74e2e 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy @@ -66,7 +66,6 @@ class ApplicationSpec extends PluginSpecification { File startScript = getFile('build/install/myapp-shadow/bin/myapp') assert startScript.exists() assert startScript.text.contains("CLASSPATH=\$APP_HOME/lib/myapp-1.0-all.jar") - assert startScript.text.contains("-jar \"\\\"\$CLASSPATH\\\"\" \"\$APP_ARGS\"") assert startScript.text.contains("exec \"\$JAVACMD\" \"\$@\"") cleanup: @@ -146,7 +145,6 @@ class ApplicationSpec extends PluginSpecification { File startScript = getFile('build/install/myapp-shadow/bin/myapp') assert startScript.exists() assert startScript.text.contains("CLASSPATH=\$APP_HOME/lib/myapp-1.0-all.jar") - assert startScript.text.contains("-jar \"\\\"\$CLASSPATH\\\"\" \"\$APP_ARGS\"") assert startScript.text.contains("exec \"\$JAVACMD\" \"\$@\"") cleanup: From be99c14669a8b01ef86caf4a56bfe8972450ced0 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 16 Sep 2025 16:18:01 +0800 Subject: [PATCH 41/72] Require build-status for 8.x branch (#1752) --- .github/workflows/ci.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13088e37d..b87f3d960 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: - 8.x pull_request: - branches: + branches: - 8.x workflow_dispatch: @@ -33,8 +33,24 @@ jobs: - uses: gradle/actions/setup-gradle@v4 - run: ./gradlew build --info "-PtestGradleVersion=${{ matrix.gradle }}" + # Status check that is required in branch protection rules. + build-status: + needs: + - build + runs-on: ubuntu-24.04-arm + if: always() + steps: + - name: Check + run: | + results=$(tr -d '\n' <<< '${{ toJSON(needs.*.result) }}') + if ! grep -q -v -E '(failure|cancelled)' <<< "$results"; then + echo "One or more required jobs failed" + exit 1 + fi + echo "All required jobs completed successfully." + publish-snapshot: - needs: build + needs: build-status runs-on: ubuntu-latest if: github.repository == 'GradleUp/shadow' && github.ref == 'refs/heads/main' steps: From 75cfcdec410f8e3193e558f4d91f9a0b9adf3146 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 01:22:24 +0800 Subject: [PATCH 42/72] Update Gradle to v9.1.0 (#1762) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> (cherry picked from commit 4078b716702a2c847fc95ed8d626bfe375719e2b) --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2a84e188b..2e1113280 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From cbcdaf9728fe9a2b47388596a9773923426a4756 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Sun, 21 Sep 2025 16:10:07 +0800 Subject: [PATCH 43/72] Add Java 25 into test matrix (#1774) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b87f3d960..e1101beec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,13 +16,13 @@ jobs: matrix: os: [ ubuntu-latest, windows-latest ] # Always test on the latest version and some LTS. - java: [ 17, 21, 24 ] + java: [ 17, 21, 25 ] # Test on the minimum Gradle version and the latest. gradle: [ 8.3, current ] exclude: - # Gradle 8.3 doesn't support Java 24. + # Gradle 8.3 doesn't support Java 25. - gradle: 8.3 - java: 24 + java: 25 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From a2ff4630032ecc8d597a8de77370e154743824f6 Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 21 Sep 2025 16:36:18 +0800 Subject: [PATCH 44/72] Ignore local.properties (cherry picked from commit df9f164ec355a83ef1fb7c003aca1f5a2b17c9de) --- .gitignore | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 646e97241..604e8c503 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,25 @@ -*.un~ +.fleet +.gradle +.kotlin +build + +### Android Studio ### +local.properties + +### IntelliJ IDEA ### +.idea +*.iws *.iml *.ipr -*.iws -.idea -build -.gradle -*.orig out -.gradletasknamecache -.gradle-test-kit -classes/ -node_modules/ -yarn-error.log -src/docs/.vuepress/dist/ + +### VS Code ### +.vscode +bin + +### Mac OS ### .DS_Store -jd-gui.cfg -bin/ -.vscode/ + +### MkDocs ### +docs/api +site From 2be1e64e8dc3585ec752b076f8a8510f17439b18 Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 21 Sep 2025 20:20:42 +0800 Subject: [PATCH 45/72] Bump plugins and minor tweaks --- .github/workflows/ci.yml | 7 ++++--- .github/workflows/release.yml | 3 +-- build.gradle.kts | 2 +- gradle.properties | 4 ---- settings.gradle.kts | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1101beec..45667b73e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: distribution: 'zulu' java-version: ${{ matrix.java }} - uses: gradle/actions/setup-gradle@v4 - - run: ./gradlew build --info "-PtestGradleVersion=${{ matrix.gradle }}" + - run: ./gradlew build "-PtestGradleVersion=${{ matrix.gradle }}" --stacktrace # Status check that is required in branch protection rules. build-status: @@ -62,8 +62,9 @@ jobs: - uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true - # Disable CC due to https://github.com/gradle/gradle/issues/22779 - - run: ./gradlew publishToMavenCentral --no-configuration-cache + - run: ./gradlew publishToMavenCentral env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_PORTAL_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_KEY_PASSWORD }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 77d6da030..acfadb21b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,8 +20,7 @@ jobs: - uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true - # Disable CC due to https://github.com/gradle/gradle/issues/22779 - - run: ./gradlew publishToMavenCentral publishPlugins --no-configuration-cache + - run: ./gradlew publishToMavenCentral publishPlugins env: GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_KEY }} GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_SECRET }} diff --git a/build.gradle.kts b/build.gradle.kts index 4ec1095f0..78c5de90f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ import org.gradle.api.plugins.JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME plugins { groovy `java-gradle-plugin` - id("com.gradle.plugin-publish") version "1.3.1" + id("com.gradle.plugin-publish") version "2.0.0" id("com.vanniktech.maven.publish") version "0.34.0" id("com.diffplug.spotless") version "7.2.1" } diff --git a/gradle.properties b/gradle.properties index 04e7e3b4f..af679cf2c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,3 @@ -# Omit automatic compile dependency on kotlin-stdlib -# https://kotlinlang.org/docs/gradle.html#dependency-on-the-standard-library -kotlin.stdlib.default.dependency=false - org.gradle.caching=true org.gradle.configuration-cache=true org.gradle.configuration-cache.parallel=true diff --git a/settings.gradle.kts b/settings.gradle.kts index 7583111ca..2eefdfe89 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,7 +6,7 @@ pluginManagement { } plugins { - id("com.gradle.develocity") version "4.0.2" + id("com.gradle.develocity") version "4.2" } develocity { From d512286584313a6296c4f6f7cb08425c1bb6e03a Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 10 Oct 2025 14:31:21 +0800 Subject: [PATCH 46/72] Update ASM and jdependency to support Java 26 (#1810) Syncs fc6ddff059cba246b081d150640fec4a43a83fa2. --- build.gradle.kts | 4 ++-- src/docs/changes/README.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 78c5de90f..b9a1e402c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -74,12 +74,12 @@ publishing.publications.withType().configureEach { dependencies { api("org.apache.ant:ant:1.10.15") // Types from Ant are exposed in the public API. implementation("org.jdom:jdom2:2.0.6.1") - implementation("org.ow2.asm:asm-commons:9.8") + implementation("org.ow2.asm:asm-commons:9.9") implementation("commons-io:commons-io:2.19.0") implementation("org.codehaus.plexus:plexus-utils:4.0.2") implementation("org.codehaus.plexus:plexus-xml:4.1.0") implementation("org.apache.logging.log4j:log4j-core:2.24.1") - implementation("org.vafer:jdependency:2.13") + implementation("org.vafer:jdependency:2.14") testImplementation("org.spockframework:spock-core:2.3-groovy-4.0") { exclude(group = "org.codehaus.groovy") diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index cfba8f9bd..13bf6fe6d 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -6,6 +6,7 @@ **Changed** - Stop using start script templates bundled in Shadow. ([#1750](https://github.com/GradleUp/shadow/pull/1750)) +- Update ASM and jdependency to support Java 26. ([#1810](https://github.com/GradleUp/shadow/pull/1810)) **Fixed** From 3971dcfa53e3831f16f29f5689b59185b2a959c3 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 10 Oct 2025 14:36:34 +0800 Subject: [PATCH 47/72] Remove document tests for 8.x (#1812) --- .../shadow/docs/ManualCodeSnippetTests.groovy | 41 --------- .../docs/executer/GradleBuildExecuter.groovy | 87 ------------------- .../shadow/docs/executer/NoopExecuter.groovy | 18 ---- .../extractor/ManualSnippetExtractor.groovy | 68 --------------- .../docs/fixture/GroovyDslFixture.groovy | 49 ----------- .../plugins/shadow/docs/internal/Block.java | 11 --- .../internal/snippets/TestCodeSnippet.java | 41 --------- .../snippets/executer/CompileException.java | 18 ---- .../executer/ExceptionTransformer.groovy | 39 --------- .../snippets/executer/SnippetExecuter.java | 14 --- .../fixture/GroovyScriptFixture.groovy | 10 --- .../snippets/fixture/SnippetFixture.java | 27 ------ 12 files changed, 423 deletions(-) delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/NoopExecuter.groovy delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/fixture/GroovyDslFixture.groovy delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy delete mode 100644 src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy deleted file mode 100644 index b937059aa..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/ManualCodeSnippetTests.groovy +++ /dev/null @@ -1,41 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs - -import com.github.jengelman.gradle.plugins.shadow.docs.executer.GradleBuildExecuter -import com.github.jengelman.gradle.plugins.shadow.docs.executer.NoopExecuter -import com.github.jengelman.gradle.plugins.shadow.docs.extractor.ManualSnippetExtractor -import com.github.jengelman.gradle.plugins.shadow.docs.fixture.GroovyDslFixture -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.TestCodeSnippet -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.SnippetExecuter -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.GroovyScriptFixture -import com.google.common.base.StandardSystemProperty -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.DynamicTest -import org.junit.jupiter.api.TestFactory -import org.junit.jupiter.api.io.TempDir - -import java.nio.file.Path - -class ManualCodeSnippetTests { - public static final LinkedHashMap FIXTURES = [ - "groovy" : new GradleBuildExecuter("build.gradle", new GroovyDslFixture(), new GroovyDslFixture.ImportsExtractor()), - "groovy no-plugins": new GradleBuildExecuter("build.gradle", new GroovyScriptFixture(), new GroovyDslFixture.ImportsExtractor()), - "groovy no-run" : new NoopExecuter() - ] - - @Disabled("We have to run doc tests on main branch only") - @TestFactory - List provideDynamicTests(@TempDir Path tempDir) { - File cwd = new File(StandardSystemProperty.USER_DIR.value()) - def content = new File(cwd, "src/docs") - List snippets = [] - - FIXTURES.each { selector, executer -> - ManualSnippetExtractor.extract(tempDir, content, selector, executer).each { - snippets.add(it) - } - } - return snippets.collect { - DynamicTest.dynamicTest(it.testName, it) - } - } -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy deleted file mode 100644 index d727eb562..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/GradleBuildExecuter.groovy +++ /dev/null @@ -1,87 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.executer - -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.TestCodeSnippet -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.SnippetExecuter -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.SnippetFixture -import com.github.jengelman.gradle.plugins.shadow.util.PluginSpecification -import org.gradle.testkit.runner.GradleRunner - -import java.util.function.Function - -class GradleBuildExecuter implements SnippetExecuter { - - private final SnippetFixture fixture - private final String buildFile - private final Function> importExtractor - - private List arguments = ["build", "-m"] - - GradleBuildExecuter(String buildFile, SnippetFixture fixture, Function> importExtractor) { - this.buildFile = buildFile - this.fixture = fixture - this.importExtractor = importExtractor - } - - GradleBuildExecuter(String buildFile, List arguments, SnippetFixture fixture, Function> importExtractor) { - this(buildFile, fixture, importExtractor) - this.arguments = arguments - } - - @Override - SnippetFixture getFixture() { - return fixture - } - - @Override - void execute(File tempDir, TestCodeSnippet snippet) throws Exception { - addSubProject(tempDir) - File settings = new File(tempDir, "settings.gradle") - settings.text = """ -rootProject.name = 'shadowTest' -include 'api', 'main' -""" - - File mainDir = new File(tempDir, "main") - mainDir.mkdirs() - File buildFile = new File(mainDir, buildFile) - - - List importsAndSnippet = importExtractor.apply(snippet.getSnippet()) - - String imports = importsAndSnippet.get(0) - String snippetMinusImports = fixture.transform(importsAndSnippet.get(1)) - String fullSnippet = imports + fixture.pre() + snippetMinusImports + fixture.post() - - buildFile.text = replaceTokens(fullSnippet) - - GradleRunner runner = GradleRunner.create() - .withGradleVersion(PluginSpecification.TEST_GRADLE_VERSION) - .withProjectDir(tempDir) - .withPluginClasspath() - .forwardOutput() - - runner.withArguments(":main:build", "-m").build() - - } - - private static void addSubProject(File dir) { - File api = new File(dir, "api") - api.mkdirs() - File build = new File(api, "build.gradle") - build.text = """ -plugins { - id 'java' - id 'com.gradleup.shadow' -} - -repositories { - mavenLocal() - mavenCentral() -} -""" - } - - private static String replaceTokens(String snippet) { - return snippet.replaceAll("@version@", 'latest') - } -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/NoopExecuter.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/NoopExecuter.groovy deleted file mode 100644 index aabd60c81..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/executer/NoopExecuter.groovy +++ /dev/null @@ -1,18 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.executer - -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.TestCodeSnippet -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.SnippetExecuter -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.SnippetFixture - -class NoopExecuter implements SnippetExecuter { - - @Override - SnippetFixture getFixture() { - return null - } - - @Override - void execute(File tempDir, TestCodeSnippet snippet) throws Exception { - // noop - } -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy deleted file mode 100644 index 7f1f85aa1..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/extractor/ManualSnippetExtractor.groovy +++ /dev/null @@ -1,68 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.extractor - -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.TestCodeSnippet -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.ExceptionTransformer -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.SnippetExecuter -import groovy.ant.FileNameFinder - -import java.nio.file.Path -import java.util.regex.Pattern - -class ManualSnippetExtractor { - - static List extract(Path tempDir, File root, String cssClass, SnippetExecuter executer) { - List snippets = [] - - def snippetBlockPattern = Pattern.compile(/(?ims)```$cssClass\n(.*?)\n```/) - def filenames = new FileNameFinder().getFileNames(root.absolutePath, "**/*.md") - - filenames.each { filename -> - def file = new File(filename) - addSnippets(tempDir, snippets, file, snippetBlockPattern, executer) - } - - snippets - } - - private static void addSnippets(Path tempDir, List snippets, File file, Pattern snippetBlockPattern, SnippetExecuter executer) { - def source = file.text - String testName = file.parentFile.name + "/" + file.name - Map snippetsByLine = findSnippetsByLine(source, snippetBlockPattern) - - snippetsByLine.each { lineNumber, snippet -> - snippets << createSnippet(tempDir, testName, file, lineNumber, snippet, executer) - } - } - - private static List findSnippetBlocks(String code, Pattern snippetTagPattern) { - List tags = [] - code.eachMatch(snippetTagPattern) { matches -> - tags.add(matches[0]) - } - tags - } - - private static Map findSnippetsByLine(String source, Pattern snippetTagPattern) { - List snippetBlocks = findSnippetBlocks(source, snippetTagPattern) - Map snippetBlocksByLine = [:] - - int codeIndex = 0 - snippetBlocks.each { block -> - codeIndex = source.indexOf(block, codeIndex) - def lineNumber = source.substring(0, codeIndex).readLines().size() + 2 - snippetBlocksByLine.put(lineNumber, extractSnippetFromBlock(block)) - codeIndex += block.size() - } - - snippetBlocksByLine - } - - private static String extractSnippetFromBlock(String tag) { - tag.substring(tag.indexOf("\n") + 1, tag.lastIndexOf("\n")) - } - - private static TestCodeSnippet createSnippet(Path tempDir, String sourceClassName, File sourceFile, int lineNumber, String snippet, SnippetExecuter executer) { - new TestCodeSnippet(tempDir, snippet, sourceClassName + ":$lineNumber", executer, new ExceptionTransformer(sourceClassName, sourceFile.name, lineNumber)) - } - -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/fixture/GroovyDslFixture.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/fixture/GroovyDslFixture.groovy deleted file mode 100644 index 0c67cf501..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/fixture/GroovyDslFixture.groovy +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.fixture - -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.GroovyScriptFixture - -import java.util.function.Function - -class GroovyDslFixture extends GroovyScriptFixture { - - @Override - String pre() { - """ -plugins { - id 'java' - id 'com.gradleup.shadow' - id 'application' -} - -version = "1.0" -group = 'shadow' - -repositories { - mavenLocal() - mavenCentral() -} -""" - } - - static class ImportsExtractor implements Function> { - - @Override - List apply(String snippet) { - StringBuilder imports = new StringBuilder() - StringBuilder scriptMinusImports = new StringBuilder() - - for (String line : snippet.split("\\n")) { - StringBuilder target - if (line.trim().startsWith("import ")) { - target = imports - } else { - target = scriptMinusImports - } - - target.append(line).append("\n") - } - - return Arrays.asList(imports.toString(), scriptMinusImports.toString()) - } - } -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java deleted file mode 100644 index 133d8cdf4..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/Block.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.internal; - -public interface Block { - - /** - * Execute the action. - * - * @throws Exception any - */ - void execute() throws Exception; -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java deleted file mode 100644 index 50ad397ab..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/TestCodeSnippet.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets; - -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.ExceptionTransformer; -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer.SnippetExecuter; - -import org.junit.jupiter.api.function.Executable; - -import java.nio.file.Path; - -public class TestCodeSnippet implements Executable { - - private final Path tempDir; - private final String snippet; - private final String testName; - private final SnippetExecuter executer; - private final ExceptionTransformer exceptionTransformer; - - public TestCodeSnippet(Path tempDir, String snippet, String testName, SnippetExecuter executer, ExceptionTransformer exceptionTransformer) { - this.tempDir = tempDir; - this.snippet = snippet; - this.testName = testName; - this.executer = executer; - this.exceptionTransformer = exceptionTransformer; - } - - public String getSnippet() { - return snippet; - } - - public String getTestName() { - return testName; - } - - public void execute() throws Throwable { - try { - executer.execute(tempDir.toFile(), this); - } catch (Throwable t) { - throw exceptionTransformer.transform(t, executer.getFixture().getOffset()); - } - } -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java deleted file mode 100644 index eeab7a2d4..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/CompileException.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer; - -public class CompileException extends RuntimeException { - - private static final long serialVersionUID = 0; - - private final int lineNo; - - public CompileException(Throwable cause, int lineNo) { - super(cause); - this.lineNo = lineNo; - } - - public int getLineNo() { - return lineNo; - } - -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy deleted file mode 100644 index 15331d0ef..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/ExceptionTransformer.groovy +++ /dev/null @@ -1,39 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer - -class ExceptionTransformer { - - final String sourceClassName - final String sourceFileName - final Integer lineNumber - - ExceptionTransformer(String sourceClassName, String sourceFileName, Integer lineNumber) { - this.sourceClassName = sourceClassName - this.sourceFileName = sourceFileName - this.lineNumber = lineNumber - } - - Throwable transform(Throwable throwable, Integer offset) throws Exception { - def errorLine = 0 - - if (throwable instanceof CompileException) { - errorLine = throwable.lineNo - } else { - def frame = throwable.getStackTrace().find { it.fileName == sourceClassName } - if (frame) { - errorLine = frame.lineNumber - } else { - frame = throwable.getStackTrace().find { it.fileName == "Example.java" } - if (frame) { - errorLine = frame.lineNumber - } - } - } - errorLine = errorLine - offset - StackTraceElement[] stack = throwable.getStackTrace() - List newStack = new ArrayList(stack.length + 1) - newStack.add(new StackTraceElement(sourceClassName, "javadoc", sourceFileName, lineNumber + errorLine)) - newStack.addAll(stack) - throwable.setStackTrace(newStack as StackTraceElement[]) - throwable - } -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java deleted file mode 100644 index a78fc8ab8..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/executer/SnippetExecuter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.executer; - -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.TestCodeSnippet; -import com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture.SnippetFixture; - -import java.io.File; - -public interface SnippetExecuter { - - SnippetFixture getFixture(); - - void execute(File tempDir, TestCodeSnippet snippet) throws Exception; - -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy deleted file mode 100644 index 04fdccd67..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/GroovyScriptFixture.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture - -class GroovyScriptFixture extends SnippetFixture { - - @Override - String post() { - "\n;0;" - } - -} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java deleted file mode 100644 index cf29db97c..000000000 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/docs/internal/snippets/fixture/SnippetFixture.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.docs.internal.snippets.fixture; - -import com.github.jengelman.gradle.plugins.shadow.docs.internal.Block; - -public class SnippetFixture { - - public void around(Block action) throws Exception { - action.execute(); - } - - public String transform(String text) { - return text; - } - - public String pre() { - return ""; - } - - public String post() { - return ""; - } - - public Integer getOffset() { - return pre().split("\n").length; - } - -} From e7545d274149da2d79efe411258c29d97469cf7b Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 10 Oct 2025 14:55:46 +0800 Subject: [PATCH 48/72] Update test matrix on CI (#1811) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45667b73e..cb0ce5e81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,15 +14,22 @@ jobs: name: OS=${{ matrix.os }}, Java=${{ matrix.java }}, Gradle=${{ matrix.gradle }} strategy: matrix: - os: [ ubuntu-latest, windows-latest ] + os: [ ubuntu-24.04-arm ] # Always test on the latest version and some LTS. - java: [ 17, 21, 25 ] + java: [ 17, 25 ] # Test on the minimum Gradle version and the latest. gradle: [ 8.3, current ] exclude: # Gradle 8.3 doesn't support Java 25. - gradle: 8.3 java: 25 + include: + - os: windows-latest + gradle: 8.3 + java: 17 + - os: windows-latest + gradle: current + java: 21 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From c38d751ad0bd9e9cfaa2d744d072bdfb903b0dcd Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 10 Oct 2025 15:02:17 +0800 Subject: [PATCH 49/72] Bump actions (#1813) --- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/release.yml | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb0ce5e81..773006448 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,12 +32,12 @@ jobs: java: 21 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ matrix.java }} - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@v5 - run: ./gradlew build "-PtestGradleVersion=${{ matrix.gradle }}" --stacktrace # Status check that is required in branch protection rules. @@ -61,12 +61,12 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'GradleUp/shadow' && github.ref == 'refs/heads/main' steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@v5 with: cache-read-only: true - run: ./gradlew publishToMavenCentral diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index acfadb21b..0ab967947 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,12 +12,12 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@v5 with: cache-read-only: true - run: ./gradlew publishToMavenCentral publishPlugins From 1e5f74d49984c9e91e152c469ecc9189d7503638 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 10 Oct 2025 15:45:00 +0800 Subject: [PATCH 50/72] Tweak Spock tests (#1814) * Replace `jvmArgs` * Replace `runWithDebug` with `run` * Replace `run` with `runWithSuccess` * Cleanups * Remove some ignored tests --- build.gradle.kts | 12 +- .../plugins/shadow/ApplicationSpec.groovy | 8 +- .../shadow/ConfigurationCacheSpec.groovy | 16 +- .../ConfigureShadowRelocationSpec.groovy | 2 +- .../plugins/shadow/FilteringSpec.groovy | 26 +- .../PropertiesFileTransformerSpec.groovy | 10 +- .../plugins/shadow/PublishingSpec.groovy | 8 +- .../plugins/shadow/RelocationSpec.groovy | 12 +- .../plugins/shadow/ShadowPluginSpec.groovy | 241 ++---------------- .../plugins/shadow/TransformerSpec.groovy | 34 +-- .../shadow/caching/AbstractCachingSpec.groovy | 4 +- .../shadow/util/PluginSpecification.groovy | 33 ++- 12 files changed, 109 insertions(+), 297 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b9a1e402c..36817112a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -105,13 +105,9 @@ tasks.withType().configureEach { // Required to test configuration cache in tests when using withDebug() // https://github.com/gradle/gradle/issues/22765#issuecomment-1339427241 jvmArgs( - "--add-opens", - "java.base/java.util=ALL-UNNAMED", - "--add-opens", - "java.base/java.util.concurrent.atomic=ALL-UNNAMED", - "--add-opens", - "java.base/java.lang.invoke=ALL-UNNAMED", - "--add-opens", - "java.base/java.net=ALL-UNNAMED", + "--add-opens=java.base/java.util=ALL-UNNAMED", + "--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED", + "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED", + "--add-opens=java.base/java.net=ALL-UNNAMED", ) } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy index 724d74e2e..13d35e39f 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ApplicationSpec.groovy @@ -45,7 +45,7 @@ class ApplicationSpec extends PluginSpecification { settingsFile << "rootProject.name = 'myapp'" when: - BuildResult result = run('runShadow') + BuildResult result = runWithSuccess('runShadow') then: 'tests that runShadow executed and exited' assert result.output.contains('TestApp: Hello World! (foo)') @@ -123,7 +123,7 @@ class ApplicationSpec extends PluginSpecification { """.stripIndent() when: - BuildResult result = run('runShadow') + BuildResult result = runWithSuccess('runShadow') then: 'tests that runShadow executed and exited' assert result.output.contains('Running application with JDK 17') @@ -187,7 +187,7 @@ class ApplicationSpec extends PluginSpecification { settingsFile << "rootProject.name = 'myapp'" when: - run('shadowDistZip') + runWithSuccess('shadowDistZip') then: 'Check that the distribution zip was created' File zip = getFile('build/distributions/myapp-shadow-1.0.zip') @@ -239,7 +239,7 @@ class ApplicationSpec extends PluginSpecification { settingsFile << "rootProject.name = 'myapp'" when: - run(ShadowApplicationPlugin.SHADOW_INSTALL_TASK_NAME) + runWithSuccess(ShadowApplicationPlugin.SHADOW_INSTALL_TASK_NAME) then: 'Check that the proper jar file was installed' File installedJar = getFile('build/install/myapp-shadow/lib/myapp-1.0-all.jar') diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy index 9bb5ef2a0..babc4e5f9 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigurationCacheSpec.groovy @@ -52,8 +52,8 @@ class ConfigurationCacheSpec extends PluginSpecification { settingsFile << "rootProject.name = 'myapp'" when: - run('shadowJar') - def result = run('shadowJar') + runWithSuccess('shadowJar') + def result = runWithSuccess('shadowJar') then: result.output.contains("Reusing configuration cache.") @@ -68,9 +68,9 @@ class ConfigurationCacheSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') output.delete() - def result = run('shadowJar') + def result = runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'b.properties']) @@ -120,9 +120,9 @@ class ConfigurationCacheSpec extends PluginSpecification { def output = getFile('server/build/libs/server-all.jar') when: - run('shadowJar', '-s') + runWithSuccess('shadowJar', '-s') output.delete() - def result = run('shadowJar', '-s') + def result = runWithSuccess('shadowJar', '-s') then: output.exists() @@ -163,8 +163,8 @@ class ConfigurationCacheSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar', '-s') - def result = run('shadowJar', '-s') + runWithSuccess('shadowJar', '-s') + def result = runWithSuccess('shadowJar', '-s') then: result.output.contains(":lib:shadowJar UP-TO-DATE") diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy index 2c5af9c15..d1a56632e 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ConfigureShadowRelocationSpec.groovy @@ -18,7 +18,7 @@ class ConfigureShadowRelocationSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar', '-s') + runWithSuccess('shadowJar', '-s') then: contains(output, [ diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy index 970e33e8b..bf028d3bc 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/FilteringSpec.groovy @@ -29,7 +29,7 @@ class FilteringSpec extends PluginSpecification { def 'include all dependencies'() { when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'a2.properties', 'b.properties']) @@ -46,7 +46,7 @@ class FilteringSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'b.properties']) @@ -80,7 +80,7 @@ class FilteringSpec extends PluginSpecification { '''.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'a2.properties', 'b.properties', 'c.properties']) @@ -115,7 +115,7 @@ class FilteringSpec extends PluginSpecification { '''.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'a2.properties', 'b.properties', 'c.properties']) @@ -149,7 +149,7 @@ class FilteringSpec extends PluginSpecification { '''.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'a2.properties', 'b.properties', 'c.properties']) @@ -161,7 +161,7 @@ class FilteringSpec extends PluginSpecification { buildFile.text = buildFile.text.replace('exclude(dependency(\'shadow:d:1.0\'))', 'exclude(dependency(\'shadow:c:1.0\'))') - BuildResult result = run('shadowJar') + BuildResult result = runWithSuccess('shadowJar') then: assert result.task(':shadowJar').outcome == TaskOutcome.SUCCESS @@ -198,7 +198,7 @@ class FilteringSpec extends PluginSpecification { '''.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'a2.properties', 'b.properties', 'c.properties']) @@ -213,7 +213,7 @@ class FilteringSpec extends PluginSpecification { } '''.stripIndent() - BuildResult result = run('shadowJar') + BuildResult result = runWithSuccess('shadowJar') then: assert result.task(':shadowJar').outcome == TaskOutcome.SUCCESS @@ -253,7 +253,7 @@ class FilteringSpec extends PluginSpecification { '''.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['d.properties', 'shadow/Passed.class']) @@ -305,7 +305,7 @@ class FilteringSpec extends PluginSpecification { File serverOutput = getFile('server/build/libs/server-1.0-all.jar') when: - run(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: serverOutput.exists() @@ -359,7 +359,7 @@ class FilteringSpec extends PluginSpecification { File serverOutput = getFile('server/build/libs/server-1.0-all.jar') when: - run(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: serverOutput.exists() @@ -387,7 +387,7 @@ class FilteringSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'b.properties']) @@ -421,7 +421,7 @@ class FilteringSpec extends PluginSpecification { '''.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'a2.properties', 'b.properties', 'c.properties']) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy index 34ace1f52..62de4f8b0 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PropertiesFileTransformerSpec.groovy @@ -34,7 +34,7 @@ class PropertiesFileTransformerSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -87,7 +87,7 @@ class PropertiesFileTransformerSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: output.exists() @@ -121,7 +121,7 @@ class PropertiesFileTransformerSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: output.exists() @@ -158,7 +158,7 @@ class PropertiesFileTransformerSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: output.exists() @@ -202,7 +202,7 @@ class PropertiesFileTransformerSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: output.exists() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy index 6ce01faff..9dde49d38 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy @@ -57,7 +57,7 @@ class PublishingSpec extends PluginSpecification { """.stripIndent() when: - run('publish') + runWithSuccess('publish') then: File publishedFile = publishingRepo.rootDir.file('shadow/maven-all/1.0/maven-all-1.0.jar').canonicalFile @@ -125,7 +125,7 @@ class PublishingSpec extends PluginSpecification { """.stripIndent() when: - run('publish') + runWithSuccess('publish') then: File publishedFile = publishingRepo.rootDir.file('shadow/maven-all/1.0/maven-all-1.0-my-classifier.my-ext').canonicalFile @@ -206,7 +206,7 @@ class PublishingSpec extends PluginSpecification { """.stripMargin() when: - run('publish') + runWithSuccess('publish') then: File publishedFile = publishingRepo.rootDir.file('shadow/maven-all/1.0/maven-all-1.0.jar').canonicalFile @@ -270,7 +270,7 @@ class PublishingSpec extends PluginSpecification { """.stripIndent() when: - run('publish') + runWithSuccess('publish') then: File mainJar = publishingRepo.rootDir.file('com/acme/maven/1.0/maven-1.0.jar').canonicalFile diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy index a72008197..253961e9e 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/RelocationSpec.groovy @@ -27,7 +27,7 @@ class RelocationSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, [ @@ -95,7 +95,7 @@ class RelocationSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, [ @@ -158,7 +158,7 @@ class RelocationSpec extends PluginSpecification { '''.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, [ @@ -230,7 +230,7 @@ class RelocationSpec extends PluginSpecification { '''.stripIndent() when: - run(':app:shadowJar') + runWithSuccess(':app:shadowJar') then: File appOutput = getFile('app/build/libs/app-all.jar') @@ -271,7 +271,7 @@ class RelocationSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, [ @@ -316,7 +316,7 @@ class RelocationSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: noExceptionThrown() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy index fda372688..97be7aa45 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy @@ -2,16 +2,12 @@ package com.github.jengelman.gradle.plugins.shadow import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.util.PluginSpecification -import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.artifacts.Configuration import org.gradle.api.plugins.JavaPlugin import org.gradle.testfixtures.ProjectBuilder import org.gradle.testkit.runner.BuildResult -import spock.lang.Ignore -import spock.lang.IgnoreIf import spock.lang.Issue -import spock.lang.Unroll import java.util.jar.Attributes import java.util.jar.JarFile @@ -55,64 +51,6 @@ class ShadowPluginSpec extends PluginSpecification { } - @IgnoreIf({ - // Gradle 8.3 doesn't support Java 21. - JavaVersion.current().majorVersion.toInteger() >= 21 - }) - @Unroll - def 'Compatible with Gradle #version'() { - given: - File one = buildJar('one.jar').insertFile('META-INF/services/shadow.Shadow', - 'one # NOTE: No newline terminates this line/file').write() - - repo.module('shadow', 'two', '1.0').insertFile('META-INF/services/shadow.Shadow', - 'two # NOTE: No newline terminates this line/file').publish() - - buildFile << """ - dependencies { - implementation 'junit:junit:3.8.2' - implementation files('${escapedPath(one)}') - } - - tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - mergeServiceFiles() - } - """.stripIndent() - - when: - run(['shadowJar']) { - it.withGradleVersion(version) - it.withDebug(true) - it.withTestKitDir(getTestKitDir()) - } - - then: - assert output.exists() - - where: - version << ['8.3'] - } - - def 'Error in Gradle versions < 8.3'() { - given: - buildFile << """ - dependencies { - implementation 'junit:junit:3.8.2' - } - - tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - mergeServiceFiles() - } - """.stripIndent() - - expect: - runWithFailure(['shadowJar']) { - it.withGradleVersion('7.0') - it.withDebug(true) - it.withTestKitDir(getTestKitDir()) - } - } - def 'shadow copy'() { given: URL artifact = this.class.classLoader.getResource('test-artifact-1.0-SNAPSHOT.jar') @@ -126,7 +64,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -153,7 +91,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output("shadow.jar"), ['shadow/Passed.class', 'junit/framework/Test.class']) @@ -199,7 +137,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('server/build/libs/server-all.jar') when: - run(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: serverOutput.exists() @@ -256,7 +194,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('server/build/libs/server-all.jar') when: - runWithDebug(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: serverOutput.exists() @@ -311,7 +249,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('server/build/libs/server-all.jar') when: - runWithDebug(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: serverOutput.exists() @@ -364,7 +302,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = file('server/build/libs/server-all.jar') when: - runWithDebug(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: contains(serverOutput, [ @@ -419,7 +357,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = file('server/build/libs/server-all.jar') when: - runWithDebug(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: contains(serverOutput, [ @@ -472,7 +410,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = file('server/build/libs/server-all.jar') when: - runWithDebug(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: contains(serverOutput, [ @@ -550,7 +488,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('impl/build/libs/impl-all.jar') when: - runWithDebug(':impl:shadowJar') + runWithSuccess(':impl:shadowJar') then: serverOutput.exists() @@ -626,7 +564,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('impl/build/libs/impl-all.jar') when: - runWithDebug(':impl:shadowJar') + runWithSuccess(':impl:shadowJar') then: serverOutput.exists() @@ -680,7 +618,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('server/build/libs/server.jar') when: - run(':server:jar') + runWithSuccess(':server:jar') then: serverOutput.exists() @@ -738,7 +676,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('server/build/libs/server-all.jar') when: - run(':server:shadowJar') + runWithSuccess(':server:shadowJar') then: serverOutput.exists() @@ -775,7 +713,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties', 'META-INF/a.properties']) @@ -802,7 +740,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties']) @@ -840,7 +778,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - runWithDebug('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['api.properties', 'implementation.properties', @@ -865,7 +803,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: contains(output, ['a.properties']) @@ -892,7 +830,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: JarFile jar = new JarFile(output) @@ -907,7 +845,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -939,7 +877,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -961,7 +899,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -988,7 +926,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -1036,7 +974,7 @@ class ShadowPluginSpec extends PluginSpecification { File serverOutput = getFile('impl/build/libs/impl-1.0-all.jar') when: - runWithDebug(':impl:shadowJar') + runWithSuccess(':impl:shadowJar') then: serverOutput.exists() @@ -1045,137 +983,6 @@ class ShadowPluginSpec extends PluginSpecification { ]) } - @Issue('SHADOW-143') - @Ignore("This spec requires > 15 minutes and > 8GB of disk space to run") - def "check large zip files with zip64 enabled"() { - given: - repo.module('shadow', 'a', '1.0') - .insertFile('a.properties', 'a') - .insertFile('a2.properties', 'a2') - .publish() - - file('src/main/java/myapp/Main.java') << """ - package myapp; - public class Main { - public static void main(String[] args) { - System.out.println("TestApp: Hello World! (" + args[0] + ")"); - } - } - """.stripIndent() - - buildFile << """ - apply plugin: 'application' - - application { - mainClass = 'myapp.Main' - } - - dependencies { - implementation 'shadow:a:1.0' - } - - def generatedResourcesDir = new File(project.layout.buildDirectory.asFile.get(), "generated-resources") - - task generateResources { - doLast { - def rnd = new Random() - def buf = new byte[128 * 1024] - for (x in 0..255) { - def dir = new File(generatedResourcesDir, x.toString()) - dir.mkdirs() - for (y in 0..255) { - def file = new File(dir, y.toString()) - rnd.nextBytes(buf) - file.bytes = buf - } - } - } - } - - sourceSets { - main { - output.dir(generatedResourcesDir, builtBy: generateResources) - } - } - - tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - zip64 = true - } - - runShadow { - args 'foo' - } - """.stripIndent() - - settingsFile << "rootProject.name = 'myapp'" - - when: - BuildResult result = run('runShadow') - - then: 'tests that runShadow executed and exited' - assert result.output.contains('TestApp: Hello World! (foo)') - - - } - - @Issue("SHADOW-303") - @Ignore("Plugin has been deprecated") - def "doesn't error when adding aspectj plugin"() { - given: - buildFile.text = """ - buildscript { - repositories { - maven { - url = "https://maven.eveoh.nl/content/repositories/releases" - } - } - - dependencies { - classpath "nl.eveoh:gradle-aspectj:2.0" - } - } - """.stripIndent() - - buildFile << defaultBuildScript - - buildFile << """ - project.ext { - aspectjVersion = '1.8.12' - } - - apply plugin: 'aspectj' - apply plugin: 'application' - - application { - mainClass = 'myapp.Main' - } - - repositories { - mavenCentral() - } - - runShadow { - args 'foo' - } - - """ - - file('src/main/java/myapp/Main.java') << """ - package myapp; - public class Main { - public static void main(String[] args) { - System.out.println("TestApp: Hello World! (" + args[0] + ")"); - } - } - """.stripIndent() - - when: - BuildResult result = run('runShadow') - - then: 'tests that runShadow executed and exited' - assert result.output.contains('TestApp: Hello World! (foo)') - } - @Issue("https://github.com/GradleUp/shadow/issues/609") def "doesn't error when using application mainClass property"() { given: @@ -1212,7 +1019,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - BuildResult result = run('runShadow') + BuildResult result = runWithSuccess('runShadow') then: 'tests that runShadow executed and exited' assert result.output.contains('TestApp: Hello World! (foo)') @@ -1238,7 +1045,7 @@ class ShadowPluginSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy index 7bed060ce..1ba44e918 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/TransformerSpec.groovy @@ -41,7 +41,7 @@ class TransformerSpec extends PluginSpecification { """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -81,7 +81,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -121,7 +121,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -176,7 +176,7 @@ com.mysql.jdbc.Driver'''.stripIndent()) """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -224,7 +224,7 @@ org.mortbay.log.Factory'''.stripIndent() """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -261,7 +261,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() 'three # NOTE: No newline terminates this line/file' when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -297,7 +297,7 @@ two # NOTE: No newline terminates this line/file'''.stripIndent() """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -330,7 +330,7 @@ two # NOTE: No newline terminates this line/file """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -366,7 +366,7 @@ two # NOTE: No newline terminates this line/file """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -410,7 +410,7 @@ two # NOTE: No newline terminates this line/file """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -462,7 +462,7 @@ two # NOTE: No newline terminates this line/file """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -509,7 +509,7 @@ two # NOTE: No newline terminates this line/file """.stripIndent() when: - run('jar', 'shadowJar') + runWithSuccess('jar', 'shadowJar') then: File jar = getFile('build/libs/shadow-1.0.jar') @@ -569,7 +569,7 @@ two # NOTE: No newline terminates this line/file """.stripIndent() when: - run('jar', 'shadowJar') + runWithSuccess('jar', 'shadowJar') then: File jar = getFile('build/libs/shadow-1.0.jar') @@ -628,7 +628,7 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -672,7 +672,7 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: output.exists() @@ -715,7 +715,7 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( """.stripIndent() when: - run('shadowJar') + runWithSuccess('shadowJar') then: assert output.exists() @@ -745,7 +745,7 @@ staticExtensionClasses=com.acme.bar.SomeStaticExtension'''.stripIndent()).write( """.stripIndent() when: - run('shadowJar', '--warning-mode=all') + runWithSuccess('shadowJar') then: assert output.exists() diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy index 3c0ed8c9b..f54c7bb9f 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/caching/AbstractCachingSpec.groovy @@ -36,14 +36,14 @@ abstract class AbstractCachingSpec extends PluginSpecification { BuildResult runWithCacheEnabled(String... arguments) { List cacheArguments = ['--build-cache'] cacheArguments.addAll(arguments) - return run(cacheArguments) + return runWithSuccess(cacheArguments) } BuildResult runInAlternateDirWithCacheEnabled(String... arguments) { List cacheArguments = ['--build-cache'] cacheArguments.addAll(arguments) // TODO: Use PluginSpecification.run here to reuse flags, but cache tests failed for now, need to investigate. - return runner.withProjectDir(alternateDir.toFile()).withArguments(cacheArguments).build() + return runner().withProjectDir(alternateDir.toFile()).withArguments(cacheArguments).build() } void assertShadowJarHasResult(TaskOutcome expectedOutcome) { diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index 92e53591b..71efa6f25 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -8,6 +8,7 @@ import spock.lang.Specification import spock.lang.TempDir import java.nio.file.Path +import java.nio.file.Paths import java.util.function.Function import java.util.jar.JarEntry import java.util.jar.JarFile @@ -17,7 +18,15 @@ abstract class PluginSpecification extends Specification { @TempDir Path dir - public static final String TEST_GRADLE_VERSION = System.getProperty("TEST_GRADLE_VERSION") + private static final String TEST_GRADLE_VERSION = System.getProperty("TEST_GRADLE_VERSION") + + private static final Path TEST_KIT_DIR + + static { + def gradleUserHome = System.getenv("GRADLE_USER_HOME") + ?: Paths.get(System.getProperty("user.home"), ".gradle").toAbsolutePath().toString() + TEST_KIT_DIR = Paths.get(gradleUserHome, "testkit") + } AppendableMavenFileRepository repo @@ -54,30 +63,29 @@ abstract class PluginSpecification extends Specification { """.stripIndent() } - GradleRunner getRunner() { + GradleRunner runner(Collection tasks = Collections.emptyList()) { + def extraArgs = ["--warning-mode=fail", "--configuration-cache", "--stacktrace"] GradleRunner.create() .withGradleVersion(TEST_GRADLE_VERSION) .withProjectDir(dir.toFile()) + .withTestKitDir(TEST_KIT_DIR.toFile()) .forwardOutput() .withPluginClasspath() + .withArguments(extraArgs + tasks) } - GradleRunner runner(Collection tasks) { - runner.withArguments(["-Dorg.gradle.warning.mode=all", "--configuration-cache", "--stacktrace"] + tasks.toList()) - } - - BuildResult run(String... tasks) { - run(tasks.toList()) + BuildResult runWithSuccess(String... tasks) { + return runWithSuccess(tasks.toList()) } - BuildResult run(List tasks, Function runnerFunction = { it }) { + BuildResult runWithSuccess(List tasks, Function runnerFunction = { it }) { def result = runnerFunction.apply(runner(tasks)).build() assertNoDeprecationWarnings(result) return result } - BuildResult runWithDebug(String... tasks) { - return run(tasks.toList(), { it.withDebug(true) }) + BuildResult runWithFailure(String... tasks) { + return runWithFailure(tasks.toList()) } BuildResult runWithFailure(List tasks, Function runnerFunction = { it }) { @@ -94,7 +102,8 @@ abstract class PluginSpecification extends Specification { static boolean containsDeprecationWarning(String output) { output.contains("has been deprecated and is scheduled to be removed in Gradle") || - output.contains("has been deprecated. This is scheduled to be removed in Gradle") + output.contains("has been deprecated. This is scheduled to be removed in Gradle") || + output.contains("will fail with an error in Gradle") } File getBuildFile() { From 797b5b8c72fb472132739e53c73bf4612deb08a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:36:21 +0800 Subject: [PATCH 51/72] Update Gradle to v9.2.0 (#1828) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> (cherry picked from commit c24ae19c6d12537f7cfb8e679a31aa349a5a16ca) --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e1113280..bad7c2462 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From f5f948d1a13f8e97a0a32c03778597eccac4b863 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Sat, 1 Nov 2025 12:52:47 +0800 Subject: [PATCH 52/72] Rename ci.yml to build.yml --- .github/workflows/{ci.yml => build.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{ci.yml => build.yml} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/build.yml similarity index 100% rename from .github/workflows/ci.yml rename to .github/workflows/build.yml From 7b1546cbb299044207dcab56f350bc0cdaa63efc Mon Sep 17 00:00:00 2001 From: Goooler Date: Mon, 1 Dec 2025 09:56:34 +0800 Subject: [PATCH 53/72] Stop deprecating ShadowExtension It's useful in 9.x versions. --- .../jengelman/gradle/plugins/shadow/ShadowExtension.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy index 53fc8b38d..e8e12c356 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowExtension.groovy @@ -4,7 +4,6 @@ import org.gradle.api.Project import org.gradle.api.component.SoftwareComponentContainer import org.gradle.api.publish.maven.MavenPublication -@Deprecated class ShadowExtension { private final SoftwareComponentContainer components From b9681782b2957c6b65193bb05492ee65d1179bf2 Mon Sep 17 00:00:00 2001 From: Goooler Date: Sat, 13 Dec 2025 10:42:55 +0800 Subject: [PATCH 54/72] Bump spock-core to 2.4 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 36817112a..18cf42f4b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -81,7 +81,7 @@ dependencies { implementation("org.apache.logging.log4j:log4j-core:2.24.1") implementation("org.vafer:jdependency:2.14") - testImplementation("org.spockframework:spock-core:2.3-groovy-4.0") { + testImplementation("org.spockframework:spock-core:2.4-groovy-4.0") { exclude(group = "org.codehaus.groovy") exclude(group = "org.hamcrest") } From 4b407f9f14ab6dafa70bda634c303e92a0d5b6ca Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 26 Feb 2026 14:03:28 +0800 Subject: [PATCH 55/72] Update dependency org.vafer:jdependency to v2.15 (#1926) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 18cf42f4b..d4ad4b124 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -79,7 +79,7 @@ dependencies { implementation("org.codehaus.plexus:plexus-utils:4.0.2") implementation("org.codehaus.plexus:plexus-xml:4.1.0") implementation("org.apache.logging.log4j:log4j-core:2.24.1") - implementation("org.vafer:jdependency:2.14") + implementation("org.vafer:jdependency:2.15") testImplementation("org.spockframework:spock-core:2.4-groovy-4.0") { exclude(group = "org.codehaus.groovy") From 5f61ec17f8828ee71f6fa207b282137ac4587519 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 26 Feb 2026 14:10:29 +0800 Subject: [PATCH 56/72] Update dependencies --- build.gradle.kts | 10 +++++----- gradle.properties | 12 ++++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d4ad4b124..95314587c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,8 +7,8 @@ plugins { groovy `java-gradle-plugin` id("com.gradle.plugin-publish") version "2.0.0" - id("com.vanniktech.maven.publish") version "0.34.0" - id("com.diffplug.spotless") version "7.2.1" + id("com.vanniktech.maven.publish") version "0.36.0" + id("com.diffplug.spotless") version "8.2.1" } version = providers.gradleProperty("VERSION_NAME").get() @@ -77,15 +77,15 @@ dependencies { implementation("org.ow2.asm:asm-commons:9.9") implementation("commons-io:commons-io:2.19.0") implementation("org.codehaus.plexus:plexus-utils:4.0.2") - implementation("org.codehaus.plexus:plexus-xml:4.1.0") - implementation("org.apache.logging.log4j:log4j-core:2.24.1") + implementation("org.codehaus.plexus:plexus-xml:4.1.1") + implementation("org.apache.logging.log4j:log4j-core:2.25.3") implementation("org.vafer:jdependency:2.15") testImplementation("org.spockframework:spock-core:2.4-groovy-4.0") { exclude(group = "org.codehaus.groovy") exclude(group = "org.hamcrest") } - testImplementation("org.xmlunit:xmlunit-legacy:2.10.2") + testImplementation("org.xmlunit:xmlunit-legacy:2.11.0") testImplementation("org.apache.commons:commons-lang3:3.17.0") testImplementation("com.google.guava:guava:33.3.1-jre") testImplementation(platform("org.junit:junit-bom:5.13.1")) diff --git a/gradle.properties b/gradle.properties index af679cf2c..bf6efff56 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,18 +1,22 @@ org.gradle.caching=true org.gradle.configuration-cache=true org.gradle.configuration-cache.parallel=true -org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx4g -XX:MaxMetaspaceSize=2g +org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx4g org.gradle.kotlin.dsl.allWarningsAsErrors=true org.gradle.parallel=true +org.gradle.tooling.parallel=true -GROUP=com.gradleup.shadow -POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.10-SNAPSHOT +########## Properties for publishing to Maven Central ########## mavenCentralAutomaticPublishing=true +mavenCentralDeploymentValidation=PUBLISHED mavenCentralPublishing=true signAllPublications=true +GROUP=com.gradleup.shadow +POM_ARTIFACT_ID=shadow-gradle-plugin +VERSION_NAME=8.3.10-SNAPSHOT + POM_NAME=Shadow Gradle Plugin POM_DESCRIPTION=Gradle plugin to create fat/uber JARs, apply file transforms, and relocate packages for applications and libraries. Gradle version of Maven's Shade plugin. POM_INCEPTION_YEAR=2024 From 611e54717e5800c357d3478896ba6e3835a0735c Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Thu, 26 Feb 2026 14:20:57 +0800 Subject: [PATCH 57/72] Use ASM from jdependency embedded (#1927) Syncs 2bddd9628608d0e9c6921c0374b63a27e43569ab. --- build.gradle.kts | 1 - src/docs/changes/README.md | 2 ++ .../gradle/plugins/shadow/impl/RelocatorRemapper.groovy | 2 +- .../gradle/plugins/shadow/tasks/ShadowCopyAction.groovy | 8 ++++---- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 95314587c..4408dd8b0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -74,7 +74,6 @@ publishing.publications.withType().configureEach { dependencies { api("org.apache.ant:ant:1.10.15") // Types from Ant are exposed in the public API. implementation("org.jdom:jdom2:2.0.6.1") - implementation("org.ow2.asm:asm-commons:9.9") implementation("commons-io:commons-io:2.19.0") implementation("org.codehaus.plexus:plexus-utils:4.0.2") implementation("org.codehaus.plexus:plexus-xml:4.1.1") diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 13bf6fe6d..23fc514f7 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -11,6 +11,8 @@ **Fixed** - Fix resolving BOM dependencies when `minimize` is enabled. ([#1638](https://github.com/GradleUp/shadow/pull/1638)) +- Use ASM from jdependency embedded. ([#1898](https://github.com/GradleUp/shadow/pull/1898)) + This fixes potential classpath conflicts when using Shadow with other plugins that also use ASM. ## [v8.3.9] (2025-08-05) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy index 31fafab21..f47ecf104 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/impl/RelocatorRemapper.groovy @@ -25,7 +25,7 @@ import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowCopyAction.RelativeArchivePath import groovy.transform.CompileStatic -import org.objectweb.asm.commons.Remapper +import org.vafer.jdeb.shaded.objectweb.asm.commons.Remapper import java.util.regex.Matcher import java.util.regex.Pattern diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy index 3fb9eaef4..90ade6def 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.groovy @@ -34,10 +34,10 @@ import org.gradle.api.tasks.WorkResults import org.gradle.api.tasks.bundling.Zip import org.gradle.api.tasks.util.PatternSet import org.gradle.internal.UncheckedException -import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassVisitor -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.commons.ClassRemapper +import org.vafer.jdeb.shaded.objectweb.asm.ClassReader +import org.vafer.jdeb.shaded.objectweb.asm.ClassVisitor +import org.vafer.jdeb.shaded.objectweb.asm.ClassWriter +import org.vafer.jdeb.shaded.objectweb.asm.commons.ClassRemapper import java.util.zip.ZipException From 01e4009e464182b5fa3960bbe8e327cf6be9c7e6 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 26 Feb 2026 14:22:28 +0800 Subject: [PATCH 58/72] Prepare version 8.3.10 --- gradle.properties | 2 +- src/docs/changes/README.md | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index bf6efff56..714124d9f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ signAllPublications=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.10-SNAPSHOT +VERSION_NAME=8.3.10 POM_NAME=Shadow Gradle Plugin POM_DESCRIPTION=Gradle plugin to create fat/uber JARs, apply file transforms, and relocate packages for applications and libraries. Gradle version of Maven's Shade plugin. diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 23fc514f7..a8cbe2fdc 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,7 +1,10 @@ # Change Log -## [Unreleased] +## [v8.3.10] (2026-02-26) + +> [!WARNING] +> Only Gradle 9 support is being backported to this version. No additional features or crucial bug fixes will be included in the 8.x line. Please migrate to Shadow 9 as soon as possible. **Changed** @@ -466,7 +469,8 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = " Date: Thu, 26 Feb 2026 14:23:35 +0800 Subject: [PATCH 59/72] Prepare next development version --- src/docs/changes/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index a8cbe2fdc..d0a58fbcb 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,6 +1,9 @@ # Change Log +## [Unreleased] + + ## [v8.3.10] (2026-02-26) > [!WARNING] From 30aaa52ec9eebb25fbff5e18515d2f0c19f672ad Mon Sep 17 00:00:00 2001 From: Goooler Date: Mon, 2 Mar 2026 20:08:36 +0800 Subject: [PATCH 60/72] Remove integTest source set in tests --- .../gradle/plugins/shadow/util/PluginSpecification.groovy | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index 71efa6f25..7352fe898 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -55,10 +55,6 @@ abstract class PluginSpecification extends Specification { version = "1.0" group = 'shadow' - sourceSets { - integTest - } - repositories { maven { url = "${repo.uri}" } } """.stripIndent() } From 6bf9d7e8bf3acfbe7406fd3d7c7fb0ea334425b4 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Mon, 2 Mar 2026 20:29:12 +0800 Subject: [PATCH 61/72] Fix compatibility with Isolated Projects (#1947) Ports 09f50816c3927dba890b5871c880164b31572521. --- src/docs/changes/README.md | 3 + .../shadow/internal/UnusedTracker.groovy | 72 +++++++------------ .../plugins/shadow/PublishingSpec.groovy | 39 +++++----- .../shadow/util/PluginSpecification.groovy | 7 +- 4 files changed, 51 insertions(+), 70 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index d0a58fbcb..c4b33a619 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,9 @@ ## [Unreleased] +**Fixed** + +- Fix compatibility with Isolated Projects. ([#1947](https://github.com/GradleUp/shadow/pull/1947)) ## [v8.3.10] (2026-02-26) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy index 16968b9c0..e870eb267 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/UnusedTracker.groovy @@ -1,13 +1,12 @@ package com.github.jengelman.gradle.plugins.shadow.internal import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.FileCollectionDependency -import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.attributes.Category +import org.gradle.api.attributes.LibraryElements +import org.gradle.api.attributes.Usage import org.gradle.api.file.FileCollection import org.gradle.api.tasks.InputFiles -import org.gradle.util.GradleVersion import org.vafer.jdependency.Clazz import org.vafer.jdependency.Clazzpath import org.vafer.jdependency.ClazzpathUnit @@ -48,52 +47,33 @@ class UnusedTracker { return toMinimize } - private static boolean isProjectDependencyFile(File file, Dependency dep) { - def fileName = file.name - def dependencyName = dep.name - - return (fileName == "${dependencyName}.jar") || - (fileName.startsWith("${dependencyName}-") && fileName.endsWith('.jar')) - } - - private static void addJar(Configuration config, Dependency dep, List result) { - def file = config.find { isProjectDependencyFile(it, dep) } as File - if (file != null) { - result.add(file) - } - } - static FileCollection getApiJarsFromProject(Project project) { - def apiDependencies = project.configurations.asMap['api']?.dependencies ?: null - if (apiDependencies == null) return project.files() + def apiConfiguration = project.configurations.findByName("api") + if (apiConfiguration == null) return project.files() - def runtimeConfiguration = project.configurations.asMap['runtimeClasspath'] ?: project.configurations.runtime - def apiJars = new LinkedList() - apiDependencies.each { dep -> - if (dep instanceof ProjectDependency) { - apiJars.addAll(getApiJarsFromProject(dependencyProjectCompat(dep, project))) - addJar(runtimeConfiguration, dep, apiJars) - } else if (dep instanceof FileCollectionDependency) { - apiJars.addAll(dep.files) - } else { - addJar(runtimeConfiguration, dep, apiJars) - def jarFile = runtimeConfiguration.find { it.name.startsWith("${dep.name}-") } - if (jarFile != null) { - apiJars.add(jarFile) + def configName = "shadowMinimizeApi" + def shadowApiConfig + if (project.configurations.names.contains(configName)) { + shadowApiConfig = project.configurations.named(configName) + } else { + shadowApiConfig = project.configurations.register(configName) { config -> + config.canBeResolved = true + config.canBeConsumed = false + config.attributes { attrs -> + attrs.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage, Usage.JAVA_API)) + attrs.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category, Category.LIBRARY)) + attrs.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR)) } + config.extendsFrom(apiConfiguration) } } - return project.files(apiJars) - } - - /** - * TODO: this could be removed after bumping the min Gradle requirement to 8.11 or above. - */ - private static dependencyProjectCompat(ProjectDependency projectDependency, Project project) { - if (GradleVersion.current() >= GradleVersion.version("8.11")) { - return project.project(projectDependency.path) - } - return projectDependency.dependencyProject + return project.files(shadowApiConfig.flatMap { shadowApi -> + shadowApi.incoming.artifacts.resolvedArtifacts.map { artifacts -> + artifacts + .findAll { it.id.componentIdentifier !instanceof ModuleComponentIdentifier } + .collect { it.file } + } + }) } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy index 9dde49d38..e62e5fa02 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy @@ -142,40 +142,32 @@ class PublishingSpec extends PluginSpecification { include 'c' """.stripMargin() - buildFile.text = """ - subprojects { - apply plugin: 'java' - apply plugin: 'maven-publish' - - version = "1.0" - group = 'shadow' - - repositories { maven { url = "${repo.uri}" } } - publishing { - repositories { - maven { - url = "${publishingRepo.uri}" - } + def publishingBlock = """ + apply plugin: 'java' + apply plugin: 'maven-publish' + + version = "1.0" + group = 'shadow' + + repositories { maven { url = "${repo.uri}" } } + publishing { + repositories { + maven { + url = "${publishingRepo.uri}" } - } + } } """.stripIndent() file('a/build.gradle') << """ - plugins { - id 'java' - id 'maven-publish' - } + $publishingBlock """.stripMargin() file('a/src/main/resources/a.properties') << 'a' file('a/src/main/resources/a2.properties') << 'a2' file('b/build.gradle') << """ - plugins { - id 'java' - id 'maven-publish' - } + $publishingBlock """.stripMargin() file('b/src/main/resources/b.properties') << 'b' @@ -184,6 +176,7 @@ class PublishingSpec extends PluginSpecification { plugins { id 'com.gradleup.shadow' } + $publishingBlock dependencies { implementation project(':a') diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy index 7352fe898..aa54676ef 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/util/PluginSpecification.groovy @@ -4,6 +4,7 @@ import com.github.jengelman.gradle.plugins.shadow.util.file.TestFile import org.codehaus.plexus.util.IOUtil import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner +import org.gradle.util.GradleVersion import spock.lang.Specification import spock.lang.TempDir @@ -67,7 +68,7 @@ abstract class PluginSpecification extends Specification { .withTestKitDir(TEST_KIT_DIR.toFile()) .forwardOutput() .withPluginClasspath() - .withArguments(extraArgs + tasks) + .withArguments(extraArgs + ipFlag + tasks) } BuildResult runWithSuccess(String... tasks) { @@ -195,4 +196,8 @@ abstract class PluginSpecification extends Specification { } return new File(gradleUserHome, "testkit") } + + // https://docs.gradle.org/current/userguide/isolated_projects.html#how_do_i_use_it + private static def ipFlag = GradleVersion.version(TEST_GRADLE_VERSION) >= GradleVersion.version("9.0.0") ? + ["-Dorg.gradle.unsafe.isolated-projects=true"] : [] } From a2d82f73997361e71a7b4fd9924488542aac7f22 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Mon, 2 Mar 2026 21:05:28 +0800 Subject: [PATCH 62/72] Fix interaction with Gradle artifact transforms (#1949) Ports 29cbc564e10d2aaa0a38b3ebc22b39eebc9a990a. --- src/docs/changes/README.md | 1 + .../internal/AbstractDependencyFilter.groovy | 14 +-- .../plugins/shadow/ShadowPluginSpec.groovy | 100 ++++++++++++++++++ 3 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index c4b33a619..213cfe849 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -6,6 +6,7 @@ **Fixed** - Fix compatibility with Isolated Projects. ([#1947](https://github.com/GradleUp/shadow/pull/1947)) +- Fix interaction with Gradle artifact transforms. ([#1949](https://github.com/GradleUp/shadow/pull/1949)) ## [v8.3.10] (2026-02-26) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy index 2e401301b..07f01e089 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/AbstractDependencyFilter.groovy @@ -26,12 +26,14 @@ abstract class AbstractDependencyFilter implements DependencyFilter { @Override FileCollection resolve(FileCollection configuration) { - Set includedDeps = [] - Set excludedDeps = [] - resolve(configuration.resolvedConfiguration.firstLevelModuleDependencies, includedDeps, excludedDeps) - return project.files(configuration.files) - project.files(excludedDeps.collect { - it.moduleArtifacts*.file - }.flatten()) + return configuration - project.files(project.provider { + Set includedDeps = [] + Set excludedDeps = [] + resolve(configuration.resolvedConfiguration.firstLevelModuleDependencies, includedDeps, excludedDeps) + excludedDeps.collectMany { + it.moduleArtifacts.collect { it.file } + } + }) } @Override diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy index 97be7aa45..bed7ca151 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy @@ -1054,4 +1054,104 @@ class ShadowPluginSpec extends PluginSpecification { JarFile jar = new JarFile(output) assert jar.entries().collect().findAll { it.name.endsWith('.class') }.size() == 1 } + + @Issue("https://github.com/GradleUp/shadow/issues/882") + def 'compat gradle artifact transform'() { + given: + file('settings.gradle') << "include('app', 'lib')\n" + file("lib/build.gradle") << """ + plugins { + id 'java-library' + } + """.stripIndent() + + file("lib/src/main/java/com/company/Utils.java") << """ + package com.company; + + public class Utils { + public static void foo() { + System.out.println("bar"); + } + } + """.stripIndent() + + file("app/build.gradle") << """ + import org.gradle.api.artifacts.transform.TransformParameters + import org.gradle.api.artifacts.transform.TransformAction + import org.gradle.api.artifacts.transform.TransformOutputs + import org.gradle.api.artifacts.transform.InputArtifact + import org.gradle.api.file.FileSystemLocation + import org.gradle.api.provider.Provider + + plugins { + id 'application' + id 'com.gradleup.shadow' + } + + application { + mainClass = 'com.company.Main' + } + + dependencies { + implementation project(':lib') + } + + def transformedAttribute = Attribute.of('custom-transformed', Boolean) + + dependencies { + attributesSchema { + attribute(transformedAttribute) + } + artifactTypes.maybeCreate('jar').attributes.attribute(transformedAttribute, false) + } + + dependencies { + registerTransform(CustomTransformAction) { + from.attribute(Attribute.of('artifactType', String), 'jar').attribute(transformedAttribute, false) + to.attribute(Attribute.of('artifactType', String), 'jar').attribute(transformedAttribute, true) + } + } + + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + configurations = [project.configurations.runtimeClasspath] + } + + configurations.runtimeClasspath { + attributes.attribute(transformedAttribute, true) + } + + abstract class CustomTransformAction implements TransformAction { + @InputArtifact abstract Provider getInputArtifact() + + @Override + void transform(TransformOutputs outputs) { + File input = inputArtifact.get().asFile + File output = outputs.file(input.name) + output.bytes = input.bytes + } + } + """.stripIndent() + + file("app/src/main/java/com/company/Main.java") << """ + package com.company; + + public class Main { + public static void main(String[] args) { + Utils.foo(); + } + } + """.stripIndent() + + when: + runWithSuccess(":app:shadowJar") + + then: + File outputJar = getFile("app/build/libs/app-all.jar") + outputJar.exists() + contains(outputJar, [ + "com/company/Main.class", + "com/company/Utils.class", + "META-INF/MANIFEST.MF" + ]) + } } From 9f1d458185c73251a659a01b5b5fcedf382b2bda Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:58:50 +0000 Subject: [PATCH 63/72] Fix Log4j2PluginsCacheFileTransformer not working for merging Log4j2Plugins.dat files (#1955) * Initial plan * Port PR #1175 fixes to Groovy Log4j2PluginsCacheFileTransformer Co-authored-by: Goooler <10363352+Goooler@users.noreply.github.com> * Fix Log4j2PluginsCacheFileTransformer merging issue Add a fix for Log4j2PluginsCacheFileTransformer issue. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Goooler <10363352+Goooler@users.noreply.github.com> Co-authored-by: Zongle Wang --- src/docs/changes/README.md | 1 + .../Log4j2PluginsCacheFileTransformer.groovy | 56 ++++++++----- ...g4j2PluginsCacheFileTransformerSpec.groovy | 80 +++++++++++++++---- 3 files changed, 101 insertions(+), 36 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 213cfe849..17d5d2a20 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -7,6 +7,7 @@ - Fix compatibility with Isolated Projects. ([#1947](https://github.com/GradleUp/shadow/pull/1947)) - Fix interaction with Gradle artifact transforms. ([#1949](https://github.com/GradleUp/shadow/pull/1949)) +- Fix `Log4j2PluginsCacheFileTransformer` not working for merging `Log4j2Plugins.dat` files. ([#1955](https://github.com/GradleUp/shadow/pull/1955)) ## [v8.3.10] (2026-02-26) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.groovy index 7b2d831f8..60afccb66 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.groovy @@ -33,18 +33,23 @@ import org.gradle.api.file.FileTreeElement import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE /** - * Modified from the maven equivalent to work with gradle + * Modified from Log4j2PluginCacheFileTransformer.java. * * @author Paul Nelson Baker * @see LinkedIn * @see GitHub - * @see edwgiz/maven-shaded-log4j-transformer - * @see PluginsCacheFileTransformer.java */ @CacheableTransformer class Log4j2PluginsCacheFileTransformer implements Transformer { + /** + * Log4j config files to share across the transformation stages. + */ private final List temporaryFiles + + /** + * {@link Relocator} instances to share across the transformation stages. + */ private final List relocators private ShadowStats stats @@ -56,7 +61,7 @@ class Log4j2PluginsCacheFileTransformer implements Transformer { @Override boolean canTransformResource(FileTreeElement element) { - return PLUGIN_CACHE_FILE == element.name + return PLUGIN_CACHE_FILE == element.relativePath.pathString } @Override @@ -80,27 +85,28 @@ class Log4j2PluginsCacheFileTransformer implements Transformer { } } + /** + * @return {@code true} if any dat file collected. + */ @Override boolean hasTransformedResource() { - // This functionality matches the original plugin, however, I'm not clear what - // the exact logic is. From what I can tell temporaryFiles should be never be empty - // if anything has been performed. - def hasTransformedMultipleFiles = temporaryFiles.size() > 1 - def hasAtLeastOneFileAndRelocator = !temporaryFiles.isEmpty() && !relocators.isEmpty() - def hasTransformedResources = hasTransformedMultipleFiles || hasAtLeastOneFileAndRelocator - return hasTransformedResources + return !temporaryFiles.isEmpty() } @Override void modifyOutputStream(ZipOutputStream zipOutputStream, boolean preserveFileTimestamps) { - PluginCache pluginCache = new PluginCache() - pluginCache.loadCacheFiles(getUrlEnumeration()) - relocatePlugins(pluginCache) - ZipEntry entry = new ZipEntry(PLUGIN_CACHE_FILE) - entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) - zipOutputStream.putNextEntry(entry) - pluginCache.writeCache(CloseShieldOutputStream.wrap(zipOutputStream)) - temporaryFiles.clear() + try { + PluginCache aggregator = new PluginCache() + aggregator.loadCacheFiles(getUrlEnumeration()) + relocatePlugins(aggregator) + ZipEntry entry = new ZipEntry(PLUGIN_CACHE_FILE) + entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) + zipOutputStream.putNextEntry(entry) + // prevent the aggregator to close the jar output. + aggregator.writeCache(CloseShieldOutputStream.wrap(zipOutputStream)) + } finally { + deleteTempFiles() + } } private Enumeration getUrlEnumeration() { @@ -108,7 +114,17 @@ class Log4j2PluginsCacheFileTransformer implements Transformer { return Collections.enumeration(urls) } - private void relocatePlugins(PluginCache pluginCache) { + private void deleteTempFiles() { + def iterator = temporaryFiles.listIterator() + while (iterator.hasNext()) { + def file = iterator.next() + file.delete() + iterator.remove() + } + } + + // Package-private for testing. + void relocatePlugins(PluginCache pluginCache) { for (Map currentMap : pluginCache.getAllCategories().values()) { pluginEntryLoop: for (PluginEntry currentPluginEntry : currentMap.values()) { diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy index a9659a85e..99f0283d1 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerSpec.groovy @@ -5,18 +5,17 @@ import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator import org.apache.logging.log4j.core.config.plugins.processor.PluginCache import org.apache.tools.zip.ZipOutputStream -import spock.lang.Specification +import spock.lang.Unroll + +import java.util.jar.JarInputStream import static java.util.Collections.singletonList import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE /** - * @author Paul Nelson Baker - * @since 2018-08 - * @see GitHub - * @see LinkedIn + * Modified from Log4j2PluginCacheFileTransformerTest.java. */ -class Log4j2PluginsCacheFileTransformerSpec extends Specification { +class Log4j2PluginsCacheFileTransformerSpec extends TransformerSpecSupport { Log4j2PluginsCacheFileTransformer transformer @@ -24,24 +23,49 @@ class Log4j2PluginsCacheFileTransformerSpec extends Specification { transformer = new Log4j2PluginsCacheFileTransformer() } - void "should not transformer"() { + void "canTransformResource"() { + expect: + !transformer.canTransformResource(getFileElement("")) + !transformer.canTransformResource(getFileElement(".")) + !transformer.canTransformResource(getFileElement("tmp.dat")) + !transformer.canTransformResource(getFileElement("${PLUGIN_CACHE_FILE}.tmp")) + !transformer.canTransformResource(getFileElement("tmp/${PLUGIN_CACHE_FILE}")) + transformer.canTransformResource(getFileElement(PLUGIN_CACHE_FILE)) + } + + void "transformAndModifyOutputStream"() { + expect: + !transformer.hasTransformedResource() + when: transformer.transform(new TransformerContext(PLUGIN_CACHE_FILE, getResourceStream(PLUGIN_CACHE_FILE), null)) + transformer.transform(new TransformerContext(PLUGIN_CACHE_FILE, getResourceStream(PLUGIN_CACHE_FILE), null)) then: - !transformer.hasTransformedResource() - } - - void "should transform"() { - given: - List relocators = new ArrayList<>() - relocators.add(new SimpleRelocator(null, null, null, null)) + transformer.hasTransformedResource() when: - transformer.transform(new TransformerContext(PLUGIN_CACHE_FILE, getResourceStream(PLUGIN_CACHE_FILE), relocators)) + def jarBuff = new ByteArrayOutputStream() + new ZipOutputStream(jarBuff).withCloseable { zos -> + transformer.modifyOutputStream(zos, false) + } + def foundEntry = findEntry(jarBuff) then: - transformer.hasTransformedResource() + foundEntry != null + } + + private static String findEntry(ByteArrayOutputStream jarBuff) { + new JarInputStream(new ByteArrayInputStream(jarBuff.toByteArray())).withCloseable { jarIn -> + def entry = jarIn.nextJarEntry + while (entry != null) { + if (entry.name == PLUGIN_CACHE_FILE) { + return entry.name + } + entry = jarIn.nextJarEntry + } + return null + } } void "relocate classes inside DAT file"() { @@ -77,10 +101,34 @@ class Log4j2PluginsCacheFileTransformerSpec extends Specification { cache.loadCacheFiles(Collections.enumeration([new URL(urlString)])) cache.getCategory("lookup")["date"].className == "new.location.org.apache.logging.log4j.core.lookup.DateLookup" + } + @Unroll + void "relocations [#pattern -> #shadedPattern expects #target]"() { + given: + PluginCache aggregator = new PluginCache() + aggregator.loadCacheFiles(Collections.enumeration([getResourceUrl(PLUGIN_CACHE_FILE)])) + transformer.transform(new TransformerContext(PLUGIN_CACHE_FILE, getResourceStream(PLUGIN_CACHE_FILE), [new SimpleRelocator(pattern, shadedPattern, null, null)], new ShadowStats())) + transformer.relocatePlugins(aggregator) + + expect: + for (def pluginEntryMap : aggregator.allCategories.values()) { + for (def entry : pluginEntryMap.values()) { + assert entry.className.startsWith(target) + } + } + + where: + pattern | shadedPattern | target + "org.apache.logging" | "new.location.org.apache.logging" | "new.location.org.apache.logging" + "com.apache.logging" | "new.location.com.apache.logging" | "org.apache.logging" } InputStream getResourceStream(String resource) { return this.class.getClassLoader().getResourceAsStream(resource) } + + URL getResourceUrl(String resource) { + return this.class.getClassLoader().getResource(resource) + } } From 2f6f1f510c6c44df491c3aefbbe516e0a10fc733 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 20:02:53 +0800 Subject: [PATCH 64/72] Deprecate KnowsTask (#1957) * Initial plan * Deprecate KnowsTask with @Deprecated annotation and warning log Co-authored-by: Goooler <10363352+Goooler@users.noreply.github.com> * Update src/docs/changes/README.md --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Goooler <10363352+Goooler@users.noreply.github.com> Co-authored-by: Zongle Wang --- src/docs/changes/README.md | 4 ++++ .../jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 17d5d2a20..3c6e4c007 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,10 @@ ## [Unreleased] +**Deprecated** + +- Deprecate `KnowsTask`, it will be removed in the next major release. ([#1957](https://github.com/GradleUp/shadow/pull/1957)) + **Fixed** - Fix compatibility with Isolated Projects. ([#1947](https://github.com/GradleUp/shadow/pull/1947)) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy index 4a103ffe0..0c7a646ea 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy @@ -4,6 +4,10 @@ import org.codehaus.groovy.reflection.ReflectionUtils import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction +/** + * @deprecated This task will be removed in the next major release. + */ +@Deprecated class KnowsTask extends DefaultTask { public static final String NAME = "knows" @@ -11,6 +15,7 @@ class KnowsTask extends DefaultTask { @TaskAction def knows() { + logger.warn("The '{}' task has been deprecated and will be removed in the next major release.", NAME) println "\nNo, The Shadow Knows...." println ReflectionUtils.getCallingClass(0).getResourceAsStream("/shadowBanner.txt").text } From 7dfc2a97b97cdd4563d29258c678f7430b6efbde Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Thu, 28 May 2026 12:18:07 +0800 Subject: [PATCH 65/72] Update jdependency to support Java 27 (#2040) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> (cherry picked from commit a3eaee21934da6933df525e724679b71dade9556) --- build.gradle.kts | 2 +- src/docs/changes/README.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4408dd8b0..114687817 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -78,7 +78,7 @@ dependencies { implementation("org.codehaus.plexus:plexus-utils:4.0.2") implementation("org.codehaus.plexus:plexus-xml:4.1.1") implementation("org.apache.logging.log4j:log4j-core:2.25.3") - implementation("org.vafer:jdependency:2.15") + implementation("org.vafer:jdependency:2.16") testImplementation("org.spockframework:spock-core:2.4-groovy-4.0") { exclude(group = "org.codehaus.groovy") diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 3c6e4c007..3ca262cb9 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,10 @@ ## [Unreleased] +**Changed** + +- Update jdependency to support Java 27. ([#2040](https://github.com/GradleUp/shadow/pull/2040)) + **Deprecated** - Deprecate `KnowsTask`, it will be removed in the next major release. ([#1957](https://github.com/GradleUp/shadow/pull/1957)) From 62f3d95a190a511a91b1a3385e0145f3f1167473 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Thu, 28 May 2026 13:42:55 +0800 Subject: [PATCH 66/72] Update Gradle to 9.5.1 (#2041) * (cherry picked from commit fa41bec4a3c5205bc9a4540ed37924616c2ad78a) * (cherry picked from commit 881f4efe5005e0c2c9f0bad6b9d7f0d7a55d074e) * Fix validatePlugins for JavaJarExec * Fix `publish multiproject shadow jar with maven-publish plugin` test Add Maven publication configuration for project 'b' ``` Declaring a dependency on an unpublished project has been deprecated. This will fail with an error in Gradle 10. A dependency was declared on project ':b', but that project does not declare any publications. Ensure project ':b' declares at least one publication. Consult the upgrading guide for further information: https://docs.gradle.org/9.5.1/userguide/upgrading_version_9.html#publishing_dependency_on_unpublished_project at org.gradle.api.internal.artifacts.ivyservice.projectmodule.DefaultProjectDependencyPublicationResolver.getImplicitCoordinates(DefaultProjectDependencyPublicationResolver.java:147) at org.gradle.api.internal.artifacts.ivyservice.projectmodule.DefaultProjectDependencyPublicationResolver.createCoordinateResolver(DefaultProjectDependencyPublicationResolver.java:108) at org.gradle.api.internal.artifacts.ivyservice.projectmodule.DefaultProjectDependencyPublicationResolver.lambda$withCoordinateResolver$1(DefaultProjectDependencyPublicationResolver.java:97) at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) at org.gradle.api.internal.artifacts.ivyservice.projectmodule.DefaultProjectDependencyPublicationResolver$VariantCoordinateResolverCache.computeIfAbsent(DefaultProjectDependencyPublicationResolver.java:369) at org.gradle.api.internal.artifacts.ivyservice.projectmodule.DefaultProjectDependencyPublicationResolver.lambda$withCoordinateResolver$2(DefaultProjectDependencyPublicationResolver.java:96) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$fromMutableState$1(DefaultProjectStateRegistry.java:450) at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:300) ``` * Tweak reasons --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.jar | Bin 45457 -> 48462 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 5 +- gradlew.bat | 176 ++++++++---------- .../shadow/internal/JavaJarExec.groovy | 5 + .../plugins/shadow/tasks/KnowsTask.groovy | 2 + .../plugins/shadow/PublishingSpec.groovy | 8 + 7 files changed, 101 insertions(+), 99 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8bdaf60c75ab801e22807dde59e12a8735a34077..b1b8ef56b44f16b14dc800fa8103a6d89abb526f 100644 GIT binary patch delta 39796 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ɵ=r6CZm*ctobRli@Q9X4qo$){P6@xZ0Eq-I) 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%0Aonjyf`q#Bg+;H(_UceX22V^&|e4K_eG#r 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 I`1hxO0p@%Q`v3p{ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bad7c2462..df6a6ad76 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index ef07e0162..b9bb139f7 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index 5eed7ee84..24c62d56f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,94 +1,82 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH= - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy index 28ed02308..c931c5ac5 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/JavaJarExec.groovy @@ -2,11 +2,16 @@ package com.github.jengelman.gradle.plugins.shadow.internal import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault +@DisableCachingByDefault(because = "Not worth caching") abstract class JavaJarExec extends JavaExec { @InputFile + @PathSensitive(PathSensitivity.RELATIVE) File jarFile @Override diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy index 0c7a646ea..71a68a990 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/tasks/KnowsTask.groovy @@ -3,11 +3,13 @@ package com.github.jengelman.gradle.plugins.shadow.tasks import org.codehaus.groovy.reflection.ReflectionUtils import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault /** * @deprecated This task will be removed in the next major release. */ @Deprecated +@DisableCachingByDefault(because = "Not worth caching") class KnowsTask extends DefaultTask { public static final String NAME = "knows" diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy index e62e5fa02..2f11c2aed 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/PublishingSpec.groovy @@ -168,6 +168,14 @@ class PublishingSpec extends PluginSpecification { file('b/build.gradle') << """ $publishingBlock + + publishing { + publications { + maven(MavenPublication) { + from components.java + } + } + } """.stripMargin() file('b/src/main/resources/b.properties') << 'b' From 57934197e774f4a0731da3da0f9b1a2615bcb6fc Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 27 Feb 2026 20:22:25 +0800 Subject: [PATCH 67/72] Change Maven Central deployment validation to NONE (cherry picked from commit f8d019b064ea4726398ba6aca5c6731b83d881ed) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 714124d9f..9083059fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ org.gradle.tooling.parallel=true ########## Properties for publishing to Maven Central ########## mavenCentralAutomaticPublishing=true -mavenCentralDeploymentValidation=PUBLISHED +mavenCentralDeploymentValidation=NONE mavenCentralPublishing=true signAllPublications=true From bfd53393a4a471fa0646ab503ba3ebe83b2fab54 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 19:05:19 +0800 Subject: [PATCH 68/72] Update pluginPublish to v2.1.0 (#1959) * Update pluginPublish to v2.1.0 * Declare `compatibility { features { configurationCache = true } }` https://plugins.gradle.org/docs/publish-plugin --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler (cherry picked from commit 5148dbb9ae6051eadd859e079641b7110b859a08) --- build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 114687817..12edd6aae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ import org.gradle.api.plugins.JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME plugins { groovy `java-gradle-plugin` - id("com.gradle.plugin-publish") version "2.0.0" + id("com.gradle.plugin-publish") version "2.1.0" id("com.vanniktech.maven.publish") version "0.36.0" id("com.diffplug.spotless") version "8.2.1" } @@ -31,6 +31,7 @@ gradlePlugin { displayName = providers.gradleProperty("POM_NAME").get() description = providers.gradleProperty("POM_DESCRIPTION").get() tags = listOf("onejar", "shade", "fatjar", "uberjar") + compatibility { features { configurationCache = true } } } } } From b2692064e1006410183e699d9778f321588b3764 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 28 May 2026 13:54:33 +0800 Subject: [PATCH 69/72] Remove redundant plugin id --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 12edd6aae..c68048012 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,7 @@ import org.gradle.api.plugins.JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.JAVADOC_ELEMENTS_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME +import org.gradle.plugin.compatibility.compatibility plugins { groovy @@ -25,8 +26,7 @@ gradlePlugin { vcsUrl = providers.gradleProperty("POM_URL") plugins { - create("shadowPlugin") { - id = "com.gradleup.shadow" + create("com.gradleup.shadow") { implementationClass = "com.github.jengelman.gradle.plugins.shadow.ShadowPlugin" displayName = providers.gradleProperty("POM_NAME").get() description = providers.gradleProperty("POM_DESCRIPTION").get() From ac6bc8efbb3097d4b1384c1b6b7ff8b10d55eb36 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Mon, 2 Mar 2026 19:17:25 +0800 Subject: [PATCH 70/72] Change git push command for releasing (#1945) Updated git push command to use --follow-tags. (cherry picked from commit 6a52076e2e4385e786e79a16e1f81320fb7ace81) --- RELEASING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASING.md b/RELEASING.md index d2e3438fc..63363595b 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -30,7 +30,7 @@ 7. Push! ```sh - git push && git push --tags + git push --follow-tags ``` This will trigger a GitHub Action workflow which will create a GitHub release and upload the From 1aa766cb6a61b6c07f61c7ce976adb73b3f8328f Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 28 May 2026 14:02:37 +0800 Subject: [PATCH 71/72] Prepare version 8.3.11 --- gradle.properties | 2 +- src/docs/changes/README.md | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9083059fc..188dc48c8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ signAllPublications=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.10 +VERSION_NAME=8.3.11 POM_NAME=Shadow Gradle Plugin POM_DESCRIPTION=Gradle plugin to create fat/uber JARs, apply file transforms, and relocate packages for applications and libraries. Gradle version of Maven's Shade plugin. diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 3ca262cb9..89cd54bc7 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,7 +1,10 @@ # Change Log -## [Unreleased] +## [v8.3.11] (2026-05-28) + +> [!WARNING] +> Only Gradle 9 support is being backported to this version. No additional features or crucial bug fixes will be included in the 8.x line. Please migrate to Shadow 9 as soon as possible. **Changed** @@ -485,7 +488,8 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = " Date: Thu, 28 May 2026 14:03:37 +0800 Subject: [PATCH 72/72] Prepare next development version --- gradle.properties | 2 +- src/docs/changes/README.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 188dc48c8..9ced65597 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ signAllPublications=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=8.3.11 +VERSION_NAME=8.3.12-SNAPSHOT POM_NAME=Shadow Gradle Plugin POM_DESCRIPTION=Gradle plugin to create fat/uber JARs, apply file transforms, and relocate packages for applications and libraries. Gradle version of Maven's Shade plugin. diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 89cd54bc7..40440f60e 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -1,6 +1,9 @@ # Change Log +## [Unreleased] + + ## [v8.3.11] (2026-05-28) > [!WARNING]