diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..02ecbd1a45 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,27 @@ +on: + workflow_dispatch + +jobs: + publish: + name: Publish + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: temurin + cache: 'gradle' + - name: Change wrapper permission + run: chmod +x ./gradlew + + - name: Publish Maven + run: ./.github/workflows/scripts/publish-maven.sh + env: + NEXUS_USERNAME: ${{ secrets.SONATYPE_OSSRH_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.SONATYPE_OSSRH_PASSWORD }} + SIGNING_PRIVATE_KEY: ${{ secrets.PGP_PRIVATE_KEY }} + SIGNING_PASSWORD: ${{ secrets.PGP_PASSPHRASE }} diff --git a/.github/workflows/scripts/publish-maven.sh b/.github/workflows/scripts/publish-maven.sh new file mode 100755 index 0000000000..ec06a0cca5 --- /dev/null +++ b/.github/workflows/scripts/publish-maven.sh @@ -0,0 +1,9 @@ +set -x + +branch=$(git rev-parse --abbrev-ref HEAD) + +if [ "$branch" = "main" ] || [ "$branch" = "master" ]; then + ./gradlew :core:publishToSonatype closeAndReleaseSonatypeStagingRepository -PremoveSnapshotSuffix +else + ./gradlew :core:publishToSonatype +fi diff --git a/Jenkinsfile b/Jenkinsfile index c0d8ae698e..43e14857a3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -75,7 +75,6 @@ pipeline { // Do not deploy on PR builds expression { env.CHANGE_ID == null } anyOf { - expression { env.GIT_BRANCH == "master" } expression { env.GIT_BRANCH == "develop" } expression { env.GIT_BRANCH ==~ /[0-9]+\.[0-9]+\.[0-9]+-rc/ } } @@ -84,13 +83,10 @@ pipeline { environment { NEXUS_USERNAME = credentials('android-sonatype-nexus-username') NEXUS_PASSWORD = credentials('android-sonatype-nexus-password') - GPG_KEY_ID = credentials('android-sdk-signing-public-key-id') - GPG_PASSPHRASE = credentials('android-sdk-signing-private-key-password') - GPG_KEY_LOCATION = credentials('android-sdk-signing-private-key-ring-file') } steps { echo 'Deploy to Sonatype nexus' - sh './gradlew :core:publish' + sh './gradlew :core:publishToSonatype' } } } diff --git a/build.gradle.kts b/build.gradle.kts index 60d5c01dee..5c308b06ae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,16 @@ import org.jlleitschuh.gradle.ktlint.reporter.ReporterType +group = "org.hisp.dhis" +version = libs.versions.dhis2AndroidSdkVersion.get() + +/** + * Property from the Gradle command line. To remove the snapshot suffix from the version. + */ +if (project.hasProperty("removeSnapshotSuffix")) { + val mainVersion = (version as String).split("-SNAPSHOT")[0] + version = mainVersion +} + buildscript { repositories { google() @@ -18,6 +29,7 @@ buildscript { plugins { alias(libs.plugins.sonarqube) alias(libs.plugins.dokka) + alias(libs.plugins.nexus.publish) } sonarqube { @@ -61,9 +73,6 @@ subprojects { apply(plugin = "org.jlleitschuh.gradle.ktlint") apply(plugin = "org.jetbrains.dokka") - //group = GROUP - //version = VERSION_NAME - configure { version.set("0.50.0") android.set(true) @@ -73,4 +82,16 @@ subprojects { reporter(ReporterType.CHECKSTYLE) } } +} + +val nexusUsername: String? = System.getenv("NEXUS_USERNAME") +val nexusPassword: String? = System.getenv("NEXUS_PASSWORD") + +nexusPublishing { + this.repositories { + sonatype { + username.set(nexusUsername) + password.set(nexusPassword) + } + } } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Props.kt b/buildSrc/src/main/kotlin/Props.kt index fe472edfc6..7e47175ec2 100644 --- a/buildSrc/src/main/kotlin/Props.kt +++ b/buildSrc/src/main/kotlin/Props.kt @@ -27,18 +27,17 @@ */ object Props { - val GROUP = "org.hisp.dhis" - val POM_NAME = "Core" - val POM_ARTIFACT_ID = "android-core" - val POM_PACKAGING = "aar" - val POM_DESCRIPTION = "Android SDK for DHIS 2." - val POM_URL = "https://github.com/dhis2/dhis2-android-sdk" - val POM_SCM_URL = "https://github.com/dhis2/dhis2-android-sdk" - val POM_SCM_CONNECTION = "scm:git:git://github.com/dhis2/dhis2-android-sdk.git" - val POM_SCM_DEV_CONNECTION = "scm:git:ssh://git@github.com/dhis2/dhis2-android-sdk.git" - val POM_LICENCE_NAME = "BSD" - val POM_LICENCE_URL = "https://opensource.org/licenses/BSD-3-Clause" - val POM_LICENCE_DIST = "repo" - val POM_DEVELOPER_ID = "DHIS 2" - val POM_DEVELOPER_NAME = "DHIS 2" + const val POM_NAME = "Core" + const val POM_ARTIFACT_ID = "android-core" + const val POM_PACKAGING = "aar" + const val POM_DESCRIPTION = "Android SDK for DHIS 2." + const val POM_URL = "https://github.com/dhis2/dhis2-android-sdk" + const val POM_SCM_URL = "https://github.com/dhis2/dhis2-android-sdk" + const val POM_SCM_CONNECTION = "scm:git:git://github.com/dhis2/dhis2-android-sdk.git" + const val POM_SCM_DEV_CONNECTION = "scm:git:ssh://git@github.com/dhis2/dhis2-android-sdk.git" + const val POM_LICENCE_NAME = "BSD" + const val POM_LICENCE_URL = "https://opensource.org/licenses/BSD-3-Clause" + const val POM_LICENCE_DIST = "repo" + const val POM_DEVELOPER_ID = "DHIS 2" + const val POM_DEVELOPER_NAME = "DHIS 2" } diff --git a/buildSrc/src/main/kotlin/maven-publish-conventions.gradle.kts b/buildSrc/src/main/kotlin/maven-publish-conventions.gradle.kts index 3180cb0905..aeaa3f77e6 100644 --- a/buildSrc/src/main/kotlin/maven-publish-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/maven-publish-conventions.gradle.kts @@ -26,50 +26,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import java.net.URI - plugins { `maven-publish` signing } -val VERSION_NAME: String by project - fun isReleaseBuild(): Boolean { - return !VERSION_NAME.contains("SNAPSHOT") -} - -val releaseRepositoryUrl: String = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - -val snapshotRepositoryUrl: String = "https://oss.sonatype.org/content/repositories/snapshots/" - -fun getRepositoryUsername(): String? { - return System.getenv("NEXUS_USERNAME") + return !version.toString().endsWith("-SNAPSHOT") } -fun getRepositoryPassword(): String? { - return System.getenv("NEXUS_PASSWORD") -} - -fun gpgKeyId(): String? { - return System.getenv("GPG_KEY_ID") -} - -fun gpgKeyLocation(): String? { - return System.getenv("GPG_KEY_LOCATION") -} - -fun gpgPassphrase(): String? { - return System.getenv("GPG_PASSPHRASE") -} - -gradle.taskGraph.whenReady(closureOf { - if (gradle.taskGraph.allTasks.any { it is Sign }) { - allprojects { ext["signing.keyId"] = gpgKeyId() } - allprojects { ext["signing.secretKeyRingFile"] = gpgKeyLocation() } - allprojects { ext["signing.password"] = gpgPassphrase() } - } -}) +val signingPrivateKey: String? = System.getenv("SIGNING_PRIVATE_KEY") +val signingPassword: String? = System.getenv("SIGNING_PASSWORD") val androidJavadocsJar = tasks.register("androidJavadocsJar", Jar::class) { archiveClassifier.set("javadoc") @@ -85,9 +52,7 @@ afterEvaluate { from(components["release"]) artifact(androidJavadocsJar) - groupId = Props.GROUP artifactId = Props.POM_ARTIFACT_ID - version = VERSION_NAME pom { name = Props.POM_NAME @@ -114,22 +79,12 @@ afterEvaluate { } } } - - repositories { - maven { - url = if (isReleaseBuild()) URI(releaseRepositoryUrl) else URI(snapshotRepositoryUrl) - - credentials { - username = getRepositoryUsername() - password = getRepositoryPassword() - } - } - } } + } - signing { - setRequired({ isReleaseBuild() && gradle.taskGraph.hasTask("publishing") }) - sign(publishing.publications) - } + signing { + setRequired({ isReleaseBuild() && gradle.taskGraph.hasTask("publishing") }) + useInMemoryPgpKeys(signingPrivateKey, signingPassword) + sign(publishing.publications) } -} \ No newline at end of file +} diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 5628fd60b4..6fc0b7e1ba 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -44,8 +44,8 @@ repositories { maven(url = "https://oss.sonatype.org/content/repositories/snapshots") } -val VERSION_CODE: String by project -val VERSION_NAME: String by project +group = rootProject.group +version = rootProject.version android { compileSdk = libs.versions.targetSdkVersion.get().toInt() @@ -57,8 +57,8 @@ android { multiDexEnabled = true vectorDrawables.useSupportLibrary = true - buildConfigField("long", "VERSION_CODE", VERSION_CODE) - buildConfigField("String", "VERSION_NAME", "\"${VERSION_NAME}\"") + buildConfigField("long", "VERSION_CODE", libs.versions.dhis2AndroidSdkCode.get()) + buildConfigField("String", "VERSION_NAME", "\"$version\"") } compileOptions { diff --git a/core/gradle.properties b/core/gradle.properties deleted file mode 100644 index 9f9e03be39..0000000000 --- a/core/gradle.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2016, University of Oslo -# -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# Neither the name of the HISP project nor the names of its contributors may -# be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -# Properties which are consumed by plugins/gradle-mvn-push.gradle plugin. -# They are used for publishing artifact to snapshot repository. - -VERSION_NAME=1.10.0 -VERSION_CODE=292 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7f1ebb1edc..e2d9608e28 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,10 +1,14 @@ [versions] +dhis2AndroidSdkVersion = "1.10.0-SNAPSHOT" +dhis2AndroidSdkCode = "292" + gradle = "8.3.1" kotlin = "1.9.21" ktlint = "11.5.1" sonarqube = "3.3" detekt = "1.18.0" dokka = "1.9.20" +nexusPublish = "1.3.0" targetSdkVersion = "34" minSdkVersion = "21" @@ -125,5 +129,6 @@ facebook-soloader = { group = "com.facebook.soloader", name = "soloader", versio sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +nexus-publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexusPublish"} [bundles]