Repository: GradleUp/shadow (kotlin)

Issue:
About shadow with MavenPublication, how to specify a output filename, or postfix is not clear
Hello, thank you for your work. 

https://imperceptiblethoughts.com/shadow/publishing/#publishing-with-maven-publish-plugin
I am trying to publish a maven dependency in a form of shadowJar. Referring the document, I coded like below specifying groupId, artifactId, version. But in a main project that uses the dependency, I guess the project cannot inject the dependency because there is only  <artifactId>-0.1.0-SNAPSHOT-shadow.jar, not with <artifactId>-0.1.0-SNAPSHOT.jar. 

How to specify output in detail? 

### Shadow Version
Latest

### Gradle Version
Gradle 6.4.1

### Expected Behavior
```
> ~/.m2/repository/<groupId>/<artifactId>/0.1.0-SNAPSHOT
> ls
maven-metadata-local.xml                                 
<artifactId>-0.1.0-SNAPSHOT.pom
<artifactId>-0.1.0-SNAPSHOT-shadow.jar       
<artifactId>-0.1.0-SNAPSHOT.jar
```

### Actual Behavior
```
> ~/.m2/repository/<groupId>/<artifactId>/0.1.0-SNAPSHOT
> ls
maven-metadata-local.xml                                 
<artifactId>-0.1.0-SNAPSHOT.pom
<artifactId>-0.1.0-SNAPSHOT-shadow.jar
```

### Gradle Build Script(s)
```
publishing {
    publications {
        shadow(MavenPublication) { publication ->
            from project.shadow.component(publication)
            groupId = '<groupId>'
            artifactId = '<artifactid>'
            version = '0.1.0-SNAPSHOT'
        }
    }
}

>  ./gradlew :protocol:publishToMavenLocal
```

### Content of Shadow JAR (`jar tf <jar file>` - post link to GIST if too long)

Pull request description:
Closes #614.

Patch:
diff --git a/docs/configuration/README.md b/docs/configuration/README.md
index f4322bc59..21fa1b080 100644
--- a/docs/configuration/README.md
+++ b/docs/configuration/README.md
@@ -13,21 +13,35 @@ details.
 
 ## Configuring Output Name
 
-Shadow configures the default `shadowJar` task to set the output JAR's `destinationDirectory`, `archiveBaseName`, `appendix`,
-`archiveVersion`, and `extension` to the same default values as Gradle does for all `Jar` tasks.
-Additionally, it configures the `archiveClassifier` to be `all`.
+Shadow configures the default `shadowJar` task to set the output JAR's
+
+- [`archiveAppendix`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveAppendix)
+- [`archiveBaseName`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveBaseName)
+- [`archiveExtension`](https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:archiveExtension)
+- [`archiveFile`](https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:archiveFile)
+- [`archiveFileName`](https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:archiveFileName)
+- [`archiveVersion`](https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:archiveVersion)
+- [`destinationDirectory`](https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:destinationDirectory)
+
+to the same default values as Gradle does for all `Jar` tasks.
+Additionally, it configures the
+[`archiveClassifier`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveClassifier)
+to be `all`. The listed ones are not full, you can view all the properties in 
+[`Jar`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html).
+The output shadowed JAR file will be named with the following format:
 
-If working with a Gradle project with the name `myApp` and archiveVersion `1.0`, the default `shadowJar` task will output a
-file at: `build/libs/myApp-1.0-all.jar`
+```
+archiveBaseName-$archiveAppendix-$archiveVersion-$archiveClassifier.$archiveExtension
+```
 
-As with all `Jar` tasks in Gradle, these values can be overridden:
+If working with a Gradle project with the name `myApp` and version `1.0`, the default `shadowJar` task will output a
+file at: `build/libs/myApp-1.0-all.jar`. You can override the properties listed above to change the output name of the 
+shadowed JAR file. e.g.
 
 === "Kotlin"
 
     ```kotlin
     tasks.shadowJar {
-      archiveBaseName = "shadow"
-      archiveClassifier = ""
       archiveVersion = ""
     }
     ```
@@ -36,12 +50,13 @@ As with all `Jar` tasks in Gradle, these values can be overridden:
 
     ```groovy
     tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
-      archiveBaseName = 'shadow'
-      archiveClassifier = ''
       archiveVersion = ''
     }
     ```
 
