Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions packages/kotlin-sdk/PUBLISHING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Publishing `org.dashj:dash-sdk-android` to Maven Central

The SDK publishes under the existing **`org.dashj`** namespace (same as
`dashj-core`), so no new Central namespace verification is needed. This is a
Maven-coordinates decision only — the Kotlin source packages remain
`org.dashfoundation.dashsdk`. Deployment uses **JReleaser**, mirroring
[dashj/core/build.gradle](https://github.com/dashpay/dashj/blob/master/core/build.gradle):
release versions go to Maven Central via the Central Portal; `-SNAPSHOT`
versions go to the Sonatype snapshots repository.

## Prerequisites

- **Sonatype Central Portal token** for the `org.dashj` namespace (held by
HashEngineering — the same account that publishes `dashj-core`).
- **GPG signing key** (the dashj release key works), with the public key on the
keyservers.
- **Native toolchain**: Android NDK r28+ (`28.1.13356709`), `cargo-ndk`, rustup
targets `aarch64-linux-android` and `x86_64-linux-android`, JDK 17.

## Credentials — environment only, never committed

Gradle signing (signs artifacts during the staging publish; the classic
`signing.keyId` / `signing.password` / `signing.secretKeyRingFile` entries in
`~/.gradle/gradle.properties`, as used for dashj-core, also work):

```bash
export ORG_GRADLE_PROJECT_signingKey="$(cat private-key.asc)" # ASCII-armored
export ORG_GRADLE_PROJECT_signingPassword="…"
```

JReleaser deploy (read only when a `jreleaser*` task runs):

```bash
export JRELEASER_MAVENCENTRAL_SONATYPE_USERNAME="…" # Central Portal token name
export JRELEASER_MAVENCENTRAL_SONATYPE_PASSWORD="…" # Central Portal token value
export JRELEASER_NEXUS2_SNAPSHOTS_USERNAME="…" # same token (snapshots repo)
export JRELEASER_NEXUS2_SNAPSHOTS_PASSWORD="…"
export JRELEASER_GPG_PUBLIC_KEY="$(cat public-key.asc)"
export JRELEASER_GPG_SECRET_KEY="$(cat private-key.asc)"
export JRELEASER_GPG_PASSPHRASE="…"
```

## Release steps (from `packages/kotlin-sdk/`)

```bash
# 1. Build the native JNI library (arm64-v8a + x86_64) and verify its exports.
./build_android.sh --verify

# 2. Stage the signed release AAR + sources/javadoc jars into sdk/build/staging-deploy.
./gradlew :sdk:publishReleasePublicationToStagingRepository -PsdkVersion=0.1.0
# (the staging dir sdk/build/staging-deploy is wiped automatically before every
# staging publish — cleanStagingDeploy — so stale versions from earlier runs
# can never reach JReleaser)

# 3. Upload the staged artifacts. Release versions -> Maven Central;
# -SNAPSHOT versions -> Sonatype snapshots.
./gradlew :sdk:jreleaserDeploy -PsdkVersion=0.1.0
Comment on lines +49 to +57

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Clean the staging repository before assembling a release

The runbook publishes each requested version into the fixed sdk/build/staging-deploy Maven repository and then gives that entire directory to both configured JReleaser deployers. Maven publication adds or replaces files for the current coordinates but does not remove other version directories, and JReleaser explicitly recommends deploying from a clean state. Reusing this sequence after an earlier snapshot or release staging run can therefore bundle stale versions with the intended release, causing duplicate-version or validation failures and potentially uploading unintended artifacts. Run :sdk:clean before staging; it removes the configured build directory while preserving the JNI libraries under src/main/jniLibs.

Suggested change
# 2. Stage the signed release AAR + sources/javadoc jars into sdk/build/staging-deploy.
./gradlew :sdk:publishReleasePublicationToStagingRepository -PsdkVersion=0.1.0
# 3. Upload the staged artifacts. Release versions -> Maven Central;
# -SNAPSHOT versions -> Sonatype snapshots.
./gradlew :sdk:jreleaserDeploy -PsdkVersion=0.1.0
# 2. Clear previously staged versions, then stage the signed release AAR + sources/javadoc jars.
./gradlew :sdk:clean
./gradlew :sdk:publishReleasePublicationToStagingRepository -PsdkVersion=0.1.0
# 3. Upload the staged artifacts. Release versions -> Maven Central;
# -SNAPSHOT versions -> Sonatype snapshots.
./gradlew :sdk:jreleaserDeploy -PsdkVersion=0.1.0

source: ['codex']

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest push: a cleanStagingDeploy Delete task now wipes sdk/build/staging-deploy before every *ToStagingRepository publish (wired via tasks.withType<PublishToMavenRepository>), so JReleaser always deploys from a clean staging state regardless of prior snapshot/release runs. Verified in the task graph with --dry-run; PUBLISHING.md updated to note the automatic wipe.

```

Then approve/verify the deployment at <https://central.sonatype.com> and
confirm the artifact appears on search.maven.org (sync takes ~30 min).

**Versioning:** the default is `0.1.0-SNAPSHOT`; pass the same
`-PsdkVersion=x.y.z` to steps 2 and 3. The first release should be a real
version (e.g. `0.1.0`) — the Android wallet's CI must depend on a pinned
release, never a snapshot.

## The JNI guard

`sdk/src/main/jniLibs/` is gitignored, so a clean checkout has no
`libdash_sdk_jni.so` — and an AAR published without it installs fine but dies
at runtime with `UnsatisfiedLinkError`. The `verifyJniLibsForRemotePublish`
task therefore **hard-fails** every staging/remote/jreleaser publish task when
the `.so` is missing for `arm64-v8a` or `x86_64`. There is no override for
remote publishes; `-PallowMissingJni` only downgrades the check for
`publishToMavenLocal` (metadata-only dry runs into `~/.m2`). If the guard
fires, run step 1.

## Consuming the artifact

```kotlin
repositories { mavenCentral() }
dependencies { implementation("org.dashj:dash-sdk-android:0.1.0") }
```

Requires `minSdk 29`. The AAR bundles the native library for `arm64-v8a` and
`x86_64`; `armeabi-v7a` is intentionally unsupported.
2 changes: 2 additions & 0 deletions packages/kotlin-sdk/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ androidxTestExtJunit = "1.2.1"
androidxTestRunner = "1.6.2"
espresso = "3.6.1"
robolectric = "4.14.1"
jreleaser = "1.17.0"

[libraries]
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" }
Expand Down Expand Up @@ -66,3 +67,4 @@ kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
jreleaser = { id = "org.jreleaser", version.ref = "jreleaser" }
261 changes: 260 additions & 1 deletion packages/kotlin-sdk/sdk/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
import java.util.concurrent.Callable
import org.gradle.api.publish.maven.tasks.PublishToMavenLocal
import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
import org.jreleaser.model.Active

plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp)
`maven-publish`
id("signing")
alias(libs.plugins.jreleaser)
}

