3

I am trying to publish a Java library to maven central repository. I have never done this before. This project is for testing purposes. When I figure out how to properly publish a project, I will then publish an actual library. My goal is to be able to add this project as a dependency for other projects. I know I could include it as a .jar, but I want to learn about other ways of importing dependencies.

While running the task:

./gradlew publish

in my project root folder, I get the build error:

> Task :signMavenJavaPublication FAILED
Caching disabled for task ':signMavenJavaPublication' because:
  Build cache is disabled
Task ':signMavenJavaPublication' is not up-to-date because:
  Task has failed previously.
:signMavenJavaPublication (Thread[Execution worker for ':',5,main]) completed. Took 0.004 secs.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':signMavenJavaPublication'.
> Cannot perform signing task ':signMavenJavaPublication' because it has no configured signatory

EDIT: I have made some progress. I will post this at the bottom of the question.

For the past four days, I have been trying to figure out why. I will post the build code further below, but first I will go through all the steps I followed to be able to publish to the central repository in the first place.

My gradle experience is limited, but I think I know the basics.

I have read various documentation on:

central.sonatype.org

Gradle

for how to publish / sign. I don't know exactly what i am doing or why.

  1. Apply for a GroupID on Sonatype Jira. This issue/ticket is resolved. And I should be able to publish SNAPSHOT and release artifacts to s01.oss.sonatype.org. My GroupID is my github domain. So, as far as I know, this lets me publish my projects / libraries under "io.github.username".

  2. Download and set up GnuPG:

At some point in the set up I was asked to create a GnuPG password (signing.password). Don't remember when.

gpg --gen-key

Entering my name and email. Now I can type:

gpg -K

And I get the following (not actual values):

sec   ed25519 2022-05-25 [SC] [expires: 2024-05-24]
      ****************************************
uid           [ultimate] My Name <my-email@mail.com>
ssb   cv25519 2022-05-25 [E] [expires: 2024-05-24]

So, the **************************************** is the password I am using. (the final 8 digits). Now I export the key.(I think it creates my secret key right?):

gpg --export-secret-keys ******** > C:\users\username\secring.gpg

As far as I know, this could be any folder. As long as the folder corresponds to the:

signing.secretKeyRingFile=\users\username\secring.gpg

in the gradle.properties file. Also, what would be the correct way to type this?

signing.secretKeyRingFile=\users\username\secring.gpg
signing.secretKeyRingFile=C:\users\username\secring.gpg
signing.secretKeyRingFile=C:\\users\\username\\secring.gpg
signing.secretKeyRingFile="C:\\users\\username\\secring.gpg"

(I think I have tried all the variations)

Then I need to send the public key to some key server. And there are some alternatives:

  • keyserver.ubuntu.com
  • keys.openpgp.org
  • pgp.mit.edu

I have tried to send it to all of them.

gpg --keyserver hkp://keyserver.ubuntu.com --send-keys ****************************************

And to can check if the server received the key:

gpg --keyserver hkp://keyserver.ubuntu.com --search-key 'my-email@mail.com'

And they got it. At least the server responds with the last 16 or so digits of the key.

  1. So at this point I set up a simple java test project named "Storage". Pushing it to my github repo. under the same name.

Structure

  1. And now we can get to the gradle files. Keep in mind, I'm not entirely sure if this is correct. If I left out something, or something is unnecessary. Please let me know.

build.gradle

plugins {
    id 'java-library'
    id 'signing'
    id 'maven-publish'
}

group 'io.github.username'
version '0.0.1'

repositories {
    mavenCentral()
    maven { url "http://repo.maven.apache.org/maven2" }
    maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}

dependencies {}

java {
    withJavadocJar()
    withSourcesJar()
}


publishing {
    publications {
        mavenJava(MavenPublication) {

            groupId = 'io.github.username'
            artifactId = 'storage'
            version = '0.0.1'
            from components.java

            pom {
                name = 'Storage'
                description = 'Storage is an open-source Java library test'
                url = 'https://github.com/username/Storage'
                inceptionYear = '2022'

                licenses {
                    license {
                        name = 'MIT License'
                        url = 'http://www.opensource.org/licenses/mit-license.php'
                    }
                }
                developers {
                    developer {
                        id = 'sonatype-username'
                        name = 'Full Name'
                        email = 'my-email@mail.com'
                    }
                }
                scm {
                    connection = 'scm:git:git://github.com/username/Storage.git'
                    developerConnection = 'scm:git:ssh://github.com/username/Storage.git'
                    url = 'https://github.com/username/Storage'
                }
            }
        }
    }
    repositories {
        maven {
            name = "OSSRH"
            url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
            credentials {
                username = project.properties["ossrhUsername"]
                password = project.properties["ossrhPassword"]
            }
        }
    }
}

signing {
    sign publishing.publications.mavenJava
}

