Skip to content

Instantly share code, notes, and snippets.

@zsmb13

zsmb13/build.gradle (module) Secret

Last active May 14, 2021
Embed
What would you like to do?
Gradle config files for publishing to MavenCentral. Full article https://proandroiddev.com/publishing-android-libraries-to-mavencentral-in-2021-8ac9975c3e52 , latest live versions of these in a working repo https://github.com/GetStream/stream-chat-android/tree/develop/scripts
// 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 {
artifact("$buildDir/libs/${project.getName()}-${version}.jar")
}
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'
}
}
}
}
}
}
ext["signing.keyId"] = rootProject.ext["signing.keyId"]
ext["signing.password"] = rootProject.ext["signing.password"]
ext["signing.secretKeyRingFile"] = rootProject.ext["signing.secretKeyRingFile"]
signing {
sign publishing.publications
}
// Create variables with empty default values
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''
ext["sonatypeStagingProfileId"] = ''
ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.secretKeyRingFile"] = ''
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.secretKeyRingFile"] = System.getenv('SIGNING_SECRET_KEY_RING_FILE')
}
// 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/"))
}
}
}
@saidahakim21

This comment has been minimized.

Copy link

@saidahakim21 saidahakim21 commented Apr 22, 2021

i am getting the following error :
Caused by: org.gradle.api.InvalidUserDataException: Cannot add a NexusRepository with name 'sonatype' as a NexusRepository with that name already exists.

do you have any idea how can i fix that please ?
thank you

@zsmb13

This comment has been minimized.

Copy link
Owner Author

@zsmb13 zsmb13 commented Apr 22, 2021

That happens when the nexusPublishing block runs more than once. Make sure you apply the publish-root.gradle scipt that contains it only once, and in the project level (root) build.gradle file.

@saidahakim21

This comment has been minimized.

Copy link

@saidahakim21 saidahakim21 commented Apr 22, 2021

Thank you for your reply,
i just checked, i only apply it once per file (root build.gradle + module build.gradle)
i removed it from root file and it seem to fix it somehow, i no longer have the same problem (:signReleasePublication FAILED
for now )
thank you

@zsmb13

This comment has been minimized.

Copy link
Owner Author

@zsmb13 zsmb13 commented Apr 22, 2021

I recommend placing the nexusPublishing block in only the root build.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.

@atsushieno

This comment has been minimized.

Copy link

@atsushieno atsushieno commented May 10, 2021

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.

@KibiH

This comment has been minimized.

Copy link

@KibiH KibiH commented May 10, 2021

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?

@KibiH

This comment has been minimized.

Copy link

@KibiH KibiH commented May 10, 2021

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!

@pilgr

This comment has been minimized.

Copy link

@pilgr pilgr commented May 13, 2021

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.

@zsmb13

This comment has been minimized.

Copy link
Owner Author

@zsmb13 zsmb13 commented May 14, 2021

@pilgr: thanks for the note, some others bumped into this too. I've now fixed this is all versions of the article :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment