GradleUp / shadow

Gradle plugin to create fat/uber JARs, apply file transforms, and relocate packages for applications and libraries. Gradle version of Maven's Shade plugin.
https://www.gradleup.com/shadow/
Apache License 2.0
3.76k stars 395 forks source link

uploadX task fails if both shadow 2.0.x and application plugin are applied. #347

Closed huxi closed 5 years ago

huxi commented 6 years ago

Shadow Version

1.2.4 vs. 2.0.0/2.0.1

Gradle Version

4.3.1/4.4-rc1

Expected Behavior

This example project (build.gradle is also provided below) should work with 2.0.x since it worked with 1.2.4. Execute gradlew to run the default tasks.

Actual Behavior

Execution failed for task ':uploadPublished'.
> Could not publish configuration 'published'
   > A POM cannot have multiple artifacts with the same type and classifier. Already have MavenArtifact gradle-shadow2:zip:zip:null, trying to add MavenArtifact gradle-shadow2:zip:zip:null.

If you remove the following two lines, the build will work.

apply plugin: 'application'
mainClassName = 'foo.Main'

If you instead switch back from 2.0.1 to 1.2.4, the build will work. If you use Gradle 4.4-rc1, neither will work. See https://github.com/gradle/gradle/issues/3589

Gradle Build Script(s)

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        //classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4'
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
    }
}

wrapper {
    gradleVersion = '4.3.1'
    // gradleVersion = '4.4-rc1'
}

description = 'some description'
version = '1.0.0-SNAPSHOT'

def localReleaseRepoFile = new File("${System.properties.'user.home'}/local-gradle-repository/release")
def localSnapshotRepoFile = new File("${System.properties.'user.home'}/local-gradle-repository/snapshot")
def localReleaseRepo = localReleaseRepoFile.toURL().toString()
def localSnapshotRepo = localSnapshotRepoFile.toURL().toString()
repositories {
    maven {
        url localReleaseRepo
    }
    maven {
        url localSnapshotRepo
    }
    mavenCentral()
    mavenLocal()
}

apply plugin: 'application'
mainClassName = 'foo.Main'

apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'com.github.johnrengelman.shadow'

def deployer = null

configurations {
    published.extendsFrom archives
}

uploadPublished {
    deployer = repositories.mavenDeployer {
        repository(url: localReleaseRepo)
        snapshotRepository(url: localSnapshotRepo)
    }
}

def defaultProject= {
    url 'http://foobar.com'
    name project.name
    description project.description
}

def installer = install.repositories.mavenInstaller

installer.pom.project defaultProject

deployer.pom.project defaultProject

defaultTasks 'build', 'shadowJar', 'uploadPublished'

Content of Shadow JAR (jar tf <jar file> - post link to GIST if too long)

n/a, content of the JAR is not the problem.

fpoyer commented 6 years ago

Reproduced here with Maven plugin's uploadArchives task, shadow 2.0.2 and Gradle 4.4.1 If anyone can give me indications where to start looking, I'll be happy to help, as this bug forces me to keep using shadow 1.2.4 until fixed... :'(

johnrengelman commented 6 years ago

I think the maven plugin is adding the outputs of distTar and distZip to the upload

fpoyer commented 6 years ago

Can't you reverse the logic of the plugin (shadow) then? And make the result of distTar and distZip the shadow ones (kind of overriding or overloading if you want), and add targets originalDistTar and originalDistZip that produce (but do not upload/add to upload targets) the original contents, in case anyone need them? Just brainstorming here, there might be obvious reasons not to that I'm missing...

ljohnston commented 6 years ago

Running into the same issue. Any workaround here?

fpoyer commented 6 years ago

We reverted to 1.2.4 for the time being, but be warned that this produces a warning with gradle 4.X about a private/internal constructor being kept for this plugin compatibility only and planned to be removed with Gradle 5.

filip-owczarzak commented 6 years ago

Hi @johnrengelman! Are you working on the issue or planning to do so in the nearest future?

huxi commented 6 years ago

Any news about this? I have to stay on 1.2.4 because of it but that version of the plugin won't work anymore with Gradle 5.0, i.e. the next Gradle version.

Warning produced by Gradle 4.10 with --warning-mode all:

A constructor for `org.gradle.api.internal.java.JavaLibrary` is used by Shadow plugin v1.2.x, and has been preserved for compatibility This has been deprecated and is scheduled to be removed in Gradle 5.0. If you're using the Shadow plugin, try upgrading to v2.x
huxi commented 6 years ago

