Skip to content

Commit 8fcc497

Browse files
committed
Migrate from OSSRH to Sonatype Central publishing
- Switch to gradleup/nmcp plugin for automatic publication - Update GitHub Actions to use SONATYPE_USERNAME/SONATYPE_PASSWORD - Remove manual repository configuration and staging steps - Configure modern GPG signing using global iterable secrets
1 parent 05ce7d1 commit 8fcc497

File tree

5 files changed

+58
-77
lines changed

5 files changed

+58
-77
lines changed

.editorconfig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@ root = true
33
[*]
44
indent_style = space
55
indent_size = 4
6-
tab_width = 4
6+
tab_width = 4
7+
8+
[*.{yml,yaml}]
9+
indent_size = 2
10+
tab_width = 2

.github/workflows/publish.yml

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
name: Publish to Maven Central
1+
name: Publish to Sonatype Central
22

33
on:
44
push:
5+
branches:
6+
- sonatype-publish # for testing the action
57
tags:
6-
- 'v*' # Trigger on version tags
8+
- "*.*.*" # Match semantic version tags like 3.5.13
9+
- "*.*.*-*" # Match pre-release tags like 3.6.0-beta1, 3.5.12-stg
710
workflow_dispatch: # Allow manual trigger
811

912
jobs:
@@ -15,30 +18,24 @@ jobs:
1518
- name: Set up JDK
1619
uses: actions/setup-java@v4
1720
with:
18-
java-version: '17'
19-
distribution: 'temurin'
21+
java-version: "17"
22+
distribution: "temurin"
2023
cache: gradle
2124

22-
- name: Import GPG Key
25+
- name: Import GPG Key and Create Secring
2326
run: |
24-
echo "${{ secrets.GPG_PRIVATE_KEY }}" | base64 -d > private.gpg
25-
gpg --batch --import private.gpg
26-
rm private.gpg
27+
echo "${{ secrets.GPG_SECRET_KEY }}" | base64 -d | gpg --batch --import
28+
# Create secring.gpg for Gradle signing plugin compatibility
29+
gpg --batch --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --export-secret-keys > ~/.gnupg/secring.gpg
30+
# Extract last 8 characters for short format
31+
GPG_KEY="${{ secrets.GPG_KEY_ID }}"
32+
echo "SHORT_GPG_KEY_ID=${GPG_KEY: -8}" >> $GITHUB_ENV
2733
28-
- name: Build
29-
run: ./gradlew clean build
34+
- name: Build and Publish to Sonatype Central
35+
run: ./gradlew clean assemble publishAllPublicationsToCentralPortal
3036
env:
31-
ORG_GRADLE_PROJECT_SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
32-
ORG_GRADLE_PROJECT_SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
33-
ORG_GRADLE_PROJECT_SIGNING_SECRET_KEY_RING_FILE: ~/.gnupg/secring.gpg
34-
ORG_GRADLE_PROJECT_NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
35-
ORG_GRADLE_PROJECT_NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
36-
37-
- name: Publish to Maven Central
38-
run: ./gradlew uploadArchives
39-
env:
40-
ORG_GRADLE_PROJECT_SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
41-
ORG_GRADLE_PROJECT_SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
42-
ORG_GRADLE_PROJECT_SIGNING_SECRET_KEY_RING_FILE: ~/.gnupg/secring.gpg
43-
ORG_GRADLE_PROJECT_NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
44-
ORG_GRADLE_PROJECT_NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
37+
ORG_GRADLE_PROJECT_SIGNING_KEY_ID: ${{ env.SHORT_GPG_KEY_ID }}
38+
ORG_GRADLE_PROJECT_SIGNING_PASSWORD: ${{ secrets.GPG_PASSPHRASE }}
39+
ORG_GRADLE_PROJECT_SIGNING_SECRET_KEY_RING_FILE: /home/runner/.gnupg/secring.gpg
40+
ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
41+
ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,6 @@ pom.xml.versionsBackup
6767
pom.xml.next
6868
release.properties
6969

70-
jacoco.exec
70+
jacoco.exec
71+
# VSCode settings
72+
.vscode/

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ buildscript {
1717
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
1818
}
1919
classpath "com.github.dcendents:android-maven-gradle-plugin:2.1"
20+
classpath "com.gradleup.nmcp:nmcp:0.0.8"
2021
// NOTE: Do not place your application dependencies here; they belong
2122
// in the individual module build.gradle files
2223
}
@@ -32,4 +33,4 @@ allprojects {
3233

3334
task clean(type: Delete) {
3435
delete rootProject.buildDir
35-
}
36+
}

