Repository: GradleUp/shadow (kotlin)

Issue:
Publishing custom ShadowJar
### Describe your use-case which is not covered by existing documentation.

Since there is already documentation on both creating a custom ShadowJar, and publishing JAR created by `shadowJar` task instead of original JAR. I believe it would be beneficial to also include an example / recommended way on how to publish the custom ShadowJar instead.

For example, I got it working with following:
```gradle
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin
import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin

dependencies {
    implementation 'org.slf4j:slf4j-api:2.0.16'
    shadow 'com.typesafe:config:1.4.3'
}

tasks.register("customShadowJar", ShadowJar) {
    group = ShadowBasePlugin.GROUP_NAME
    description = "A custom shadow jar task"

    archiveClassifier = null
    from sourceSets.main.output
    configurations = [project.configurations.findByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME) ?: project.configurations.getByName("runtime")]

    exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "META-INF/versions/**/module-info.class", "module-info.class")

    relocate("org.slf4j", "com.example.slf4j")
}

project.configurations.findByName(ShadowJavaPlugin.SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME).outgoing {
    artifacts.clear()
    artifact(tasks.customShadowJar)
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.shadow

            pom {
                name = "My Library"
                description = "A simple library"
            }
        }
    }
}
```

### Reference any relevant documentation, other materials or issues/pull requests that can be used for inspiration.

### Existing documentation
- [Creating a Custom ShadowJar Task](https://github.com/GradleUp/shadow/blob/9.0.0-beta8/src/docs/custom-tasks/README.md#creating-a-custom-shadowjar-task)
- [Publish the Shadowed JAR instead of the Original JAR](https://github.com/GradleUp/shadow/blob/9.0.0-beta8/src/docs/publishing/README.md#publish-the-shadowed-jar-instead-of-the-original-jar)

### Inspiration
I was trying to see if there is any alternative way to solve the use-case mentioned in https://github.com/GradleUp/shadow/issues/1115 where developer would like to use Shadow plugin only for relocating (shading) some libraries, while leaving others to be declared as runtime dependency.

Ideally, I believe developer would like to use `shadow` configuration but this cause problem due to `Class-Path` entry in `META-INF/MANIFEST.MF`, which works as expected according to https://github.com/GradleUp/shadow/issues/324 if we assume that this is an app to be run (I think this is what Shadow is aiming for?) instead of a library to be consumed by other projects. This cause developer to implement workaround like https://github.com/apache/kafka/pull/15532 that has drawback where created Gradle module metadata is incorrect as discussed [here](https://github.com/apache/kafka/pull/18018#issuecomment-2639311771) due to how Gradle metadata is not changed, but only POM file is manipulated directly. 

Since the `Class-Path` entry is only added in `shadowJar` task from https://github.com/GradleUp/shadow/blob/9.0.0-beta8/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt#L49, if developer created a custom ShadowJar task with identical setup but without the mentioned lines, then they would be able to achieve using `shadow` configuration without  `Class-Path` entry added. Please do correct me whether this is intentional / oversight / bug though because it led to a different result of `META-INF/MANIFEST.MF`.

Assuming, above behavior is intended, then workaround for library developer is to create a custom ShadowJar task and modify the `shadow` Gradle software component to include the JAR file created from custom ShadowJar task instead. If I understand correctly, this can be done by changing the output artifact of `shadowRuntimeElements` consumable configuration https://github.com/GradleUp/shadow/blob/9.0.0-beta8/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt#L93.

Regardless, I am unsure if there is other use case where publishing JAR from custom ShadowJar task, but if there is, the documentation would be nice to have.

### Are you interested in contributing to the documentation?

_No response_

Pull request:
https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:publications
https://docs.gradle.org/current/userguide/publishing_customization.html#sec:publishing_custom_artifacts_to_maven
https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.MavenPublication.html#org.gradle.api.publish.maven.MavenPublication:artifact(java.lang.Object)

Closes #1252.

Patch:
diff --git a/src/docs/publishing/README.md b/src/docs/publishing/README.md
index 15172841d..53b2de5fa 100644
--- a/src/docs/publishing/README.md
+++ b/src/docs/publishing/README.md
@@ -90,3 +90,42 @@ publishing {
   }
 }
 ```
+
+
+## Publish Custom ShadowJar Task Outputs
+
+It is possible to publish a custom `ShadowJar` task's output via the [`MavenPublication.artifact(java.lang.Object)`](https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.MavenPublication.html#org.gradle.api.publish.maven.MavenPublication:artifact(java.lang.Object)) method. 
+
+```groovy
+// Publishing a Shadow JAR with the Maven-Publish Plugin
+plugins {
+  id 'java'
+  id 'maven-publish'
+  id 'com.gradleup.shadow'
+}
+
+def testShadowJar = tasks.register('testShadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
+  group = com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin.GROUP_NAME
+  description = "Create a combined JAR of project and test dependencies"
+  archiveClassifier = "tests"
+  from sourceSets.test.output
+  configurations = [project.configurations.testRuntimeClasspath]
+}
+
+dependencies {
+  testImplementation 'junit:junit:3.8.2'
+}
+
+publishing {
+  publications {
+    shadow(MavenPublication) {
+      artifact(testShadowJar)
+    }
+  }
+  repositories {
+    maven {
+      url = "https://repo.myorg.com"
+    }
+  }
+}
+```


Test patch:
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 a068fc424..12d3c83a7 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
@@ -9,6 +9,7 @@ import assertk.assertions.isEqualTo
 import assertk.assertions.single
 import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin.Companion.SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME
 import com.github.jengelman.gradle.plugins.shadow.internal.classPathAttributeKey
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
 import com.github.jengelman.gradle.plugins.shadow.util.GradleModuleMetadata
 import com.github.jengelman.gradle.plugins.shadow.util.Issue
 import com.github.jengelman.gradle.plugins.shadow.util.JarPath
@@ -140,6 +141,37 @@ class PublishingTest : BasePluginTest() {
     assertShadowVariantCommon(gmmAdapter.fromJson(repoPath("my/maven/1.0/maven-1.0.module")))
   }
 
+  @Test
+  fun publishCustomShadowJar() {
+    projectScriptPath.appendText(
+      publishConfiguration(
+        projectBlock = """
+          def testShadowJar = tasks.register('testShadowJar', ${ShadowJar::class.java.name}) {
+            group = com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin.GROUP_NAME
+            description = "Create a combined JAR of project and test dependencies"
+            archiveClassifier = "tests"
+            from sourceSets.test.output
+            configurations = [project.configurations.testRuntimeClasspath]
+          }
+        """.trimIndent(),
+        dependenciesBlock = """
+          testImplementation 'junit:junit:3.8.2'
+        """.trimIndent(),
+        publicationsBlock = """
+          shadow(MavenPublication) {
+            artifact testShadowJar
+          }
+        """.trimIndent(),
+      ),
+    )
+
+    publish()
+
+    assertThat(repoJarPath("my/maven/1.0/maven-1.0-tests.jar")).useAll {
+      containsEntries(*junitEntries)
+    }
+  }
+
   @ParameterizedTest
   @ValueSource(booleans = [false, true])
   fun publishShadowedGradlePlugin(legacy: Boolean) {