+This will result in the output file being named `myApp-all.jar` instead of `myApp-1.0-all.jar`.
+
+
 ## Configuring the Runtime Classpath
 
 Each Java JAR file contains a manifest file that provides metadata about the contents of the JAR file itself.
diff --git a/docs/configuration/merging/README.md b/docs/configuration/merging/README.md
index 5f5360f82..d5c821944 100644
--- a/docs/configuration/merging/README.md
+++ b/docs/configuration/merging/README.md
@@ -368,7 +368,7 @@ which means it honors the `duplicatesStrategy` property as its parent classes do
 - `INHERIT`: Uses the same strategy as the parent copy specification.
 - `WARN`: Do not attempt to prevent duplicates, but log a warning message when multiple items are to be created at the same path.
 
-You can see more details about them in 
+see more details about them in 
 [`DuplicatesStrategy`](https://docs.gradle.org/current/javadoc/org/gradle/api/file/DuplicatesStrategy.html).
 
 `ShadowJar` recognizes `DuplicatesStrategy.INCLUDE` as the default, if you want to change the strategy, you can 
diff --git a/docs/publishing/README.md b/docs/publishing/README.md
index e888b53f4..534c8b229 100644
--- a/docs/publishing/README.md
+++ b/docs/publishing/README.md
@@ -218,3 +218,76 @@ It is possible to publish a custom `ShadowJar` task's output via the [`MavenPubl
       }
     }
     ```
+
+
+## Publish the Shadowed JAR with Custom Artifact Name
+
+It is possible to configure the artifact name of the shadowed JAR via properties like `archiveBaseName`, see more 
+customizable properties listed in [Configuring Output Name](../configuration/README.md#configuring-output-name). e.g.
+
+=== "Kotlin"
+
+    ```kotlin
+    plugins {
+      java
+      `maven-publish`
+      id("com.gradleup.shadow")
+    }
+
+    group = "my-group"
+    version = "1.0"
+
+    tasks.shadowJar {
+      archiveClassifier = "my-classifier"
+      archiveExtension = "my-ext"
+      archiveBaseName = "maven-all"
+    }
+
+    publishing {
+      publications {
+        create<MavenPublication>("shadow") {
+          from(components["shadow"])
+          // This will override `archiveBaseName`.
+          artifactId = "my-artifact"
+        }
+      }
+      repositories {
+        maven("https://repo.myorg.com")
+      }
+    }
+    ```
+
+=== "Groovy"
+
+    ```groovy
+    plugins {
+      id 'java'
+      id 'maven-publish'
+      id 'com.gradleup.shadow'
+    }
+
+    group = 'my-group'
+    version = '1.0'
+
+    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
+      archiveClassifier = 'my-classifier'
+      archiveExtension = 'my-ext'
+      archiveBaseName = 'maven-all'
+    }
+
+    publishing {
+      publications {
+        shadow(MavenPublication) {
+          from components.shadow
+          // This will override `archiveBaseName`.
+          artifactId = 'my-artifact'
+        }
+      }
+      repositories {
+        maven { url = 'https://repo.myorg.com' }
+      }
+    }
+    ```
+
+We modified `archiveClassifier`, `archiveExtension` and `archiveBaseName` in this example, the published artifact will 
+be named `my-artifact-2.0-my-classifier.my-ext` instead of `1.0-all.jar`.


Test patch:
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
index e42ed45ab..0d9960b3f 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginTest.kt
@@ -34,6 +34,7 @@ import kotlin.io.path.name
 import kotlin.io.path.outputStream
 import kotlin.io.path.writeText
 import org.gradle.api.plugins.JavaPlugin
+import org.gradle.api.tasks.bundling.Jar
 import org.gradle.testfixtures.ProjectBuilder
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.condition.DisabledForJreRange
@@ -60,20 +61,24 @@ class JavaPluginTest : BasePluginTest() {
     val shadowTask = project.tasks.getByName(SHADOW_JAR_TASK_NAME) as ShadowJar
     val shadowConfig = project.configurations.getByName(ShadowBasePlugin.CONFIGURATION_NAME)
 
-    with(shadowTask) {
+    // Check extended properties.
+    with(shadowTask as Jar) {
+      assertThat(archiveAppendix.orNull).isNull()
       assertThat(archiveBaseName.get()).isEqualTo(projectName)
-      assertThat(destinationDirectory.get().asFile)
-        .isEqualTo(project.layout.buildDirectory.dir("libs").get().asFile)
-      assertThat(archiveVersion.get()).isEqualTo(version)
       assertThat(archiveClassifier.get()).isEqualTo("all")
       assertThat(archiveExtension.get()).isEqualTo("jar")
       assertThat(archiveFileName.get()).isEqualTo("my-shadow-1.0.0-all.jar")
+      assertThat(archiveVersion.get()).isEqualTo(version)
       assertThat(archiveFile.get().asFile).all {
         isEqualTo(destinationDirectory.file(archiveFileName).get().asFile)
         isEqualTo(project.projectDir.resolve("build/libs/my-shadow-1.0.0-all.jar"))
       }
-      assertThat(archiveAppendix.orNull).isNull()
+      assertThat(destinationDirectory.get().asFile)
+        .isEqualTo(project.layout.buildDirectory.dir("libs").get().asFile)
+    }
 
+    // Check self properties.
+    with(shadowTask) {
       assertThat(minimizeJar.get()).isFalse()
       assertThat(enableRelocation.get()).isFalse()
       assertThat(relocationPrefix.get()).isEqualTo(ShadowBasePlugin.SHADOW)
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 2c907d66b..fdcf0f0ee 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
@@ -214,26 +214,55 @@ class PublishingTest : BasePluginTest() {
   }
 
   @Issue(
+    "https://github.com/GradleUp/shadow/issues/614",
     "https://github.com/GradleUp/shadow/issues/860",
     "https://github.com/GradleUp/shadow/issues/945",
   )
   @Test
-  fun publishShadowJarWithCustomClassifierAndExtension() {
+  fun publishShadowJarWithCustomArtifactName() {
     projectScriptPath.appendText(
       publishConfiguration(
+        projectBlock = """
+          group = 'my-group'
+          version = '2.0'
+        """.trimIndent(),
         shadowBlock = """
           archiveClassifier = 'my-classifier'
           archiveExtension = 'my-ext'
           archiveBaseName = 'maven-all'
         """.trimIndent(),
+        publicationsBlock = """
+        shadow(MavenPublication) {
+          from components.shadow
+          artifactId = 'my-artifact'
+        }
+        """.trimIndent(),
       ),
     )
 
     publish()
 
-    assertShadowJarCommon(repoJarPath("my/maven-all/1.0/maven-all-1.0-my-classifier.my-ext"))
-    assertPomCommon(repoPath("my/maven-all/1.0/maven-all-1.0.pom"))
-    assertShadowVariantCommon(gmmAdapter.fromJson(repoPath("my/maven-all/1.0/maven-all-1.0.module")))
+    assertThat(repoPath("my-group/my-artifact/2.0/").listDirectoryEntries().map { it.name }).containsOnly(
+      "my-artifact-2.0-my-classifier.my-ext.sha512",
+      "my-artifact-2.0-my-classifier.my-ext",
+      "my-artifact-2.0.pom.sha256",
+      "my-artifact-2.0.module",
+      "my-artifact-2.0.pom",
+      "my-artifact-2.0.module.sha256",
+      "my-artifact-2.0.module.sha1",
+      "my-artifact-2.0.module.md5",
+      "my-artifact-2.0.pom.sha512",
+      "my-artifact-2.0-my-classifier.my-ext.sha256",
+      "my-artifact-2.0.module.sha512",
+      "my-artifact-2.0-my-classifier.my-ext.sha1",
+      "my-artifact-2.0-my-classifier.my-ext.md5",
+      "my-artifact-2.0.pom.md5",
+      "my-artifact-2.0.pom.sha1",
+    )
+
+    assertShadowJarCommon(repoJarPath("my-group/my-artifact/2.0/my-artifact-2.0-my-classifier.my-ext"))
+    assertPomCommon(repoPath("my-group/my-artifact/2.0/my-artifact-2.0.pom"))
+    assertShadowVariantCommon(gmmAdapter.fromJson(repoPath("my-group/my-artifact/2.0/my-artifact-2.0.module")))
   }
 
   @Test