preface

I wrote a long time ago about releasing open source libraries to JCenter, but unfortunately a few months ago Jfrog made a statement to terminate the Bintray service. The statement basically said that jCenter repository would no longer accept user component submissions after March 31, 2021, and would make jCenter a read-only repository. This means that the current state of the Jcenter repository is that you can no longer commit updates to components, but you can continue to download versions of your previously hosted components, so what you need to do now is to release new versions of your components to other repositories, such as Jitpack and MavenCentral. I’ve written an article about quickly releasing open source libraries to the JitPack. This article teaches you how to publish components to the MavenCentral repository, and I’ve written a release script to simplify the process.

Script address: MavenPublishScript

preparation

Before I talk about this, it’s worth introducing the relationship between Sonatype, OSSRH, and MavenCentral. Sonatype is a company that operates the MavenCentral repository, and we want to publish components to MavenCentral. Sonatype’s OSSRH, which stands for OSS Repository Hosting, Sonatype uses Nexus Repository Manager to provide Repository Hosting for components. We publish components to Sonatype OSSRH before synchronizing them to the MavenCentral repository, just as we used to publish components to Jfrog Bintray before synchronizing them to the Jcenter repository.

1. Register a Sonatype account

First you need to register for a Sonatype Jira account. Sonatype uses Jira to manage your groupId application process. The registered address is:

Sonatype Jira – Sign up

Click on the registered address, as shown in the figure:

Fill in your email address, name, user name and password as required. The user name should not be in Chinese. Remember your user name and password, which will be used later.

2. Apply for groupId

When we use components hosted in a remote repository, we locate them by their GAV coordinates (groupId, artifactId, version). GroupId is the repository you created in Sonatype OSSRH. GroupId is the name of your repository. To apply for groupId is to apply to create your own repository in Sonatype OSSRH. When we publish components in the future, we must first publish to the repository named groupId on Sonatype OSSRH, and then synchronize to the MavenCentral repository.

Also, groupId is not a placeholder. According to Sonatype, groupId must be the reverse of a domain name, so you have a domain name. When you apply for groupId, Sonatype will somehow let you prove that you are the owner of the domain name.

If you own a domain name, such as example.com, you can use any groupId starting with com.example, such as com.example.test1, com.example.test2, etc. It doesn’t matter if you don’t own your own domain. Sonatype supports code hosting platforms for Pages site domains such as Github. You can start your Pages service on your Github account and you will have a personal domain name associated with your Github account in the format {username}.github. IO. For example, my Github Pages site is Rain9155. Github. IO. The following table lists the official tutorial addresses of these commonly used code hosting platform Pages service, and the corresponding domain names and corresponding groupId:

Code hosting platform Pages Service start tutorial address The domain name groupId
Github pages.github.com/ {username}.github.io io.github.{username}
Gitee Gitee.com/help/articl… {username}.gitee.io io.gitee.{username}
GitLab About.gitlab.com/stages-devo… {username}.gitlab.io io.gitlab.{username}

I want to apply for a groupId named io.github. Rain9155. First, open the Sonatype Jira website with the address as follows:

Sonatype Jira – Dashboard

Enter the Sonatype Jira user name and password you just registered to log in, then go to the Sonatype Jira homepage, then click the Create button in the navigation bar, a pop-up will pop up, will ask you to fill in some information to apply for groupId. Select Community Support-open Source Project Repository Hosting (OSSRH) for Project, select New Project for Issue Type, and fill in a title for Summary. Set the Group Id to the groupId you want to apply for, set the Project URL to the address of your component repository, and set the SCM URL to the version control address of your component repository as follows:

Finally click on the Create button and it will create an issue with the format of OSSRH-{taskId}, in this case OSSRH-69596, which you can see in the All Projects panel, and then wait for an email notification from Sonatype Jira, The email will be sent to the email address you filled in when you registered your account. Its first email will ask you to create an empty repository on your Github named OSSRH-{taskId} to prove that you are the owner of the groupId domain name. When you create it, You need to reply in the COMMENT panel under OSSRH-{taskId}. When you reply, it will send you another email telling you that groupId has been applied. At this point, you can publish the component to Sonatype OSSRH. You need to synchronize your component to the MavenCentral in Sonatype OSSRH before you can reference it via GAV. See how to do this later. After you synchronize, you need to reply again in the COMMENT panel under OSSRH-{taskId}. Then Sonatype OSSRH will activate the component synchronization to the MavenCentral program for you. For the entire communication process, please refer to the comment panel in my OSSRH-69596, as follows:

It does not matter what the reply is, as long as you reply, the above is the whole process of applying groupId and activating MavenCentral synchronization. It only needs to be done once when the component is published for the first time, and it does not need to be done again when the component is published in the future. The groupId is used directly.

3. Generate GPG signature information

Sonatype requires that every file published in the components of the MavenCentral repository be signed by GPG, a command-line tool that provides the ability to sign and encrypt data, supports mainstream signature and encryption algorithms, and provides a key management system. To use GPG signature, We must first install GPG on the computer and then use GPG to generate the key pairs required for the signature.

Let’s first install GPG. For Macs, just install it directly via Homebrew, and run it from the command line:

$ brew install gpg
Copy the code

For Windows computers, we can download the GPG execution file installation at:

gpg download

After the installation is complete, run the GPG –version command on the CLI. If the GPG version information is displayed, the installation is complete.

$GPG --version GPG (GnuPG) 2.2.27 libgcrypt 1.8.7 Copyright (C) 2021 G10 Code GmbH License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Home: C:/Users/HY/AppData/Roaming/gnupg Supported algorithms: Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256 Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224 Compression: Uncompressed, ZIP, ZLIB, BZIP2Copy the code

Then type GPG — full-generation-key on the command line to generate the key pair. This command will let you select the information you need to generate the key pair step by step, as follows:

$GPG --full-generate-key GPG (GnuPG) 2.2.27; Copyright (C) 2021 g10 Code GmbH This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) (14) Existing key from card Your selection? 4 RSA keys may be between 1024 and 4096 bits long. What keysizedoyou want? (3072) Requested keysize is 3072 bits Please specify how long the key should be valid. 0 = key does not expire <n> = key  expiresin n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: rain9155
Email address: [email protected]
Comment:
You selected this USER-ID:
    "rain9155 <[email protected]>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key DF7B4B4D1A32FB02 marked as ultimately trusted
gpg: revocation certificate stored as 'C:/Users/HY/AppData/Roaming/gnupg/openpgp-revocs.d\9E02D0E104E3D3517B5B0E54DF7B4B4D1A32FB02.rev'
public and secret key created and signed.

Note that this key cannot be used for encryption.  You may want to use
the command "--edit-key" to generate a subkey for this purpose.
pub   rsa3072 2021-07-06 [SC]
      9E02D0E104E3D3517B5B0E54DF7B4B4D1A32FB02
uid                      rain9155 <[email protected]>
Copy the code

First it will make your selection algorithm, I chose the RSA, here is used only for the signature, and then will let you input a key length, the default, 3072 bits, and then you will be asked to select your key expiration time, here I chose a permanent, suggest you also choose permanent, and then after confirmation will let you input your name, email, annotations as a unique identifier for the key, In this case, I generated the identifier “Rain9155

“, and when I confirm it, a pop-up will ask you to enter a password to protect your private key, remember that the password you enter will be used later, Public and Secret Key Created and signed public and Secret Key created and signed GPG –list-secret-keys = GPG –list-keys = GPG –list-keys = GPG –list-keys = GPG –list-keys = GPG –list-keys = GPG –list-keys
@gmail.com>

$ gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
C:/Users/HY/AppData/Roaming/gnupg/pubring.kbx
---------------------------------------------
pub   rsa3072 2021-07-06 [SC]
      9E02D0E104E3D3517B5B0E54DF7B4B4D1A32FB02
uid           [ultimate] rain9155 <[email protected]>
Copy the code