// Published Maven coordinate group. Per HashEngineering's call on PR #4045:
// publish under the existing `org.dashj` group — Dash already owns dashj.org and
// ships its legacy Core/Platform SDKs there, so this needs no separate domain
// verification for Maven Central (`org.dashfoundation` would have, since
// dashfoundation.org is held by a third party). The Kotlin source packages stay
// `org.dashfoundation.dashsdk`; this is a Maven-coordinates decision only.
// `maven-publish` handles local / internal-repo publishing; jreleaser (bottom of
// file) handles Maven Central releases and Sonatype SNAPSHOTs, mirroring
// dashj/core/build.gradle.
group = "org.dashj"
version = project.findProperty("sdkVersion")?.toString() ?: "0.1.0-SNAPSHOT"

android {
namespace = "org.dashfoundation.dashsdk"
compileSdk = 35
Expand Down Expand Up @@ -35,6 +55,18 @@ android {
// libdash_sdk_jni.so is produced by ../build_android.sh (cargo-ndk) into
// src/main/jniLibs/<abi>/ — AGP packages it from there. NDK r28 emits
// 16 KB-aligned ELF segments by default (Android 15+ requirement).
publishing {
singleVariant("release") {
withSourcesJar()
// Maven Central's Publisher Portal rejects any non-POM component that
// lacks a javadoc jar, and the snapshot deployer sets
// applyMavenCentralRules(true) which enforces it before upload
// (dashpay/platform#4045). AGP emits a (Kotlin-appropriate) javadoc jar
// here — no Dokka dependency required.
withJavadocJar()
Comment on lines +61 to +66

@thepastaclaw thepastaclaw Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Generated javadoc jar will be effectively empty — comment overstates what AGP produces

The module (packages/kotlin-sdk/sdk/src/main) contains zero .java source files — confirmed by search, it is pure Kotlin. AGP’s withJavadocJar() wires up the standard Javadoc Gradle task, which only processes Java sources; it does not understand Kotlin and will not document any of the SDK’s public Kotlin API. The comment at lines 64-65 (“AGP emits a (Kotlin-appropriate) javadoc jar here — no Dokka dependency required”) overstates this: the produced jar satisfies Central’s structural requirement (a -javadoc.jar artifact must exist) but contains no meaningful API documentation. This does not block a real Central upload because only artifact presence is validated, not content — flagging as a comment-accuracy nitpick in case real API docs via Dokka are wanted later.

source: [sonnet5-general]

}
}
Comment on lines +58 to +68

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Release publication is missing a javadoc jar — real Maven Central deploys will be rejected

This delta turns on a real Maven Central / Sonatype deploy path (jreleaser { deploy { maven { mavenCentral { ... } nexus2 { ... } } } }, lines 245-273), meaning :sdk:jreleaserDeploy is now expected to actually push release and snapshot artifacts to Central. android.publishing.singleVariant("release") (lines 58-62) only calls withSourcesJar() — it never calls withJavadocJar(). Central's Publisher Portal requires a javadoc jar alongside the sources jar for every non-POM component (https://central.sonatype.org/publish/requirements/), and the snapshot deployer even sets applyMavenCentralRules(true) (line 263), which makes JReleaser enforce that rule before upload. The gap in singleVariant predates this commit, but it was inert until this delta made the deploy path real — publishToMavenLocal never exercises it, so this wasn't caught by local verification. Without this, the first real release or snapshot deploy fails validation.

Suggested change
publishing {
singleVariant("release") {
withSourcesJar()
}
}
publishing {
singleVariant("release") {
withSourcesJar()
withJavadocJar()
}
}

source: ['sonnet5', 'codex']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in fcaa91fRelease publication is missing a javadoc jar — real Maven Central deploys will be rejected no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.


packaging {
jniLibs {
useLegacyPackaging = false
Expand All @@ -59,7 +91,11 @@ ksp {
}

dependencies {
implementation(libs.kotlinx.coroutines.core)
// `api`, not `implementation`: the public SDK surface returns coroutines
// types (Room DAO `Flow<…>`, `PlatformWalletManager.pendingIdentityKeys:
// StateFlow<…>`, etc.), so a consumer of the published coordinate needs
// coroutines-core on its own compile classpath.
api(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.serialization.json)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: kotlinx-serialization-json is runtime-only despite a public @serializable type

kotlinx-serialization-json is declared with implementation, so it won't be on the compile classpath of consumers pulling the new Maven coordinate. Sdk.MasternodeEntry (Sdk.kt:127-133) is a public, default-visibility data class annotated @Serializable, so the serialization compiler plugin generates a public serializer(): KSerializer<MasternodeEntry> on it — a consumer calling that would fail to compile without kotlinx-serialization-core on their classpath. That said, this is narrower than the coroutines-core issue: MasternodeEntry is never returned by any public function — only internal fun parseActiveMasternodes and a private envelope class touch it, and the actually-public discoverActiveMasternodes() return type (ActiveMasternode) isn't @Serializable. A typical consumer is very unlikely to hit this. The cleaner fix may be marking MasternodeEntry internal (it reads like a wire-format DTO that leaked to public visibility) rather than promoting the dependency to api.

Suggested change
implementation(libs.kotlinx.serialization.json)
api(libs.kotlinx.serialization.json)

source: ['codex']

@thepastaclaw thepastaclaw Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in fcaa91fkotlinx-serialization-json is runtime-only despite a public @serializable type no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.


Expand All @@ -83,3 +119,226 @@ dependencies {
androidTestImplementation(libs.espresso.core)
androidTestImplementation(libs.room.testing)
}

// Publishes the release AAR (incl. libdash_sdk_jni.so if ../build_android.sh ran first) with a
// POM carrying the Room/DataStore/Biometric api dependencies.
// Local: ./gradlew :sdk:publishToMavenLocal Coordinates: org.dashj:dash-sdk-android:<version>
// Remote: `:sdk:publishReleasePublicationToStagingRepository` stages the signed
// artifacts into build/staging-deploy, then `:sdk:jreleaserDeploy` uploads
// them to Maven Central (release) / Sonatype snapshots (see jreleaser block).
// Override the version with -PsdkVersion=x.y.z (defaults to 0.1.0-SNAPSHOT).
afterEvaluate {
publishing {
repositories {
// Local staging dir that jreleaser reads from and uploads (below); it is
// not itself a network repo, so staging never needs credentials.
maven {
name = "staging"
url = uri(layout.buildDirectory.dir("staging-deploy"))
}
}

// The staging dir is reused across runs and maven-publish never removes
// other versions' directories — a release deploy after an earlier
// snapshot/release staging run would hand JReleaser stale coordinates.
// Wipe it before every staging publish so each deploy starts clean.
val cleanStagingDeploy = tasks.register<Delete>("cleanStagingDeploy") {
delete(layout.buildDirectory.dir("staging-deploy"))
}
tasks.withType<PublishToMavenRepository>().configureEach {
if (name.endsWith("ToStagingRepository")) {
dependsOn(cleanStagingDeploy)
}
}
publications {
create<MavenPublication>("release") {
from(components["release"])
Comment on lines +154 to +155

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Publishing can create an AAR without the JNI library

The release publication is created directly from the Android release component, but there is no Gradle task dependency or validation that builds sdk/src/main/jniLibs/<abi>/libdash_sdk_jni.so first. That directory is gitignored and absent in a clean checkout; the repo docs and build script show it is produced only by packages/kotlin-sdk/build_android.sh. Because NativeLoader.ensureLoaded() calls System.loadLibrary("dash_sdk_jni"), publishing from a clean tree can produce a Maven coordinate that installs successfully but fails at runtime with UnsatisfiedLinkError. The publish path should either depend on the native build or fail fast when the expected ABI libraries are missing.

source: ['codex']

@HashEngineering HashEngineering Jul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, we will need to integrate building of the JNI libs into the gradle build system. It can be done by running the build_android.sh script from the grade script or using CMake. There could be other better ways.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in 3d05a4fPublishing can create an AAR without the JNI library no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

groupId = "org.dashj"
artifactId = "dash-sdk-android"
pom {
name.set("Dash Platform Kotlin SDK")
description.set(
"Kotlin SDK for Dash Core (L1 SPV) and Dash Platform " +
"(identities, DPNS, DashPay, shielded balances)"
)
url.set("https://github.com/dashpay/platform")
licenses {
license {
name.set("MIT License")
url.set("https://github.com/dashpay/platform/blob/master/LICENSE")
}
}
// scm + developers: required by Maven Central (and most
// remote repos) for POM validation. Pointed at the GitHub repo.
scm {
url.set("https://github.com/dashpay/platform")
connection.set("scm:git:git://github.com/dashpay/platform.git")
developerConnection.set(
"scm:git:ssh://git@github.com/dashpay/platform.git"
)
}
developers {
developer {
id.set("dashpay")
name.set("Dash Platform Contributors")
url.set("https://github.com/dashpay/platform")
}
}
}
}
}
}

// Sign published artifacts, but only for a real remote publish. `publishToMavenLocal`
// and a bare `assemble` never put a PublishToMavenRepository task in the graph, so a
// local build requires no GPG key. Keys come from the standard signing properties/env
// (signing.keyId + signing.password + signing.secretKeyRingFile, or the in-memory
// ORG_GRADLE_PROJECT_signingKey / signingPassword pair) when a remote publish runs.
signing {
// Wire the documented in-memory-key path: the ORG_GRADLE_PROJECT_signingKey
// / signingPassword env vars land as the Gradle project properties
// `signingKey` / `signingPassword`, but the signing plugin does not consume
// them automatically — a CI release following that path would otherwise fail
// in signReleasePublication before staging anything (dashpay/platform#4045).
// Absent (local dev), this is skipped and, with required=false below, no key
// is needed. The legacy signing.keyId/password/secretKeyRingFile path is
// untouched and still handled by Gradle's standard signing properties.
val signingKey = project.findProperty("signingKey") as String?
val signingPassword = project.findProperty("signingPassword") as String?
if (!signingKey.isNullOrBlank()) {
useInMemoryPgpKeys(signingKey, signingPassword)
}
setRequired(Callable {
gradle.taskGraph.allTasks.any { it is PublishToMavenRepository }
})
sign(publishing.publications["release"])
}
Comment on lines +197 to +215

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Documented in-memory signing env vars are never wired to a signatory

The comment directly above this block (lines 173-177) says signing keys can come from either the legacy signing.keyId / signing.password / signing.secretKeyRingFile properties or the in-memory ORG_GRADLE_PROJECT_signingKey / signingPassword pair. The latter environment variables only populate Gradle project properties named signingKey and signingPassword; the signing plugin does not consume them automatically, and this block never calls useInMemoryPgpKeys. Therefore a CI release following the documented in-memory-key path fails in signReleasePublication before staging anything. Explicitly read those properties and pass them to useInMemoryPgpKeys(signingKey, signingPassword); the separate legacy keyring-file path can continue to use Gradle's standard signing properties.

Suggested change
signing {
setRequired(Callable {
gradle.taskGraph.allTasks.any { it is PublishToMavenRepository }
})
sign(publishing.publications["release"])
}
signing {
val signingKey = project.findProperty("signingKey") as String?
val signingPassword = project.findProperty("signingPassword") as String?
if (signingKey != null) {
useInMemoryPgpKeys(signingKey, signingPassword)
}
setRequired(Callable {
gradle.taskGraph.allTasks.any { it is PublishToMavenRepository }
})
sign(publishing.publications["release"])
}

source: ['codex']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in fcaa91fDocumented in-memory signing env vars are never wired to a signatory no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

}

// Never publish a coordinate whose AAR lacks the native JNI library
// (libdash_sdk_jni.so). ../build_android.sh (cargo-ndk) produces it into
// src/main/jniLibs/<abi>/; that directory is gitignored and absent in a clean
// checkout, so without this guard a publish from a fresh tree yields an artifact
// that installs cleanly but dies at runtime with UnsatisfiedLinkError
// (NativeLoader.ensureLoaded → System.loadLibrary("dash_sdk_jni")).
val requiredJniAbis = listOf("arm64-v8a", "x86_64") // build_android.sh ABI policy

fun missingJniAbis(): List<String> = requiredJniAbis.filterNot { abi ->
file("src/main/jniLibs/$abi/libdash_sdk_jni.so").isFile
}

fun jniMissingMessage(missing: List<String>): String =
"Native JNI library libdash_sdk_jni.so is missing for ABI(s) " +
"${missing.joinToString()} under src/main/jniLibs/ — run ./build_android.sh " +
"before publishing so the coordinate isn't broken at runtime."

// Remote / staging publish: ALWAYS hard-fail on a missing .so. `-PallowMissingJni`
// is deliberately NOT honored here — a nativeless AAR must never reach a network
// repo, nor jreleaser's build/staging-deploy dir (which `jreleaserDeploy` then
// uploads to Maven Central). This closes the escape where `-PallowMissingJni`
// previously downgraded the check to a warning for every publish task
// (dashpay/platform#4045, finding 8b899bc2e5e8).
val verifyJniLibsForRemotePublish = tasks.register("verifyJniLibsForRemotePublish") {
doLast {
val missing = missingJniAbis()
if (missing.isNotEmpty()) {
throw GradleException(
jniMissingMessage(missing) +
" -PallowMissingJni is a local-only escape and is NOT honored for " +
"remote/staging deploys."
)
}
}
}

// Local publish (`publishToMavenLocal`): a dev may pass `-PallowMissingJni` for a
// POM/metadata-only dry run into the local ~/.m2, which never leaves the machine.
val verifyJniLibsForLocalPublish = tasks.register("verifyJniLibsForLocalPublish") {
doLast {
val missing = missingJniAbis()
if (missing.isNotEmpty()) {
val message = jniMissingMessage(missing)
if (project.hasProperty("allowMissingJni")) {
logger.warn(
"WARNING: $message (continuing: -PallowMissingJni is set — local publish only.)"
)
} else {
throw GradleException("$message Pass -PallowMissingJni for a local-only dry run.")
}
}
}
}

tasks.withType<PublishToMavenRepository>().configureEach {
dependsOn(verifyJniLibsForRemotePublish)
}
tasks.withType<PublishToMavenLocal>().configureEach {
dependsOn(verifyJniLibsForLocalPublish)
}
// jreleaser's deploy/upload/release tasks push the already-staged artifacts, so
// gate them on the strict remote check too — a staging dir populated out-of-band
// (or by a future task rewiring) can't be uploaded without the native library.
tasks.matching { task ->
task.name.startsWith("jreleaser") &&
listOf("Deploy", "Upload", "Release").any { task.name.contains(it) }
}.configureEach { dependsOn(verifyJniLibsForRemotePublish) }

// Maven Central / Sonatype deployment via jreleaser, mirroring
// dashj/core/build.gradle (https://github.com/dashpay/dashj/blob/master/core/build.gradle#L139).
// Flow: `maven-publish` stages the signed artifacts into build/staging-deploy (the
// `staging` repository configured above), then `./gradlew :sdk:jreleaserDeploy`
// uploads them — release versions to Maven Central, -SNAPSHOT versions to the
// Sonatype snapshots repo. jreleaser reads its GPG key and Sonatype credentials
// from env/props (JRELEASER_GPG_*, JRELEASER_MAVENCENTRAL_*/JRELEASER_NEXUS2_*)
// at deploy time only, so `publishToMavenLocal` and any build that never invokes a
// jreleaser task need no signing key or account.
jreleaser {
project {
name.set("dash-sdk-android")
description.set(
"Kotlin SDK for Dash Core (L1 SPV) and Dash Platform " +
"(identities, DPNS, DashPay, shielded balances)"
)
links {
homepage.set("https://github.com/dashpay/platform")
}
authors.set(listOf("Dash Platform Contributors"))
license.set("MIT")
gitRootSearch.set(true)
}

signing {
active.set(Active.ALWAYS)
armored.set(true)
}

deploy {
maven {
// Tagged release versions -> Maven Central via the Sonatype portal.
mavenCentral {
create("sonatype") {
active.set(Active.RELEASE)
url.set("https://central.sonatype.com/api/v1/publisher")
stagingRepository(
layout.buildDirectory.dir("staging-deploy").get().asFile.path
)
}
}
// -SNAPSHOT versions -> Sonatype snapshots repository.
nexus2 {
create("snapshots") {
active.set(Active.SNAPSHOT)
url.set("https://central.sonatype.com/repository/maven-snapshots/")
snapshotUrl.set("https://central.sonatype.com/repository/maven-snapshots/")
applyMavenCentralRules.set(true)
snapshotSupported.set(true)
closeRepository.set(true)
releaseRepository.set(true)
stagingRepository(
layout.buildDirectory.dir("staging-deploy").get().asFile.path
)
}
}
}
}
}
Loading
Loading