maven-push.gradle

Lines changed: 27 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,50 +16,42 @@
1616

1717
apply plugin: 'maven-publish'
1818
apply plugin: 'signing'
19+
apply plugin: 'com.gradleup.nmcp'
1920

2021
Properties properties = new Properties()
21-
properties.load(project.rootProject.file('local.properties').newDataInputStream())
22+
if (project.rootProject.file('local.properties').exists()) {
23+
properties.load(project.rootProject.file('local.properties').newDataInputStream())
24+
}
2225

2326
def isReleaseBuild() {
2427
return libraryVersion.contains("SNAPSHOT") == false
2528
}
2629

27-
def getReleaseRepositoryUrl() {
28-
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
29-
: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
30-
}
30+
// Set the project version
31+
project.version = libraryVersion
3132

32-
def getSnapshotRepositoryUrl() {
33-
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
34-
: "https://oss.sonatype.org/content/repositories/snapshots/"
35-
}
36-
37-
def getRepositoryUsername() {
38-
return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
39-
}
40-
41-
def getRepositoryPassword() {
42-
return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
43-
}
44-
45-
def keyID = properties.getProperty("signing.keyId")
46-
def signing_password = properties.getProperty("signing.password")
47-
def keyRingLocation = properties.getProperty("signing.secretKeyRingFile")
48-
def nexus_username = properties.getProperty("NEXUS_USERNAME")
49-
def nexus_password = properties.getProperty("NEXUS_PASSWORD")
33+
// Simple property lookup: local.properties first, then project properties (from ORG_GRADLE_PROJECT_* env vars)
34+
def keyID = properties.getProperty("signing.keyId") ?: findProperty('SIGNING_KEY_ID')
35+
def signing_password = properties.getProperty("signing.password") ?: findProperty('SIGNING_PASSWORD')
36+
def keyRingLocation = properties.getProperty("signing.secretKeyRingFile") ?: findProperty('SIGNING_SECRET_KEY_RING_FILE')
37+
def sonatype_username = properties.getProperty("SONATYPE_USERNAME") ?: findProperty('SONATYPE_USERNAME')
38+
def sonatype_password = properties.getProperty("SONATYPE_PASSWORD") ?: findProperty('SONATYPE_PASSWORD')
5039

5140
ext."signing.keyId" = keyID
52-
ext."signing.secretKeyRingFile" = keyRingLocation
5341
ext."signing.password" = signing_password
5442

43+
// Set secretKeyRingFile if provided
44+
if (keyRingLocation) {
45+
ext."signing.secretKeyRingFile" = keyRingLocation
46+
}
47+
5548
publishing {
5649
publications {
5750
release(MavenPublication) {
58-
groupId = GROUP
59-
artifactId = libraryName
60-
version = libraryVersion
61-
6251
afterEvaluate {
52+
groupId = GROUP
53+
artifactId = libraryName
54+
version = libraryVersion
6355
from components.release
6456
}
6557

@@ -92,32 +84,17 @@ publishing {
9284
}
9385
}
9486
}
95-
repositories {
96-
maven {
97-
name = "OSSRH"
98-
url = isReleaseBuild() ? getReleaseRepositoryUrl() : getSnapshotRepositoryUrl()
99-
credentials {
100-
username = nexus_username
101-
password = nexus_password
102-
}
103-
}
104-
}
10587
}
10688

10789
signing {
108-
required { isReleaseBuild() }
90+
required { isReleaseBuild() && keyID }
10991
sign publishing.publications.release
11092
}
11193

112-
tasks.register('uploadArchives') {
113-
dependsOn publishReleasePublicationToOSSRHRepository
114-
}
115-
116-
tasks.register('androidSourcesJar', Jar) {
117-
archiveClassifier = 'sources'
118-
from android.sourceSets.main.java.sourceFiles
94+
nmcp {
95+
publishAllPublications {
96+
username = sonatype_username
97+
password = sonatype_password
98+
publicationType = "AUTOMATIC"
99+
}
119100
}
120-
121-
artifacts {
122-
archives androidSourcesJar
123-
}

0 commit comments

Comments
 (0)