Information has a public key file location first, listed here to C: / Users/HY/AppData/Roaming/gnupg/pubring KBX, followed by a pub rsa3072 2021-07-06 (SC), said the use of RSA algorithm, public key length is 3072 bits, Create a date for the 2021-07-06, followed by a long string of nine e02d0e104e3d3517b5b0e54df7b4b4d1a32fb02 id value, which represents the public key id, need to use it only when we use after eight line, Therefore, we only need to use 1A32FB02 when using this public key. Finally, the unique identifier of the public key is generated based on the name, mailbox, and comment we entered earlier.

We only need to use the private key to sign, and the public key needs to be uploaded to the public keyserver, so that the file we signed with the private key can be uploaded to MavenCenral, and then it can use the public key to verify the file. Here I chose the public keyserver keyserver.ubuntu.com. The command format for uploading the public key is GPG –keyserver address of the public keyserver — song-keys public key id. I upload the newly generated public key 1A32FB02 to the public keyserver as follows:

$ gpg --keyserver keyserver.ubuntu.com --send-keys 1A32FB02
gpg: sending key DF7B4B4D1A32FB02 to hkp://keyserver.ubuntu.com
Copy the code

If there is no error message, the upload is successful. We can also use GPG –keyserver address –recv-keys public key id to import the public key from the public keyserver to the local to verify whether the upload is successful. As follows:

$ gpg --keyserver keyserver.ubuntu.com --recv-keys 1A32FB02
gpg: key DF7B4B4D1A32FB02: "rain9155 <[email protected]>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1
Copy the code

If the import is successful, the public key is successfully uploaded to the public key server.

As a final step, export the private key to a file, so that when we publish the component, we can use this file to sign with the private key. The command format is GPG -o path to the exported file –export-secret-key private key ID. Export the private key to a file named 1a32fb02.gpg. The private key ID is the same as the public key ID:

$ gpg -o D:/File/keystore/1A32FB02.gpg --export-secret-key 1A32FB02
Copy the code

Now have successfully to the private key export D: / File/keystore / 1 a32fb02. GPG, remember you export the private key File path, can use later.

Published to OSSRH

Now everything is ready to publish the component, using the Maven-Publish plugin. The main content we publish is the aar or JAR file of the component, the sources file, the Javadoc file, the POM file, and the signature file of these files with the.asc suffix. To simplify the publishing process, I have written the publishing process into a Gradle script – MavenPublishScript. To use this script, you just need to apply in and fill in the basic publishing information. When you execute the publishing task, you can automatically generate all the files needed for publishing and publish them to OSSRH. Here is a brief introduction to how to use this Gradle script.

First apply the script to your component’s build.gradle:

apply from: 'https://raw.githubusercontent.com/rain9155/MavenPublishScript/main/script/publication.gradle'
Copy the code

Next, prepare the Sonatype account you registered earlier, the groupId you applied for, and the GPG private key you generated. Then add the component information to the gradle.properties of the component (if not created), where the GAV coordinates are required and the rest are optional:

Publish.groupid =io.github. Rain9155 Publish.artifactid = MavenPublishScript publish.version=1.0. 0Publish. Description = A Gradle script that publishes components to a Maven repository, which supports aar and JAR publishing published.url =https://github.com/rain9155/MavenPublishScriptDeveloperName =rain9155 publish.developeremail = Jianyu9155@gmailPublish. LicenseName =The Apache license, Version2.0
publish.licenseUrl=http:/ / www.apache.org/licenses/LICENSE-2.0.txt# SCM information, format referencehttp://maven.apache.org/scm/scm-url-format.html
publish.scmUrl=https://github.com/rain9155/MavenPublishScript/tree/master
publish.scmConnection=scm:git:git://github.com/rain9155/MavenPublishScript.git
publish.scmDeveloperConnection=scm:git:ssh://github.com:rain9155/MavenPublishScript.git# When publishing an Android componentfalseIf you don't want to add a flavorName to a component's artifactId, you can set this parameter tofalseBy default,true
publish.artifactId.isAppendFavorName=false
Copy the code

Then add the GPG signature and osSRH account information to local.properties(if not created) in the project root directory. Be sure to remove local.properties from your version control to avoid leaking your signature and account information:

# GPG signing message signing.keyId= your keyId, for example1A32FB02 signing. Password = your private key password. Signing secretKeyRingFile = your private key file path, for exampleD:/File/keystore/1A32fb02.gpg # OSSRh Account information osSRh. username= Your OSSRH account name (Sonatype account name) ossrh.password= your OSSRH account password (Sonatype account password)Copy the code

Finally, run the Gradle task on the command line to publish the component. If you are publishing an Android component (AAR), Perform the task of the name of the format for the publish {flavorName} AndroidlibPublicationToMavenRepository or publish AndroidlibPublicationToMavenLoca {flavorName} FlavorName is the name of the Android component’s flavor. If you have no flavorName, do not fill in the flavorName. If you publish a Java component (JAR), Perform the task name for publishJavalibPublicationToMavenRepository or publishJavalibPublicationToMavenLocal:

/ / released android components to maven local repository gradle publishAndroidlibPublicationToMavenLocal / / release android components to maven remote release or a snapshot gradle warehouse PublishAndroidlibPublicationToMavenRepository / / assume that android component contains flavorName for China, China release version of the android components to maven local repository gradle publishChinaAndroidlibPublicationToMavenLocal / / suppose android component contains flavorName to oversea, Oversea release version of the android components to maven remote release or a snapshot warehouse gradle publishOverseaAndroidlibPublicationToMavenRepository / / release the Java component to maven local warehouse gradle publishJavalibPublicationToMavenLocal/release/Java component to maven remote release or a snapshot gradle warehouse PublishJavalibPublicationToMavenRepository / / publish all android components and Java components to maven local warehouse gradle publishToMavenLocal / / release all the android components and Java components to maven remote release or a snapshot warehouse gradle publishAllPublicationsToMavenRepository // Publish all Android and Java components to maven local repository and Maven remote Release or Snapshot repository gradle PublishCopy the code

The release task according to the component is released android components (aar) or Java components (jar) to perform, at the same time release android components support flavor release, said to the remote warehouse OSSRH issued publishXXToMavenRepository tasks, {user directory}/.m2/repository/. You can also view these tasks in the Gradle panel on the left of AS:

Selected double-click on task execution of the right, if you perform is publishXXToMavenRepository task, after the success of the task, you can to OSSRH check your release components, for the first time into the need to log in, enter your Sonatype user name and password login, Then click on the lower left to see what components you are publishing to OSSRH.

In the Staging Repository pane, you can view your published component. Select it and click on the Content pane below to see the details of the published component.

Synchronization to MavenCentral

After the component is published to OSSRH, it cannot be referenced through GAV. It must be synchronized to MavenCentral before it can be referenced through GAV. First, Close the component on OSSRH and change its Close state from open to Close, as follows:

When you click the Close button, a popup window will ask you to confirm. When you confirm, the Close button will gray out, and the Activity panel below will display the validation rules that you did during the Close process, such as verifying that your published file has a signature, contains a Javadoc file, and contains the Sources file. If the POM file is qualified, you can synchronize the component to MavenCentral only after all verification is passed. After verification, you will receive an email from Sonatype. At this time, you can click the Release button above to synchronize the component to MavenCentral, as follows:

When you click the Release button, it will pop up a popover asking you to confirm, and when you do, the Release button will gray out. If you are publishing a component for the first time, as I said in groupId application, you have to go to the COMMENT panel of OSSRH-{taskid} and reply to it once before OSSRH will activate synchronization for you, You can search the MavenCentral site for your component and reference it via GAV in a build tool such as Gradle or Maven. After activating the syncing program, you can use the GAV to synchronize your component to the MavenCentral site. The next time you Release the component, it’s automatically synchronized to the MavenCentral and you don’t have to do anything else.

conclusion

The steps for publishing to MavenCentral are much more complex than publishing to the Jitpack, which requires only a code managed repository account, while MavenCentral requires a Sonatype account, personal domain name, and signature information. But MavenCentral is much more mature than Jitpack. It is currently the largest managed repository for Java components and other open source components, and the default repository for many build systems like Maven, depending on your preferences.

That’s all for this article!

References:

JCenter service update

The Central Repository Documentation

Use the Maven Publish plugin