javadoc {
    if(JavaVersion.current().isJava9Compatible()) {
        options.addBooleanOption('html5', true)
    }
}

gradle-wrapper.properties

# auto-generated
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

# Sonatype variables
ossrhUsername=username
ossrhPassword=password

# GnuPG
signing.keyId=********
singing.password=GnpPassword
signing.secretKeyRingFile=\Users\username\secring.gpg

settings.gradle

rootProject.name = 'Storage'

That should be it. But I can include versions of various software/tools:

  • OS Windows 10
  • GnuPG 2.3.6
  • Gradle 7.4.2
  • Java 13.0.1
  • Groovy 3.0.9

PROGRESS:

I got the project published to Nexus repository manager. So I know for a fact that build.gradle can access my gradle.properties file and can read it's content.

I got the publish task to work by excluding the signing part.

I have sent my key (two keys now) to both:

  • keyserver.ubuntu.com
  • pgp.mit.edu

keys.openpgp.org does not seem to work. I get gpg: keyserver send failed: Certificate expired

When i send a key to a server I use the FULL KEY ID.

I can query a server to see if they in fact received the keys: gpg --keyserver hkp://keyserver.ubuntu.com --search-key 'my-email@mail.com'

And both servers have received 2 keys:

(1)     My Name <my-email@mail.com>
          263 bit EDDSA key ****************, created: 2022-05-28
(2)     My Name <my-email@mail.com>
          263 bit EDDSA key ****************, created: 2022-05-25
Keys 1-2 of 2 for "my-email@mail.com".  Enter number(s), N)ext, or Q)uit >

The **************** is in fact the last numerals of my keys. It has to be right. Should I only send the last 8 numerals of the key to a server?

And the singing.password I use is the same choose when creating a key.

But for some esoteric reason. The signing still does not work. Is there no way to pinpoint the EXACT reason for failure?

Please, take a look at my build.gradle. Is there an alternative way to publishing / signing i could try instead?

Does the name of the secret key file matter? secring.gpg

Dahl
  • 149
  • 1
  • 10

2 Answers2

1

The error piece:


> Cannot perform signing task ':signMavenJavaPublication' because it has no configured signatory

basically says that your signing task is not able to figure out the signature info it needs to execute. Most likely it cannot find your gradle-wrapper.properties file. What you can do is to try to put them in the main gradle.properties file and see how it goes.

As for the folders: Gradle relies on java.io.File for its path related operations which means it should be able to handle forward slashes as well.

A good approach, especially when you are setting up a new configuration and you see it failing for path reasons, is to put everything straight into the folder where you're sure Gradle (or any other system/build) is able to see it. In your case that would be either gradle home or same folder where your build.gradle is. Then, after you get everything to work, you can reorganize and put configs however you like.

EDIT:

It is also always a good idea to find a way how to printout something while your build / script / whatever is executing. So, for Gradle you can use println to print a property name:

task printSigning {
    println(project.findProperty('signing').secretKeyRingFile)
}

Or you can print a current directory:

task currentDir {
    println file('.')
}

I hope that this helps a bit.

Below questions might contain some more details and give you a hint too:

https://stackoverflow.com/a/67115705/177154

https://stackoverflow.com/a/68505768/177154

draganstankovic
  • 5,382
  • 1
  • 27
  • 33
  • Thank you. I'm fairly new to gradle and groovy, so anything that helps rule out something helps quite a bit. "Gradle relies on java.io.File". In other words i could write the path as: signing.secretKeyRingFile=/Users/username/secring.gpg instead. I actually placed gradle.properties files in 3 places now: The gradle-wrapper.properties in the wrapper folder. One under C:\Users\username\.gradle (Should be my GRADLE_USER_HOME directory right? Any gradle command i could use to be sure of this?) And a final properties file in the same folder as the gradle.build file. All with the same content. – Dahl May 27 '22 at 22:26
  • I have also tried with both ./gradlew publish and gradle publish. One thing i am unsure about, is that I recently updated gradle from v 6.2 to 7.4.2. So i would not be surprised if the issue is related to this. I wish i could pin point the exact reason for the task failiure. Maybe i haven't properly set up sonatype jira. – Dahl May 27 '22 at 22:26
  • Could there be some security issue with windows? I'm sorry for all the counter questions :) – Dahl May 27 '22 at 23:03
  • Ideally you would put your secring in the current folder so your path could be: `signing.secretKeyRingFile=secring.gpg` – draganstankovic May 28 '22 at 02:36
  • Ok. Do you know if you have to run any other tasks before gradle publish? Given my build structure. – Dahl May 28 '22 at 14:00
0

If you are getting this error in 2023 with Gradle 7+:

Take a look at this step by step guide with code examples for "how to publish to maven central with Gradle".

https://github.com/davidweber411/how-to-publish-to-maven-central-with-gradle

PS: I am the author.

David Weber
  • 173
  • 9