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

Can't figure out how to make signing work #413

Closed eli-darkly closed 6 years ago

eli-darkly commented 6 years ago

Shadow Version

2.0.1

Gradle Version

4.2.1

Expected Behavior

Jars will be signed as I specified in build.gradle

Actual Behavior

Jars were being signed, but after I made a change in the publishing configuration involving Shadow, I stopped getting signatures (see below).

Gradle Build Script(s)

apply plugin: 'java'
apply plugin: 'maven-publish'
apply plugin: 'org.ajoberstar.github-pages'
apply plugin: 'signing'
apply plugin: 'idea'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'io.codearte.nexus-staging'

configurations.all {
    // check for updates every build for dependencies with: 'changing: true'
    resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}

repositories {
    mavenLocal()
    maven { url "https://oss.sonatype.org/content/groups/public/" }
    mavenCentral()
}

allprojects {
    group = 'com.launchdarkly'
    version = "${version}"
    sourceCompatibility = 1.7
    targetCompatibility = 1.7
}

ext.libraries = [:]

libraries.internal = [
    "commons-codec:commons-codec:1.10",
    "com.google.guava:guava:19.0",
    "joda-time:joda-time:2.9.3",
    "com.launchdarkly:okhttp-eventsource:1.7.1",
    "redis.clients:jedis:2.9.0"
]

libraries.external = [
    "com.google.code.gson:gson:2.7",
    "org.slf4j:slf4j-api:1.7.21"
]

libraries.test = [
    "com.squareup.okhttp3:mockwebserver:3.10.0",
    "org.hamcrest:hamcrest-all:1.3",
    "org.easymock:easymock:3.4",
    "junit:junit:4.12",
    "ch.qos.logback:logback-classic:1.1.7"
]

dependencies {
    implementation libraries.internal
    compileClasspath libraries.external
    runtime libraries.internal, libraries.external
    testImplementation libraries.test, libraries.internal, libraries.external
    shadow libraries.external
}

jar {
    baseName = 'launchdarkly-client'
    // thin classifier means that the non-shaded non-fat jar is still available
    // but is opt-in since users will have to specify it.
    classifier = 'thin'
    manifest {
        attributes("Implementation-Version": version)
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '4.2.1'
}

buildscript {
    repositories {
        jcenter()
        mavenCentral()
        mavenLocal()
    }
    dependencies {
        classpath 'org.ajoberstar:gradle-git:1.5.0-rc.1'
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
        classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.8.0"
    }
}

// custom tasks for creating source/javadoc jars
task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.allSource
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

githubPages {
    repoUri = 'https://github.com/launchdarkly/java-client.git'
    pages {
        from javadoc
    }
    credentials {
        username = githubUser
        password = githubPassword
    }
}

shadowJar {
    baseName = 'launchdarkly-client'
    //no classifier means that the shaded jar becomes the default artifact
    classifier = ''

    // Don't shade or include slf4j
    dependencies{
        exclude(dependency('org.slf4j:.*:.*'))
        exclude(dependency('com.google.code.gson:.*:.*'))
    }

    // Shade all jars except for launchdarkly
    relocate('com', 'com.launchdarkly.shaded.com') {
        exclude("com.launchdarkly.client.*")
        exclude("com.google.gson.*")
        exclude("com.google.gson.annotations.*")
        exclude("com.google.gson.internal.*")
        exclude("com.google.gson.internal.bind.*")
        exclude("com.google.gson.internal.bind.util.*")
        exclude("com.google.gson.reflect.*")
        exclude("com.google.gson.stream.*")
    }
    relocate('okhttp3', 'com.launchdarkly.shaded.okhttp3')
    relocate('okio', 'com.launchdarkly.shaded.okio')
    relocate('org', 'com.launchdarkly.shaded.org') {
        exclude("org.slf4j.*")
        exclude("org.slf4j.event.*")
        exclude("org.slf4j.helpers.*")
        exclude("org.slf4j.spi.*")
    }
    relocate('redis', 'com.launchdarkly.shaded.redis')

    manifest {
        attributes("Implementation-Version": version)
    }
}

artifacts {
    archives jar, sourcesJar, javadocJar, shadowJar
}

test {
    testLogging {
        events "passed", "skipped", "failed", "standardOut", "standardError"
        showStandardStreams = true
        exceptionFormat = 'full'
    }
}

signing {
    sign configurations.archives
}

idea {
    module {
        downloadJavadoc = true

        downloadSources = true
    }
}

nexusStaging {
    packageGroup = "com.launchdarkly"
}

publishing {
    publications {
        shadow(MavenPublication) { publication ->
            project.shadow.component(publication)

            artifactId = 'launchdarkly-client'
            artifact jar
            artifact sourcesJar
            artifact javadocJar
            artifact shadowJar
        }
    }
    repositories {
        mavenLocal()
        maven {
            def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
            def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                username ossrhUsername
                password ossrhPassword
            }
        }
    }
}

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

