diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c8956e2a..337997ca0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,10 +14,10 @@ jobs: matrix: os: [ ubuntu-24.04-arm, windows-latest ] # Test on the minimum Gradle version and the latest. - gradle: [ 9.0.0, current ] + gradle: [ 9.1.0, current ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-java@v5 with: distribution: 'zulu' @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-24.04-arm if: github.event.repository.fork == false && github.ref == 'refs/heads/main' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-java@v5 with: distribution: 'zulu' diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e9467afe9..737eec013 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,7 +14,7 @@ jobs: id-token: write pages: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: gradle/actions/setup-gradle@v6 with: cache-read-only: true @@ -25,7 +25,7 @@ jobs: # Don't cache it to track updates. pip install mkdocs-material mkdocs build - - uses: actions/upload-pages-artifact@v4 + - uses: actions/upload-pages-artifact@v5 with: path: site - uses: actions/deploy-pages@v5 diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 2a516a472..aeff00ae1 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -19,10 +19,10 @@ on: jobs: check-links: - runs-on: ubuntu-latest # TODO: https://github.com/UmbrellaDocs/linkspector/issues/149 + runs-on: ubuntu-24.04-arm if: github.event.repository.fork == false steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: gradle/actions/setup-gradle@v6 with: cache-read-only: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 86629bb39..319711ca5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-java@v5 with: distribution: 'zulu' diff --git a/build.gradle.kts b/build.gradle.kts index 79b1e7fa1..4cff93e31 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,7 +29,7 @@ dokka { dokkaPublications.html { outputDirectory = rootDir.resolve("docs/api") } kotlin { explicitApi() - @OptIn(ExperimentalAbiValidation::class) abiValidation { enabled = true } + @OptIn(ExperimentalAbiValidation::class) abiValidation() val jdkRelease = "17" compilerOptions { allWarningsAsErrors = true @@ -60,13 +60,15 @@ spotless { kotlinGradle { ktfmt(libs.ktfmt.get().version).googleStyle() } } -val testPluginClasspath by configurations.registering { - isCanBeResolved = true - description = "Plugins used in integration tests could be resolved in classpath." -} +val testPluginClasspath = + configurations.register("testPluginClasspath") { + isCanBeResolved = true + description = "Plugins used in integration tests could be resolved in classpath." + extendsFrom(configurations.compileOnly) + } -val testKit by sourceSets.creating -val testKitImplementation by configurations.getting +val testKit = sourceSets.register("testKit") +val testKitImplementation = configurations.named("testKitImplementation") configurations.configureEach { when (name) { @@ -129,8 +131,6 @@ dependencies { testKitImplementation(libs.assertk) testPluginClasspath(libs.foojayResolver) - testPluginClasspath(libs.develocity) - testPluginClasspath(libs.kotlin.gradlePlugin) testPluginClasspath(libs.pluginPublish) lintChecks(libs.androidx.gradlePluginLints) @@ -178,7 +178,7 @@ testing.suites { withType().configureEach { useJUnitJupiter(libs.junit.bom.map { checkNotNull(it.version) }) dependencies { - implementation(testKit.output) + implementation(testKit.get().output) implementation(libs.assertk) } targets.configureEach { @@ -214,7 +214,7 @@ gradlePlugin { // This part should be placed after testing.suites to ensure the test sourceSets are created. kotlin.target.compilations { - val main by getting + val main = getByName("main") getByName("functionalTest") { // Import main and its classpath as dependencies and establish internal visibility. associateWith(main) diff --git a/docs/about/README.md b/docs/about/README.md index 2bf0973e7..bfc545d22 100644 --- a/docs/about/README.md +++ b/docs/about/README.md @@ -19,7 +19,7 @@ so Shadow was published there. ## Maintainers * [John Engelman](https://github.com/johnrengelman) -* [Goooler](https://github.com/Goooler) +* [Zongle Wang](https://github.com/Goooler) ## Contributors diff --git a/docs/changes/README.md b/docs/changes/README.md index 93aa5aaf8..ce6a2f170 100644 --- a/docs/changes/README.md +++ b/docs/changes/README.md @@ -1,6 +1,12 @@ # Change Log +## [9.4.3](https://github.com/GradleUp/shadow/releases/tag/9.4.3) - 2026-06-26 + +### Changed + +- Update dependencies for resolving CVEs. ([#2069](https://github.com/GradleUp/shadow/pull/2069)) + ## [9.4.2](https://github.com/GradleUp/shadow/releases/tag/9.4.2) - 2026-05-28 ### Changed @@ -716,7 +722,7 @@ type. ``` - [Cédric Champeau](https://github.com/melix) - Support Gradle 7 [#624](https://github.com/GradleUp/shadow/pull/624) -- [Daniel Oakey](https://github.com/danieloakey) - Close `FileInputStream` when remapping close to avoid classloader +- [Daniel Oakey](https://github.com/ghost) - Close `FileInputStream` when remapping close to avoid classloader locks [#642](https://github.com/GradleUp/shadow/pull/642) - [Maximilian Müller](https://github.com/maxm123) - Groovy error in `ServiceFileTransformer` in Gradle 3 [#655](https://github.com/GradleUp/shadow/pull/655) diff --git a/docs/configuration/README.md b/docs/configuration/README.md index c0d205521..06770b18e 100644 --- a/docs/configuration/README.md +++ b/docs/configuration/README.md @@ -126,7 +126,7 @@ configure the upstream. === "Kotlin" ```kotlin - val testJar by tasks.registering(Jar::class) { + val testJar = tasks.register("testJar") { manifest { attributes["Description"] = "This is an application JAR" } diff --git a/docs/configuration/dependencies/README.md b/docs/configuration/dependencies/README.md index 2b62f575f..b7a87f6b3 100644 --- a/docs/configuration/dependencies/README.md +++ b/docs/configuration/dependencies/README.md @@ -123,7 +123,7 @@ configuration. === "Kotlin" ```kotlin - val nonJar by configurations.creating + val nonJar = configurations.create("nonJar") // This is necessary to make the dependencies in `nonJar` available at compile time. // If you don't need that, you can skip this step. diff --git a/docs/configuration/merging/README.md b/docs/configuration/merging/README.md index 43ca7f27c..ae62f31b9 100644 --- a/docs/configuration/merging/README.md +++ b/docs/configuration/merging/README.md @@ -582,6 +582,38 @@ You can use `include`/`exclude` and more methods to configure the patterns for t } ``` +## Finding Resources in the Classpath + +When dealing with resource merge conflicts, it can be helpful to find which dependencies contain the conflicting resources. +Shadow provides a [`FindResourceInClasspath`][FindResourceInClasspath] helper task for this purpose. + +To scan for resources, register a [`FindResourceInClasspath`][FindResourceInClasspath] task in your build script and configure its `classpath` and the resource patterns to look for: + +=== "Kotlin" + + ```kotlin + tasks.register("findResources") { + classpath.from(configurations.runtimeClasspath) + include("META-INF/services/org.codehaus.groovy.runtime.ExtensionModule") + } + ``` + +=== "Groovy" + + ```groovy + tasks.register('findResources', com.github.jengelman.gradle.plugins.shadow.tasks.FindResourceInClasspath) { + classpath.from(configurations.runtimeClasspath) + include 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule' + } + ``` + +You can then run the task to scan each entry on the classpath and print any matched resources to the console: + +```shell +./gradlew findResources +``` + + [AbstractCopyTask]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.AbstractCopyTask.html [Jar.eachFile]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:eachFile(org.gradle.api.Action) @@ -589,6 +621,7 @@ You can use `include`/`exclude` and more methods to configure the patterns for t [Jar.filesNotMatching]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:filesNotMatching(java.lang.Iterable,%20org.gradle.api.Action) [AppendingTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-appending-transformer/index.html [DuplicatesStrategy]: https://docs.gradle.org/current/javadoc/org/gradle/api/file/DuplicatesStrategy.html +[FindResourceInClasspath]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-find-resource-in-classpath/index.html [GroovyExtensionModuleTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-groovy-extension-module-transformer/index.html [Jar]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html [Log4j2PluginsCacheFileTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-log4j2-plugins-cache-file-transformer/index.html diff --git a/docs/custom-tasks/README.md b/docs/custom-tasks/README.md index a9e56b138..378d67910 100644 --- a/docs/custom-tasks/README.md +++ b/docs/custom-tasks/README.md @@ -8,7 +8,7 @@ the output. === "Kotlin" ```kotlin - val testShadowJar by tasks.registering(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) { + val testShadowJar = tasks.register("testShadowJar") { description = "Create a combined JAR of project and test dependencies" archiveClassifier = "test" @@ -64,7 +64,7 @@ source code. This is accomplished by creating a custom [`ShadowJar`][ShadowJar] === "Kotlin" ```kotlin - tasks.registering(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) { + val dependencyShadowJar = tasks.register("dependencyShadowJar") { description = "Create a shadow JAR of all dependencies" archiveClassifier = "dep" configurations = project.configurations.runtimeClasspath.map { listOf(it) } diff --git a/docs/kotlin-plugins/README.md b/docs/kotlin-plugins/README.md index cc7785e88..339865136 100644 --- a/docs/kotlin-plugins/README.md +++ b/docs/kotlin-plugins/README.md @@ -80,18 +80,17 @@ automatically configure additional tasks for bundling the shadowed JAR for its ` val ktorVersion = "3.1.0" kotlin { - @Suppress("OPT_IN_USAGE") jvm().mainRun { // Optionally, set the main class for `runJvm`. mainClass = "myapp.MainKt" } sourceSets { - val commonMain by getting { + commonMain { dependencies { implementation("io.ktor:ktor-client-core:$ktorVersion") } } - val jvmMain by getting { + jvmMain { dependencies { implementation("io.ktor:ktor-client-okhttp:$ktorVersion") } diff --git a/docs/publishing/README.md b/docs/publishing/README.md index 06112ad68..28028c22b 100644 --- a/docs/publishing/README.md +++ b/docs/publishing/README.md @@ -398,7 +398,7 @@ It is possible to publish a custom [`ShadowJar`][ShadowJar] task's output via th id("com.gradleup.shadow") } - val testShadowJar by tasks.registering(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) { + val testShadowJar = tasks.register("testShadowJar") { description = "Create a combined JAR of project and test dependencies" archiveClassifier = "tests" from(sourceSets.test.map { it.output }) diff --git a/gradle.properties b/gradle.properties index d5ea87743..00522ff84 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,9 +7,7 @@ org.gradle.configuration-cache=true org.gradle.configuration-cache.parallel=true org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx4g org.gradle.kotlin.dsl.allWarningsAsErrors=true -org.gradle.parallel=true org.gradle.tooling.parallel=true -org.gradle.unsafe.isolated-projects=true ########## Properties for publishing to Maven Central ########## @@ -20,7 +18,7 @@ signAllPublications=true GROUP=com.gradleup.shadow POM_ARTIFACT_ID=shadow-gradle-plugin -VERSION_NAME=9.4.2 +VERSION_NAME=9.4.3 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/gradle/libs.versions.toml b/gradle/libs.versions.toml index f9a41b833..9a448c2c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,41 +1,41 @@ [versions] minGradle = "9.0.0" -kotlin = "2.3.20" +kotlin = "2.4.0" moshi = "1.15.2" pluginPublish = "2.1.1" [libraries] -apache-ant = "org.apache.ant:ant:1.10.15" -apache-commonsCodec = "commons-codec:commons-codec:1.21.0" -apache-commonsIo = "commons-io:commons-io:2.21.0" -apache-log4j = "org.apache.logging.log4j:log4j-core:2.25.3" -apache-maven-model = "org.apache.maven:maven-model:3.9.14" +apache-ant = "org.apache.ant:ant:1.10.17" +apache-commonsCodec = "commons-codec:commons-codec:1.22.0" +apache-commonsIo = "commons-io:commons-io:2.22.0" +apache-log4j = "org.apache.logging.log4j:log4j-core:2.26.0" +apache-maven-model = "org.apache.maven:maven-model:3.9.16" jdependency = "org.vafer:jdependency:2.16" jdom2 = "org.jdom:jdom2:2.0.6.1" kotlin-metadata = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version.ref = "kotlin" } kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } -plexus-utils = "org.codehaus.plexus:plexus-utils:4.0.2" +plexus-utils = "org.codehaus.plexus:plexus-utils:4.0.3" plexus-xml = "org.codehaus.plexus:plexus-xml:4.1.1" -xmlunit = "org.xmlunit:xmlunit-legacy:2.11.0" +xmlunit = "org.xmlunit:xmlunit-legacy:2.12.0" moshi = { module = "com.squareup.moshi:moshi", version.ref = "moshi" } moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi" } foojayResolver = "org.gradle.toolchains.foojay-resolver-convention:org.gradle.toolchains.foojay-resolver-convention.gradle.plugin:1.0.0" -develocity = "com.gradle:develocity-gradle-plugin:4.4.0" +develocity = "com.gradle:develocity-gradle-plugin:4.4.3" kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } pluginPublish = { module = "com.gradle.publish:plugin-publish-plugin", version.ref = "pluginPublish" } -androidx-gradlePluginLints = "androidx.lint:lint-gradle:1.0.0-alpha05" +androidx-gradlePluginLints = "androidx.lint:lint-gradle:1.0.0" # Dummy to get renovate updates, the version is used in rootProject build.gradle with spotless. -ktfmt = "com.facebook:ktfmt:0.62" +ktfmt = "com.facebook:ktfmt:0.64" -junit-bom = "org.junit:junit-bom:6.0.3" +junit-bom = "org.junit:junit-bom:6.1.0" assertk = "com.willowtreeapps.assertk:assertk:0.28.1" [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } -android-lint = "com.android.lint:9.1.0" +android-lint = "com.android.lint:9.2.1" jetbrains-dokka = "org.jetbrains.dokka:2.2.0" -mavenPublish = "com.vanniktech.maven.publish:0.36.0" +mavenPublish = "com.vanniktech.maven.publish:0.37.0" pluginPublish = { id = "com.gradle.plugin-publish", version.ref = "pluginPublish" } -spotless = "com.diffplug.spotless:8.4.0" +spotless = "com.diffplug.spotless:8.7.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d997cfc60..b1b8ef56b 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c61a118f7..eb84db68d 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.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 739907dfd..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/2d6327017519d23b96af35865dc997fcb544fb40/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/. diff --git a/gradlew.bat b/gradlew.bat index c4bdd3ab8..24c62d56f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -23,8 +23,8 @@ @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ 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 +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,7 +65,7 @@ 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 +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line @@ -73,21 +73,10 @@ goto fail @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +@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 -: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 +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/settings.gradle.kts b/settings.gradle.kts index 90b28d6eb..2f4dd1cd4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,7 +12,7 @@ pluginManagement { } } -plugins { id("com.gradle.develocity") version "4.4.0" } +plugins { id("com.gradle.develocity") version "4.4.3" } develocity { buildScan { @@ -39,4 +39,6 @@ dependencyResolutionManagement { rootProject.name = "shadow" +enableFeaturePreview("NO_IMPLICIT_LOOKUP_IN_PARENT_PROJECTS") + enableFeaturePreview("STABLE_CONFIGURATION_CACHE") diff --git a/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/CodeSnippetExtractor.kt b/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/CodeSnippetExtractor.kt index b5d253816..09364e3d5 100644 --- a/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/CodeSnippetExtractor.kt +++ b/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/CodeSnippetExtractor.kt @@ -2,7 +2,6 @@ package com.github.jengelman.gradle.plugins.shadow.snippet import java.nio.file.Path import java.util.regex.Pattern -import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.Path import kotlin.io.path.name import kotlin.io.path.readText @@ -12,7 +11,6 @@ import kotlin.io.path.walk object CodeSnippetExtractor { private val docRoot = Path(System.getProperty("DOCS_DIR")) - @OptIn(ExperimentalPathApi::class) private val markdownPaths = docRoot.walk().filter { it.name.endsWith(".md", ignoreCase = true) }.toList() diff --git a/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/SnippetExecutable.kt b/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/SnippetExecutable.kt index ed9b81655..0eba030e7 100644 --- a/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/SnippetExecutable.kt +++ b/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/snippet/SnippetExecutable.kt @@ -1,6 +1,7 @@ package com.github.jengelman.gradle.plugins.shadow.snippet import com.github.jengelman.gradle.plugins.shadow.testkit.assertNoDeprecationWarnings +import com.github.jengelman.gradle.plugins.shadow.testkit.enableNoImplicitLookupInParentProjects import com.github.jengelman.gradle.plugins.shadow.testkit.gradleRunner import java.nio.file.Path import java.util.jar.JarOutputStream @@ -48,6 +49,8 @@ sealed class SnippetExecutable : Executable { } include ':api', ':main' rootProject.name = 'snippet' + $enableNoImplicitLookupInParentProjects + enableFeaturePreview 'STABLE_CONFIGURATION_CACHE' enableFeaturePreview 'TYPESAFE_PROJECT_ACCESSORS' """ .trimIndent() @@ -61,25 +64,24 @@ sealed class SnippetExecutable : Executable { projectRoot.addSubProject("api", apiScript) val (imports, withoutImports) = importsExtractor(snippet) - val mainScript = - buildString { - append(imports) - append(lineSeparator) - // All buildscript {} blocks must appear before any plugins {} blocks in the script. - if (withoutImports.contains("buildscript {")) { - append(withoutImports) - } else { - if (!withoutImports.contains("plugins {")) { - append(pluginsBlock) - append(lineSeparator) - } - append(withoutImports) - } - append(lineSeparator) - append(assembleDependsOn) + val mainScript = buildString { + append(imports) + append(lineSeparator) + // All buildscript {} blocks must appear before any plugins {} blocks in the script. + if (withoutImports.contains("buildscript {")) { + append(withoutImports) + } else { + if (!withoutImports.contains("plugins {")) { + append(pluginsBlock) append(lineSeparator) } - .trimIndent() + append(withoutImports) + } + append(lineSeparator) + append(assembleDependsOn) + append(lineSeparator) + } + .trimIndent() projectRoot.addSubProject("main", mainScript) projectRoot.resolve("main/foo.jar").createFile().also { // Dummy JAR file to ensure the project can be built. diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt index bfcc48a8e..ff0c213e4 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt @@ -18,7 +18,6 @@ import com.github.jengelman.gradle.plugins.shadow.util.isWindows import com.github.jengelman.gradle.plugins.shadow.util.runProcess import java.nio.file.Path import java.util.zip.ZipFile -import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.appendText import kotlin.io.path.invariantSeparatorsPathString import kotlin.io.path.isRegularFile @@ -27,18 +26,10 @@ import kotlin.io.path.relativeTo import kotlin.io.path.walk import kotlin.io.path.writeText import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.DisabledOnOs -import org.junit.jupiter.api.condition.OS class ApplicationPluginTest : BasePluginTest() { private lateinit var mainClass: String - @DisabledOnOs( - OS.WINDOWS, - architectures = ["aarch64"], - disabledReason = - "Cannot use toolchain on Windows ARM64", // TODO: remove when min Gradle is bumped to 9.2+ - ) @Test fun integrationWithApplicationPluginAndJavaToolchains() { prepare( @@ -355,7 +346,6 @@ class ApplicationPluginTest : BasePluginTest() { } private companion object { - @OptIn(ExperimentalPathApi::class) fun Path.walkEntries(includeDirs: Boolean = false): Sequence = walk() .filter { includeDirs || it.isRegularFile() } diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt index bfc12d07e..6059969cc 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt @@ -11,6 +11,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.SHAD import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.assertNoDeprecationWarnings import com.github.jengelman.gradle.plugins.shadow.testkit.commonGradleArgs +import com.github.jengelman.gradle.plugins.shadow.testkit.enableNoImplicitLookupInParentProjects import com.github.jengelman.gradle.plugins.shadow.testkit.gradleRunner import com.github.jengelman.gradle.plugins.shadow.testkit.requireResourceAsPath import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer @@ -178,6 +179,8 @@ abstract class BasePluginTest { buildCache { $buildCacheBlock } + $enableNoImplicitLookupInParentProjects + enableFeaturePreview 'STABLE_CONFIGURATION_CACHE' enableFeaturePreview 'TYPESAFE_PROJECT_ACCESSORS' $endBlock """ diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt index 39501d60b..06818ef0f 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt @@ -12,7 +12,6 @@ import com.github.jengelman.gradle.plugins.shadow.testkit.getMainAttr import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer import com.github.jengelman.gradle.plugins.shadow.util.Issue -import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.appendText import kotlin.io.path.isDirectory import kotlin.io.path.name @@ -474,7 +473,6 @@ class CachingTest : BasePluginTest() { private fun cleanOutputs() { runWithSuccess("clean") - @OptIn(ExperimentalPathApi::class) val buildDirs = projectRoot.walk().filter { it.isDirectory() && it.name == "build" } // Make sure build folders are deleted by clean task. assertThat(buildDirs).isEmpty() diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt index 84b763e4a..be9281630 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt @@ -47,7 +47,13 @@ class KotlinPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { val entries = - arrayOf("my/", "META-INF/my.kotlin_module", mainClassEntry, *junitEntries, *manifestEntries) + arrayOf( + "my/", + "META-INF/my_my.kotlin_module", + mainClassEntry, + *junitEntries, + *manifestEntries, + ) if (excludeStdlib) { containsOnly(*entries) } else { @@ -88,7 +94,13 @@ class KotlinPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { val entries = - arrayOf("my/", "META-INF/my.kotlin_module", mainClassEntry, *entriesInAB, *manifestEntries) + arrayOf( + "my/", + "META-INF/my_my.kotlin_module", + mainClassEntry, + *entriesInAB, + *manifestEntries, + ) if (excludeStdlib) { containsOnly(*entries) } else { @@ -129,8 +141,7 @@ class KotlinPluginsTest : BasePluginTest() { runWithSuccess(shadowJarPath) assertThat(outputShadowedJar).useAll { - val entries = - arrayOf("my/", "META-INF/my.kotlin_module", mainClassEntry, *entriesInAB, *manifestEntries) + val entries = arrayOf("my/", mainClassEntry, *entriesInAB, *manifestEntries) containsAtLeast(*entries) } } diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt index 754ce1caf..a790c6a79 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt @@ -44,8 +44,6 @@ import org.gradle.api.plugins.JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME import org.gradle.testkit.runner.BuildResult import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.DisabledOnOs -import org.junit.jupiter.api.condition.OS import org.junit.jupiter.api.io.TempDir import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource @@ -59,12 +57,6 @@ class PublishingTest : BasePluginTest() { settingsScript.appendText("rootProject.name = 'maven'$lineSeparator") } - @DisabledOnOs( - OS.WINDOWS, - architectures = ["aarch64"], - disabledReason = - "Cannot use toolchain on Windows ARM64", // TODO: remove when min Gradle is bumped to 9.2+ - ) @Test fun publishShadowJarWithCorrectTargetJvm() { projectScript.appendText( diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt index 68d23bc75..1a713a0b7 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt @@ -49,20 +49,19 @@ class RelocationTest : BasePluginTest() { .trimIndent() ) val entryPrefix = relocationPrefix.replace('.', '/') - val relocatedEntries = - buildSet { - addAll( - junitEntries - .map { "$entryPrefix/$it" } - .filterNot { it.startsWith("$entryPrefix/META-INF/") } - ) - var parent = entryPrefix - while (parent.isNotEmpty()) { - add("$parent/") - parent = parent.substringBeforeLast('/', "") - } - } - .toTypedArray() + val relocatedEntries = buildSet { + addAll( + junitEntries + .map { "$entryPrefix/$it" } + .filterNot { it.startsWith("$entryPrefix/META-INF/") } + ) + var parent = entryPrefix + while (parent.isNotEmpty()) { + add("$parent/") + parent = parent.substringBeforeLast('/', "") + } + } + .toTypedArray() val result = runWithSuccess(shadowJarPath, infoArgument) diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt index e85c711e5..619f6eb0c 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt @@ -87,7 +87,7 @@ class TransformersTest : BaseTransformerTest() { assertThat(buildResult.output) .contains( // Keep this list approach for Unix/Windows test compatibility. - "Execution failed for task ':shadowJar'.", + "Execution failed for task ':shadowJar'", "> Found 1 path duplicate(s) with different content in the shadowed JAR:", " * differing-content-2", "differing-content-2 (SHA256: ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73)", diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/FindResourceInClasspath.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/FindResourceInClasspath.kt index ad34c7ac8..96342ffc9 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/FindResourceInClasspath.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/FindResourceInClasspath.kt @@ -15,12 +15,12 @@ import org.gradle.work.DisableCachingByDefault /** * Helper task to temporarily add to your build script to find resources in the classpath that were * identified as duplicates by - * [com.github.jengelman.gradle.plugins.shadow.transformers.MergePropertiesResourceTransformer] or + * [com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer] or * [com.github.jengelman.gradle.plugins.shadow.transformers.DeduplicatingResourceTransformer]. * * First, add the task to your build script: * ```kotlin - * val findResources by tasks.registering(FindResourceInClasspath::class) { + * val findResources = tasks.register("findResources") { * // add configurations to search for resources in dependency jars * classpath.from(configurations.runtimeClasspath) * // the patterns to search for (it is a Gradle PatternFilterable) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt index 3bb828c73..00615f8e9 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt @@ -235,7 +235,8 @@ public abstract class ShadowJar : Jar() { @get:Input @get:Option( option = "add-multi-release-attribute", - description = "Adds the multi-release attribute to the manifest if any dependencies contain it.", + description = + "Adds the multi-release attribute to the manifest if any dependencies contain it.", ) public open val addMultiReleaseAttribute: Property = objectFactory.property(true) diff --git a/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/GradleRunner.kt b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/GradleRunner.kt index 2175a5a3d..c8d469b61 100644 --- a/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/GradleRunner.kt +++ b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/GradleRunner.kt @@ -7,6 +7,7 @@ import kotlin.io.path.Path import kotlin.io.path.absolutePathString import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner +import org.gradle.util.GradleVersion private val testKitDir by lazy { val gradleUserHome = @@ -20,11 +21,19 @@ val testGradleVersion: String by lazy { ?: error("TEST_GRADLE_VERSION system property is not set.") } +// TODO: this could be inlined after bumping the min Gradle requirement to 9.6 or above. +val enableNoImplicitLookupInParentProjects: String + get() = + when { + GradleVersion.version(testGradleVersion) >= GradleVersion.version("9.6.0") -> + "enableFeaturePreview 'NO_IMPLICIT_LOOKUP_IN_PARENT_PROJECTS'" + else -> "" + } + val commonGradleArgs = setOf( "--configuration-cache", "--build-cache", - "--parallel", "--stacktrace", // https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:usage:parallel "-Dorg.gradle.configuration-cache.parallel=true", diff --git a/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/JarPath.kt b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/JarPath.kt index 60302fc1e..b652db8a4 100644 --- a/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/JarPath.kt +++ b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/JarPath.kt @@ -93,19 +93,18 @@ fun Assert.containsOnly(vararg entries: String) = toEntries().containsO * Ensures the JAR contains exactly the specified entries, including duplicates, in any order. Used * alone, without [containsAtLeast] or [containsNone]. */ -fun Assert.containsExactlyInAnyOrder(vararg entries: String) = - transform { actual -> - ZipInputStream(actual.path.inputStream()).use { jarInput -> - val allEntries = mutableListOf() - while (true) { - val entry = jarInput.nextEntry ?: break - allEntries.add(entry.name) - jarInput.closeEntry() - } - allEntries - } +fun Assert.containsExactlyInAnyOrder(vararg entries: String) = transform { actual -> + ZipInputStream(actual.path.inputStream()).use { jarInput -> + val allEntries = mutableListOf() + while (true) { + val entry = jarInput.nextEntry ?: break + allEntries.add(entry.name) + jarInput.closeEntry() } - .containsExactlyInAnyOrder(*entries) + allEntries + } +} + .containsExactlyInAnyOrder(*entries) private fun Assert.toEntries() = transform { actual -> actual.entries().toList().map { it.name }