From 0563193bf8f70db839c152bdfdec9189ef03ee24 Mon Sep 17 00:00:00 2001 From: Nek-12 Date: Fri, 5 Jul 2024 18:12:22 +0200 Subject: [PATCH] migrate to new sonatype publishing workflow --- .github/workflows/ci.yml | 5 - .github/workflows/docs.yml | 5 - .github/workflows/publish.yml | 18 ++-- buildSrc/src/main/kotlin/Config.kt | 1 + .../src/main/kotlin/ConfigurePublication.kt | 73 --------------- buildSrc/src/main/kotlin/PublishingExt.kt | 91 ------------------- buildSrc/src/main/kotlin/Util.kt | 10 +- .../pro.respawn.shared-library.gradle.kts | 3 - core/build.gradle.kts | 36 ++++++++ gradle/libs.versions.toml | 2 + 10 files changed, 53 insertions(+), 191 deletions(-) delete mode 100644 buildSrc/src/main/kotlin/ConfigurePublication.kt delete mode 100644 buildSrc/src/main/kotlin/PublishingExt.kt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6ea994..3b869f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,11 +20,6 @@ jobs: - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - - name: Create local properties - env: - LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }} - run: echo "$LOCAL_PROPERTIES" > local.properties - - name: set up JDK uses: actions/setup-java@v4 with: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9de1107..4af21fc 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -35,11 +35,6 @@ jobs: - name: Validate gradle wrapper uses: gradle/wrapper-validation-action@v3 - - name: Create local properties - env: - LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }} - run: echo "$LOCAL_PROPERTIES" > local.properties - - name: Update docs/README.md run: cp ./README.md ./docs/README.md diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5627ec6..4c12057 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,20 +41,14 @@ jobs: with: xcode-version: latest - - name: Create local properties - env: - LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }} - run: echo "$LOCAL_PROPERTIES" > local.properties - - name: Publish to sonatype env: - ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} - ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - # It's important to not upload in parallel or duplicate repos will be created - # repository creds are broken with gradle 8.6 https://github.com/gradle/gradle/issues/24040 - run: ./gradlew publishAllPublicationsToSonatypeRepository -Dorg.gradle.parallel=false --stacktrace --no-configuration-cache + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} + run: ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache - name: Generate Changelog uses: mikepenz/release-changelog-builder-action@v4 diff --git a/buildSrc/src/main/kotlin/Config.kt b/buildSrc/src/main/kotlin/Config.kt index 8114516..7193d04 100644 --- a/buildSrc/src/main/kotlin/Config.kt +++ b/buildSrc/src/main/kotlin/Config.kt @@ -24,6 +24,7 @@ object Config { const val licenseName = "The Apache Software License, Version 2.0" const val licenseUrl = "http://www.apache.org/licenses/LICENSE-2.0.txt" const val scmUrl = "https://github.com/respawn-app/ApiResult.git" + const val name = "ApiResult" const val description = """ ApiResult is a Kotlin Multiplatform declarative error handling framework that is performant, easy to use and feature-rich. diff --git a/buildSrc/src/main/kotlin/ConfigurePublication.kt b/buildSrc/src/main/kotlin/ConfigurePublication.kt deleted file mode 100644 index e364d4b..0000000 --- a/buildSrc/src/main/kotlin/ConfigurePublication.kt +++ /dev/null @@ -1,73 +0,0 @@ -@file:Suppress("MissingPackageDeclaration", "unused") - -import com.android.build.api.dsl.LibraryExtension -import com.android.build.gradle.tasks.BundleAar -import org.gradle.api.Project -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven -import org.gradle.kotlin.dsl.findByType -import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.maybeCreate -import org.gradle.kotlin.dsl.withType -import org.gradle.plugins.signing.Sign - -/** - * Configures Maven publishing to sonatype for this project - */ -fun Project.publishMultiplatform() { - val properties = localProperties() - val isReleaseBuild = properties["release"]?.toString().toBoolean() - val javadocTask = tasks.named("emptyJavadocJar") // TODO: dokka does not support kmp javadocs yet - - afterEvaluate { - requireNotNull(extensions.findByType()).apply { - publications.withType().configureEach { - groupId = rootProject.group.toString() - artifact(javadocTask) - configurePom() - configureVersion(isReleaseBuild) - } - sonatypeRepository(isReleaseBuild, properties) - } - signPublications(isReleaseBuild, properties) - } - - tasks.withType().configureEach { - dependsOn(javadocTask) - } -} - -/** - * Publish the android artifact - */ -fun Project.publishAndroid(ext: LibraryExtension) = with(ext) { - val properties = localProperties() - val isReleaseBuild = properties["release"]?.toString().toBoolean() - publishing { - singleVariant(Config.publishingVariant) { - withSourcesJar() - withJavadocJar() - } - } - - afterEvaluate { - requireNotNull(extensions.findByType()).apply { - publications.maybeCreate(Config.publishingVariant, MavenPublication::class).apply { - from(components[Config.publishingVariant]) - groupId = rootProject.group.toString() - configurePom() - configureVersion(isReleaseBuild) - } - sonatypeRepository(isReleaseBuild, properties) - } - signPublications(isReleaseBuild, properties) - } - - tasks.withType().configureEach { - dependsOn(tasks.withType()) - } - tasks.withType().configureEach { - dependsOn(tasks.withType()) - } -} diff --git a/buildSrc/src/main/kotlin/PublishingExt.kt b/buildSrc/src/main/kotlin/PublishingExt.kt deleted file mode 100644 index 7d2ce27..0000000 --- a/buildSrc/src/main/kotlin/PublishingExt.kt +++ /dev/null @@ -1,91 +0,0 @@ -@file:Suppress("MissingPackageDeclaration") - -import org.gradle.api.Project -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven -import org.gradle.kotlin.dsl.findByType -import org.gradle.kotlin.dsl.withType -import org.gradle.plugins.signing.Sign -import org.gradle.plugins.signing.SigningExtension -import java.net.URI -import java.util.Properties - -internal fun MavenPublication.configureVersion(release: Boolean) { - version = buildString { - append(Config.versionName) - if (!release) append("-SNAPSHOT") - } -} - -internal fun MavenPublication.configurePom() = pom { - name.set(Config.artifact) - description.set(Config.description) - url.set(Config.url) - - licenses { - license { - name.set(Config.licenseName) - url.set(Config.licenseUrl) - distribution.set("repo") - } - } - developers { - developer { - id.set(Config.vendorId) - name.set(Config.vendorName) - email.set(Config.supportEmail) - url.set(Config.developerUrl) - organization.set(Config.vendorName) - organizationUrl.set(url) - } - } - scm { - url.set(Config.scmUrl) - } -} - -internal fun PublishingExtension.sonatypeRepository(release: Boolean, localProps: Properties) = repositories { - val username = localProps["sonatypeUsername"]?.toString() ?: System.getenv("SONATYPE_USERNAME") - val password = localProps["sonatypePassword"]?.toString() ?: System.getenv("SONATYPE_PASSWORD") - maven { - name = "sonatype" - url = URI( - if (release) { - "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" - } else { - "https://s01.oss.sonatype.org/content/repositories/snapshots/" - } - ) - credentials { - this.username = username.takeIf { !it.isNullOrBlank() } - this.password = password.takeIf { !it.isNullOrBlank() } - } - } -} - -internal fun Project.signPublications(isRelease: Boolean, localProps: Properties) { - requireNotNull(extensions.findByType()).apply { - val publishing = requireNotNull(extensions.findByType()) - val signingKey: String? = localProps["signing.key"]?.toString() - val signingPassword: String? = localProps["signing.password"]?.toString() - - isRequired = isRelease - - if (signingKey != null && signingPassword != null) { - useInMemoryPgpKeys(signingKey, signingPassword) - } - - sign(publishing.publications) - - tasks.run { - withType().configureEach { - onlyIf { isRelease } - } - - withType().configureEach { - dependsOn(tasks.withType()) - } - } - } -} diff --git a/buildSrc/src/main/kotlin/Util.kt b/buildSrc/src/main/kotlin/Util.kt index 7461b4b..e187c6d 100644 --- a/buildSrc/src/main/kotlin/Util.kt +++ b/buildSrc/src/main/kotlin/Util.kt @@ -51,8 +51,9 @@ fun String.toBase64() = Base64.getEncoder().encodeToString(toByteArray()) fun Project.localProperties() = Properties().apply { val file = File(rootProject.rootDir.absolutePath, "local.properties") - require(file.exists()) { "Please create root local.properties file" } - load(FileInputStream(file)) + if (file.exists()) { + load(FileInputStream(file)) + } } fun stabilityLevel(version: String): Int { @@ -62,3 +63,8 @@ fun stabilityLevel(version: String): Int { } return Config.stabilityLevels.size } + +fun Config.version(isRelease: Boolean) = buildString { + append(versionName) + if (!isRelease) append("-SNAPSHOT") +} diff --git a/buildSrc/src/main/kotlin/pro.respawn.shared-library.gradle.kts b/buildSrc/src/main/kotlin/pro.respawn.shared-library.gradle.kts index c96562d..9beb915 100644 --- a/buildSrc/src/main/kotlin/pro.respawn.shared-library.gradle.kts +++ b/buildSrc/src/main/kotlin/pro.respawn.shared-library.gradle.kts @@ -5,7 +5,6 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi plugins { kotlin("multiplatform") id("com.android.library") - id("maven-publish") signing } @@ -17,5 +16,3 @@ kotlin { android { configureAndroidLibrary(this) } - -publishMultiplatform() diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ae669c9..315c34a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,8 @@ +import com.vanniktech.maven.publish.SonatypeHost + plugins { id("pro.respawn.shared-library") + alias(libs.plugins.maven.publish) } android { @@ -10,3 +13,36 @@ dependencies { commonMainApi(libs.kotlin.coroutines.core) jvmTestImplementation(libs.bundles.unittest) } + +mavenPublishing { + val properties = localProperties() + val isReleaseBuild = properties["release"]?.toString().toBoolean() + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL, false) + signAllPublications() + coordinates(Config.group, Config.artifact, Config.version(isReleaseBuild)) + pom { + name = Config.name + description = Config.description + url = Config.url + licenses { + license { + name = Config.licenseName + url = Config.licenseUrl + distribution = Config.licenseUrl + } + } + developers { + developer { + id = Config.vendorId + name = Config.vendorName + url = Config.developerUrl + email = Config.supportEmail + organizationUrl = Config.developerUrl + } + } + scm { + url = Config.scmUrl + } + + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea37256..17c7b98 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,7 @@ kotlinx-atomicfu = "0.23.1" lifecycle = "2.8.2" turbine = "1.0.0" versionCatalogUpdatePlugin = "0.8.4" +maven-publish-plugin = "0.29.0" [libraries] android-gradle = { module = "com.android.tools.build:gradle", version.ref = "gradleAndroid" } @@ -58,6 +59,7 @@ unittest = [ ] [plugins] +maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publish-plugin" } atomicfu = { id = "kotlinx-atomicfu", version.ref = "kotlinx-atomicfu" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } dependencyAnalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysisPlugin" }