-
-
Save zsmb13/56ed98c8fe916de441f2a9d8e060cd4a to your computer and use it in GitHub Desktop.
// Lines to add in module level build.gradle file for modules you publish | |
ext { | |
// Provide your own coordinates here | |
PUBLISH_GROUP_ID = 'io.getstream' | |
PUBLISH_VERSION = '4.8.1' | |
PUBLISH_ARTIFACT_ID = 'stream-chat-android-client' | |
} | |
apply from: "${rootProject.projectDir}/scripts/publish-module.gradle" |
// Lines to add to the project level (root) build.gradle file | |
// 1a: plugins block application of the publishing plugin | |
plugins { | |
id("io.github.gradle-nexus.publish-plugin") version "1.1.0" | |
} | |
// 1b: old plugin syntax for publishing plugin | |
buildscript { | |
dependencies { | |
classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' | |
} | |
} | |
apply plugin: 'io.github.gradle-nexus.publish-plugin' | |
// 2: applying separate publishing script | |
apply from: "${rootDir}/scripts/publish-root.gradle" |
apply plugin: 'maven-publish' | |
apply plugin: 'signing' | |
task androidSourcesJar(type: Jar) { | |
archiveClassifier.set('sources') | |
if (project.plugins.findPlugin("com.android.library")) { | |
// For Android libraries | |
from android.sourceSets.main.java.srcDirs | |
from android.sourceSets.main.kotlin.srcDirs | |
} else { | |
// For pure Kotlin libraries, in case you have them | |
from sourceSets.main.java.srcDirs | |
from sourceSets.main.kotlin.srcDirs | |
} | |
} | |
artifacts { | |
archives androidSourcesJar | |
} | |
group = PUBLISH_GROUP_ID | |
version = PUBLISH_VERSION | |
afterEvaluate { | |
publishing { | |
publications { | |
release(MavenPublication) { | |
// The coordinates of the library, being set from variables that | |
// we'll set up later | |
groupId PUBLISH_GROUP_ID | |
artifactId PUBLISH_ARTIFACT_ID | |
version PUBLISH_VERSION | |
// Two artifacts, the `aar` (or `jar`) and the sources | |
if (project.plugins.findPlugin("com.android.library")) { | |
from components.release | |
} else { | |
from components.java | |
} | |
artifact androidSourcesJar | |
artifact javadocJar | |
// Mostly self-explanatory metadata | |
pom { | |
name = PUBLISH_ARTIFACT_ID | |
description = 'Stream Chat official Android SDK' | |
url = 'https://github.com/getstream/stream-chat-android' | |
licenses { | |
license { | |
name = 'Stream License' | |
url = 'https://github.com/GetStream/stream-chat-android/blob/main/LICENSE' | |
} | |
} | |
developers { | |
developer { | |
id = 'zsmb13' | |
name = 'Márton Braun' | |
email = 'marton@getstream.io' | |
} | |
// Add all other devs here... | |
} | |
// Version control info - if you're using GitHub, follow the | |
// format as seen here | |
scm { | |
connection = 'scm:git:github.com/getstream/stream-chat-android.git' | |
developerConnection = 'scm:git:ssh://github.com/getstream/stream-chat-android.git' | |
url = 'https://github.com/getstream/stream-chat-android/tree/main' | |
} | |
} | |
} | |
} | |
} | |
} | |
signing { | |
useInMemoryPgpKeys( | |
rootProject.ext["signing.keyId"], | |
rootProject.ext["signing.key"], | |
rootProject.ext["signing.password"], | |
) | |
sign publishing.publications | |
} |
// Create variables with empty default values | |
ext["ossrhUsername"] = '' | |
ext["ossrhPassword"] = '' | |
ext["sonatypeStagingProfileId"] = '' | |
ext["signing.keyId"] = '' | |
ext["signing.password"] = '' | |
ext["signing.key"] = '' | |
File secretPropsFile = project.rootProject.file('local.properties') | |
if (secretPropsFile.exists()) { | |
// Read local.properties file first if it exists | |
Properties p = new Properties() | |
new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) } | |
p.each { name, value -> ext[name] = value } | |
} else { | |
// Use system environment variables | |
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME') | |
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD') | |
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID') | |
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID') | |
ext["signing.password"] = System.getenv('SIGNING_PASSWORD') | |
ext["signing.key"] = System.getenv('SIGNING_KEY') | |
} | |
// Set up Sonatype repository | |
nexusPublishing { | |
repositories { | |
sonatype { | |
stagingProfileId = sonatypeStagingProfileId | |
username = ossrhUsername | |
password = ossrhPassword | |
// Add these lines if using new Sonatype infra | |
// nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) | |
// snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) | |
} | |
} | |
} |
The script is very helpful and I incorporated some bits in my project too.
One thing I find it cumbersome is that it always tries to read signing info from local.properties
even if I want to resort to environment variables (particularly when I can easily verify CI setup). Since almost all Android projects end up with local.properties
, there is almost no chance to use environment variables locally with the current script.
I rewrote the publish-root.gradle
so that environment variables take higher precedence than local.properties
like:
File secretPropsFile = project.rootProject.file('local.properties')
if (secretPropsFile.exists()) {
// Read local.properties file first if it exists
Properties p = new Properties()
new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
p.each { name, value -> ext[name] = value }
}
// Use system environment variables
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME') ?: ext["ossrhUsername"]
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD') ?: ext["ossrhPassword"]
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID') ?: ext["sonatypeStagingProfileId"]
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID') ?: ext["signing.keyId"]
ext["signing.password"] = System.getenv('SIGNING_PASSWORD') ?: ext["signing.password"]
ext["signing.secretKeyRingFile"] = System.getenv('SIGNING_SECRET_KEY_RING_FILE') ?: ext["signing.secretKeyRingFile"]
This may be more helpful.
Hi there, thanks so much for your article and for this. I have tried implementing it as you wrote, - I received the reply from Sonatype that I was good to go, but when I ran
./gradlew my-project:publishReleasePublicationToSonatypeRepository
I receive back an error like this:
* What went wrong:
Execution failed for task ':initializeSonatypeStagingRepository'.
> Failed to create staging repository, server at https://s01.oss.sonatype.org/service/local/ responded with status code 403, body: <html>
<head>
<title>403 - Forbidden</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel="icon" type="image/png" href="https://s01.oss.sonatype.org/favicon.png">
<!--[if IE]>
<link rel="SHORTCUT ICON" href="https://s01.oss.sonatype.org/favicon.ico"/>
<![endif]-->
<link rel="stylesheet" href="https://s01.oss.sonatype.org/static/css/Sonatype-content.css?2.14.20-02" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body>
<h1>403 - Forbidden</h1>
<p>Forbidden</p>
</body>
</html>
I sent a request to Sonatype, but I'm wondering if you can figure out what I did wrong?
Hi there, thanks so much for your article and for this. I have tried implementing it as you wrote, - I received the reply from Sonatype that I was good to go, but when I ran
./gradlew my-project:publishReleasePublicationToSonatypeRepository
I receive back an error like this:* What went wrong: Execution failed for task ':initializeSonatypeStagingRepository'. > Failed to create staging repository, server at https://s01.oss.sonatype.org/service/local/ responded with status code 403, body: <html> <head> <title>403 - Forbidden</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <link rel="icon" type="image/png" href="https://s01.oss.sonatype.org/favicon.png"> <!--[if IE]> <link rel="SHORTCUT ICON" href="https://s01.oss.sonatype.org/favicon.ico"/> <![endif]--> <link rel="stylesheet" href="https://s01.oss.sonatype.org/static/css/Sonatype-content.css?2.14.20-02" type="text/css" media="screen" title="no title" charset="utf-8"> </head> <body> <h1>403 - Forbidden</h1> <p>Forbidden</p> </body> </html>
I sent a request to Sonatype, but I'm wondering if you can figure out what I did wrong?
OK, my idiocy, I had not correctly copied in the sonatypeStagingProfileId
Thank you so much for this extremely helpful article/tutorial. Really saved me!
Thank you for the article! I noticed that sonatypeStagingProfileId
must be set before running first publication in "Your first release" section of the article. Otherwise I was getting access denied error. Might be confusing for some readers.
@pilgr: thanks for the note, some others bumped into this too. I've now fixed this is all versions of the article :)
@zsmb13 Thanks a lot for the article. I have a usecase where I need to publish my Android module but it is not enclosed within a root project. It exists as a standalone module that I usually import manually. Do you have any resources for publishing such modules ? Is is absolutely required for a module to be enclosed within a root project for it to be publishable ?
@christyjacob4 I believe that should still be possible. For a first attempt I'd move all the configuration in my sample that lives in the root project to that module, and then see if it works like that. I can't say what exactly you might have to fix with that kind of setup after that because I haven't used a setup like that before, so it might take some trial and error / debugging.
@zsmb13 Have you come across any OS projects like this that I can maybe use as a reference ?
Thanks again 😄
Any idea how to resolve this issue.
Execution failed for task ':my-project:generatePomFileForMYProjectPublishPublication'.
java.lang.StackOverflowError (no error message)
I get the following error when I try to include the publish-module.gradle file
in build.gradle
file of my library module
Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'kotlin' for source set main of type com.android.build.gradle.internal.api.DefaultAndroidSourceSet.
@gargVader if you're not using a Kotlin source set, simply remove the lines that refer to it.
Thanks a lot @zsmb13.
Just a quick note for people having issue with the signing.key
format, if you want to put it in the local.properties
, the format should look like this:
signing.key=\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\nxxx\nyyy\n-----END PGP PRIVATE KEY BLOCK-----\n
@zsmb13
Facing this issue on Github Action only
Cannot perform signing task ':universal_adapter:signReleasePublication' because it has no configured signatory
One thing I had to do since the project I was making was provisioned after Feb 2021 was configuring the nexus publish plugin to point to the updated urls, otherwise it was failing authentication trying to reach the legacy server.
nexusPublishing {
repositories {
sonatype { //only for users registered in Sonatype after 24 Feb 2021
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
}
}
}
https://github.com/gradle-nexus/publish-plugin/#publishing-to-maven-central-via-sonatype-ossrh
@zsmb13
Hey there, thanks for your article.
I came across this issue,
Could not find method useInMemoryPgpKeys() for arguments [XXXXXXX, <Key which I get from gpg --export-secret-keys XXXXXXX | base64> , passphrase] on object of type org.gradle.plugins.signing.SigningExtension.
Could you please help with the same?
I have this issue too
@zsmb13 Hey there, thanks for your article. I came across this issue,
Could not find method useInMemoryPgpKeys() for arguments [XXXXXXX, <Key which I get from gpg --export-secret-keys XXXXXXX | base64> , passphrase] on object of type org.gradle.plugins.signing.SigningExtension.
Could you please help with the same?
i am getting this error.
:base:generatePomFileForMavenAarPublication.
> Cannot query the value of this property because it has no value available.
Can you help me understand how to debug this error as i am not able to catch the exact problem.
Thanks @zsmb13.
Thanks @ThomasGorisse , it really helped me escape the error of 'Could not read PGP secret key'. And build is successful after long time.
@zsmb13 Facing this issue on Github Action only
Cannot perform signing task ':universal_adapter:signReleasePublication' because it has no configured signatory
did u find any fix? i am getting same error but on local machine
I recommend placing the
nexusPublishing
block in only the rootbuild.gradle
instead of the module level one, that way you'll be able to publish multiple modules from your project, should you ever need to. That's what the snippets above are doing, as well as the example linked at the top.