n/a (the jar's contents are correct, that's not the problem)

This may not really be a Shadow issue per se, but I'm unclear on how to make things work as they should given the way we're using Shadow.

The issue is this. Our configuration used to be mostly the same as the above except that we were publishing via the maven plugin, rather than maven-publish. We changed because we were having a problem with the POM for the shaded jar - it was showing dependencies that should be hidden - and that problem went away once we started using maven-publish. The Shadow documentation made it pretty clear what config changes we had to make for this.

However, after changing to maven-publish, we stopped getting signatures. I think this has something to do with the task and publication objects behaving differently. For instance, without Shadow, we would be able to specify sign publishing.publications.mavenJava causing all artifacts for the publication to be signed. But sign publishing.publications.shadow does not work— I can't figure out what the name of the publication object is supposed to be. So I tried referencing the artifacts collectively as archives but that doesn't seem to do anything, even though the signature task is definitely running.

Basically I'm just wondering if you have any example of a build file that uses both Shadow and signing. I'm sure that ours has some weird qualities that are unrelated to Shadow, since we're not Gradle experts, so it may not be worthwhile to go through it in detail, but if I see something that's known to work I can try to adapt to that.

johnrengelman commented 6 years ago

Do you get an error?

You can run Gradle with the “-i” or “-d” flags to get more information on what it is doing.

eli-darkly commented 6 years ago

I don't get an error with the script shown above; it just doesn't publish any of the signature files.

When I try changing the signing task to say sign publishing.publications.shadow (which the docs for signing seemed to suggest ought to work), I get an error: Could not get unknown property 'shadow' for Publication container of type org.gradle.api.publish.internal.DefaultPublicationContainer.

I did try running Gradle with -i and -d but unfortunately didn't get any useful information, except that it was at least executing the signing task. However, I'm now even more puzzled because, while I know for sure that I saw it executing that task yesterday and was seeing signature files generated locally (but not published), this is no longer the case - I haven't changed anything but now I get no signature files.

Again, I have no idea whether this is actually related to Shadow but I would love to know if there is any example of a project successfully using Shadow + maven-publish + signing.

eli-darkly commented 6 years ago

The other thing I tried was to specify all the artifacts individually:

signing {
    sign jar
    sign sourcesJar
    sign javadocJar
    sign shadowJar
}

Doesn't help, though.

eli-darkly commented 6 years ago

Sorry, please ignore the part that says "this is no longer the case - I haven't changed anything but now I get no signature files." I had just forgotten that I need to explicitly tell Gradle to run the signArchives task before publishing (I didn't need to do that when I was using the maven plugin, but apparently I do now). So, yes, I still do get signature files generated locally, but they are still not published.

eli-darkly commented 6 years ago

Well, my confusion about why sign publishing.publications.shadow didn't work has been partly answered. I had put signing above publications and it doesn't like forward references. When I switch the order, it no longer complains that it can't find "shadow", but it fails with a different error:

Could not find method sign() for arguments [org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication_Decorated@44a50910] on object of type org.gradle.plugins.signing.SigningExtension.

However, this error happens even if I completely remove Shadow from my build, so it seems more like the signing plugin not playing nicely with the maven-publish plugin for some reason.

eli-darkly commented 6 years ago

AHA! I see what's going on and it does not have anything to do with Shadow. It's just that the ability to sign a maven-publish publication in the way that the signing plugin docs tell you to do was not actually implemented in Gradle until a few months ago, and I was using an older version. Sorry for the red herring.

cekvenich commented 4 years ago

@eli-darkly Do you have a link to github of the latest build.gradle example you posted above? I'm trying to come up w/ with just a simple hello world fat jar publish. TIA

eli-darkly commented 4 years ago

@cekvenich My build file won't be useful for a simple example - it's not simple at all, since we're building multiple distributions, adding an OSGi manifest, and various other things. But if you're curious it's here.