Just for the record: behavior is still the same with com.github.jengelman.gradle.plugins:shadow:4.0.0.

johnrengelman commented 6 years ago

@huxi what is the actual intended outcome here. What should be uploaded by the uploadPublished task? I see you creating the configuration and you're extending from archives.

huxi commented 6 years ago

@johnrengelman Primarily, it should behave like 1.2.4 instead of failing.

This is completely unrelated to anything that actually happens while shadowing (the above example doesn't even have dependencies or any class file at all). Something must have changed between 1.2.4 and 2.0.0 that causes uploadPublished to fail with the above A POM cannot have multiple artifacts message. You just need to toggle the versions in the above example build.gradle file to the expected and actual behavior in action.

There seems to be some collision between the application plugin and the shadow plugin > 1.2.4.

johnrengelman commented 6 years ago

yeah, but I need to write a test and verify what's happening. A LOT changed between those version, thus the major version change.

johnrengelman commented 6 years ago

Ok, I believe I see what's happening. According to https://docs.gradle.org/current/userguide/distribution_plugin.html#sec:publishing_distributions_upload ALL distributions are automatically added to the default archive configuration. This means that the outputs from shadowDistZip and shadowDistTar are automatically added to archives and since we don't do any special configuration of those tasks, they have the default classifier which is null.

You can work around this in your build by adding the following:

shadowDistZip.classifier = 'shadow'
shadowDistTar.classifier = 'shadow'
huxi commented 6 years ago

Hm... I'd expect that shadow plugin shouldn't have any influence at all on the published artifacts, at least by default. With 1.2.4 the shadowplugin created an additional jar with -all classifier and didn't add that to the published archives automatically. So the "upload" to the "${System.properties.'user.home'}/local-gradle-repository/snapshot" didn't include the shadowed jar.

I'm not sure about the intended behavior of 2.0.0 since it never worked for me.

Your latest reply just popped up. Are shadowDistZip/Tar new in shadow 2.0.0? Can I somehow disable them altogether because distZip/Tar of the application plugin are already doing exactly what I would expect, i.e. unshadowed distributions, and shadowed ones would be somewhat superfluous...

I'll give your workaround a shot (thanks!) but I think a better default handling of the application/shadow combination would be quite helpful.

johnrengelman commented 6 years ago

I'll add default handling, but yeah, this isn't something I can control directly. It's the behavior of the DistributionPlugin inside of Gradle itself. I'm just adding a new distribution, but I'll add the default classifier in a patch release.

huxi commented 6 years ago

Thanks a lot for your effort. Your suggested workaround works. Just tried it. 👍

davidghiurco commented 4 years ago

@johnrengelman I'm currently facing an issue on Gradle 6.1.1 / Shadow 5.2.0 (and earlier version all the way to 4.0.4) where the shadowJar plugin refuses to wait for dependency resolution until a dependent task

(which, for context here, runs maven within gradle (using gradle-maven-exec-plugin) in order to resolve certain company-specific internal dependencies which CANNOT be resolved by gradle, as they require a special maven build extension. These dependencies are then read from mavenLocal() by gradle) I've made this maven-running task the very first task in the task dependency list by compileJava.dependsOn mavenRunningTask. However, applying the shadowJar plugin to my build for some reason refuses to wait for this task to be executed.

This results in the following when trying to gradle jar / gradle assemble / gradle build (even tasks which EXCLUDE shadowJar completely)

Could not determine the dependencies of task ':shadowJar'.

Could not resolve all dependencies for configuration ':runtimeClasspath'.

I use the maven-publish plugin to create maven releases for this project. While trying to find out why the shadowJar task has the above behavior, I ran into the following on your shadow github release page:

https://github.com/johnrengelman/shadow/releases/tag/4.0.4 which states

"When using shadow, application, and maven plugins together, remove shadowDistZip and shadowDistTar from configurations.archives so they are not published or installed by default with the uploadArchives or install"

I commented out the maven-publish plugin, and instead applied the (now deprecated https://docs.gradle.org/current/userguide/maven_plugin.html) maven plugin, and sure enough, build magically started working. The reason as to why that is boggles my mind.

Right now the work-around to my problem is to apply the maven-publish plugin and configure my maven release that way, and also apply the deprecated maven plugin, which is the deprecated version of maven-publish, and could possibly cause conflicts when publishing.

TL;DR, could you please apply whatever fix you made in conjunction with the maven plugin, also to the maven-publish plugin?

Let me know if you want a separate issue for this. I felt this was the most appropriate place to ask.