Skip to content

Commit 0263f7f

Browse files
committed
build: extract publishing config into a build-logic convention plugin
Every publishable module repeated the same ~45-line maven-publish + signing + POM block, so any change to the Sonatype coordinates, license, SCM, or signing setup meant editing nine build scripts in lockstep. Introduce a `build-logic` included build with a single precompiled script plugin, `dexpace.published-module`, that owns the publication, POM metadata, staging repository, coordinates (group `org.dexpace`, version `0.0.1-alpha.1`), and the CI-gated in-memory signing configuration. Each of the nine modules now applies `id("dexpace.published-module")` and keeps only its module-specific dependencies and toolchain overrides; the POM name and description continue to derive from `project.name`, so no module needs any further publishing configuration. A module that should not be published simply does not apply the plugin. The generated POMs, Gradle module metadata, coordinates, artifacts, and signing behaviour are unchanged: the per-module POMs are byte-identical to those produced before the change, and `publishToMavenLocal` continues to skip signing when no PGP key is present (signing is required only under CI).
1 parent ea0cc81 commit 0263f7f

13 files changed

Lines changed: 148 additions & 469 deletions

File tree

build-logic/build.gradle.kts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2026 dexpace and Omar Aljarrah
3+
*
4+
* Licensed under the MIT License. See LICENSE in the project root.
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
// The `kotlin-dsl` plugin lets this build compile precompiled script plugins — every
9+
// `src/main/kotlin/*.gradle.kts` file becomes a plugin whose id is its file name minus the
10+
// `.gradle.kts` suffix (e.g. `dexpace.published-module`). Consumers in the main build apply
11+
// it by that id once `settings.gradle.kts` has `includeBuild("build-logic")` on the plugin
12+
// classpath.
13+
plugins {
14+
`kotlin-dsl`
15+
}
16+
17+
repositories {
18+
mavenCentral()
19+
gradlePluginPortal()
20+
}

build-logic/settings.gradle.kts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) 2026 dexpace and Omar Aljarrah
3+
*
4+
* Licensed under the MIT License. See LICENSE in the project root.
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
// Standalone settings for the `build-logic` included build. This build compiles the
9+
// repository's convention plugins (precompiled `*.gradle.kts` script plugins) so that the
10+
// production modules can apply them by id instead of duplicating configuration.
11+
//
12+
// `build-logic` deliberately depends on nothing from the version catalog: its sole convention
13+
// plugin wires the core `maven-publish` and `signing` plugins, which ship with Gradle itself
14+
// and therefore need no version. Keeping the included build catalog-free avoids extra
15+
// `dependencyResolutionManagement { versionCatalogs { ... } }` plumbing and the associated
16+
// classpath coupling between the main build and its own build logic.
17+
18+
rootProject.name = "build-logic"
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2026 dexpace and Omar Aljarrah
3+
*
4+
* Licensed under the MIT License. See LICENSE in the project root.
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
// Convention plugin for every module that is published to Maven Central. It carries the
9+
// `maven-publish` + `signing` setup, the shared POM metadata, the staging repository, and the
10+
// CI-gated signing configuration that was previously copied verbatim into all nine module
11+
// build scripts.
12+
//
13+
// A module opts in with `plugins { id("dexpace.published-module") }`. The publication name,
14+
// coordinates, POM, repository, and signing behaviour are then identical across modules; the
15+
// `name`/`description` fields derive from `project.name`, so a module needs no further
16+
// publishing configuration. A module that must NOT be published simply does not apply this
17+
// plugin.
18+
19+
plugins {
20+
`maven-publish`
21+
signing
22+
}
23+
24+
// Coordinates. The group and version are the same for every published module and match the
25+
// values declared on the root project; keeping the single literal here makes a coordinate
26+
// change a one-file edit instead of a nine-file edit.
27+
group = "org.dexpace"
28+
version = "0.0.1-alpha.1"
29+
30+
publishing {
31+
publications {
32+
create<MavenPublication>("library") {
33+
from(components["java"])
34+
pom {
35+
name.set(project.name)
36+
description.set("Dexpace Java SDK — ${project.name}")
37+
url.set("https://github.com/dexpace/java-sdk")
38+
licenses {
39+
license {
40+
name.set("MIT License")
41+
url.set("https://github.com/dexpace/java-sdk/blob/main/LICENSE")
42+
distribution.set("repo")
43+
}
44+
}
45+
developers {
46+
developer {
47+
id.set("dexpace")
48+
name.set("Dexpace SDK Team")
49+
}
50+
}
51+
scm {
52+
connection.set("scm:git:https://github.com/dexpace/java-sdk.git")
53+
developerConnection.set("scm:git:ssh://github.com/dexpace/java-sdk.git")
54+
url.set("https://github.com/dexpace/java-sdk")
55+
}
56+
}
57+
}
58+
}
59+
repositories {
60+
// Local staging repository. CI must override this to publish to a real remote.
61+
maven {
62+
name = "local"
63+
url = uri(rootProject.layout.buildDirectory.dir("staging-repo"))
64+
}
65+
}
66+
}
67+
68+
signing {
69+
isRequired = (System.getenv("CI") == "true")
70+
val signingKey = project.findProperty("signing.key") as String? ?: System.getenv("SIGNING_KEY")
71+
val signingPassword = project.findProperty("signing.password") as String? ?: System.getenv("SIGNING_PASSWORD")
72+
if (!signingKey.isNullOrBlank() && !signingPassword.isNullOrBlank()) {
73+
useInMemoryPgpKeys(signingKey, signingPassword)
74+
}
75+
sign(publishing.publications["library"])
76+
}

sdk-async-coroutines/build.gradle.kts

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@
88
plugins {
99
kotlin("jvm")
1010
id("org.jetbrains.kotlinx.kover")
11-
`maven-publish`
12-
signing
11+
// Publishing, signing, POM metadata, and coordinates come from this convention plugin
12+
// (build-logic/src/main/kotlin/dexpace.published-module.gradle.kts).
13+
id("dexpace.published-module")
1314
}
1415

15-
group = "org.dexpace"
16-
version = "0.0.1-alpha.1"
17-
1816
// Java 8 bytecode is inherited from the root build script — the module ships to JDK 8 consumers
1917
// just like `sdk-core` does.
2018

@@ -40,50 +38,3 @@ dependencies {
4038
tasks.test {
4139
useJUnitPlatform()
4240
}
43-
44-
publishing {
45-
publications {
46-
create<MavenPublication>("library") {
47-
from(components["java"])
48-
pom {
49-
name.set(project.name)
50-
description.set("Dexpace Java SDK — ${project.name}")
51-
url.set("https://github.com/dexpace/java-sdk")
52-
licenses {
53-
license {
54-
name.set("MIT License")
55-
url.set("https://github.com/dexpace/java-sdk/blob/main/LICENSE")
56-
distribution.set("repo")
57-
}
58-
}
59-
developers {
60-
developer {
61-
id.set("dexpace")
62-
name.set("Dexpace SDK Team")
63-
}
64-
}
65-
scm {
66-
connection.set("scm:git:https://github.com/dexpace/java-sdk.git")
67-
developerConnection.set("scm:git:ssh://github.com/dexpace/java-sdk.git")
68-
url.set("https://github.com/dexpace/java-sdk")
69-
}
70-
}
71-
}
72-
}
73-
repositories {
74-
maven {
75-
name = "local"
76-
url = uri(rootProject.layout.buildDirectory.dir("staging-repo"))
77-
}
78-
}
79-
}
80-
81-
signing {
82-
isRequired = (System.getenv("CI") == "true")
83-
val signingKey = project.findProperty("signing.key") as String? ?: System.getenv("SIGNING_KEY")
84-
val signingPassword = project.findProperty("signing.password") as String? ?: System.getenv("SIGNING_PASSWORD")
85-
if (!signingKey.isNullOrBlank() && !signingPassword.isNullOrBlank()) {
86-
useInMemoryPgpKeys(signingKey, signingPassword)
87-
}
88-
sign(publishing.publications["library"])
89-
}

sdk-async-netty/build.gradle.kts

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@
88
plugins {
99
kotlin("jvm")
1010
id("org.jetbrains.kotlinx.kover")
11-
`maven-publish`
12-
signing
11+
// Publishing, signing, POM metadata, and coordinates come from this convention plugin
12+
// (build-logic/src/main/kotlin/dexpace.published-module.gradle.kts).
13+
id("dexpace.published-module")
1314
}
1415

15-
group = "org.dexpace"
16-
version = "0.0.1-alpha.1"
17-
1816
dependencies {
1917
implementation(project(":sdk-core"))
2018
// `netty-common` carries `io.netty.util.concurrent.Future`/`Promise`/`EventExecutor` —
@@ -30,50 +28,3 @@ dependencies {
3028
tasks.test {
3129
useJUnitPlatform()
3230
}
33-
34-
publishing {
35-
publications {
36-
create<MavenPublication>("library") {
37-
from(components["java"])
38-
pom {
39-
name.set(project.name)
40-
description.set("Dexpace Java SDK — ${project.name}")
41-
url.set("https://github.com/dexpace/java-sdk")
42-
licenses {
43-
license {
44-
name.set("MIT License")
45-
url.set("https://github.com/dexpace/java-sdk/blob/main/LICENSE")
46-
distribution.set("repo")
47-
}
48-
}
49-
developers {
50-
developer {
51-
id.set("dexpace")
52-
name.set("Dexpace SDK Team")
53-
}
54-
}
55-
scm {
56-
connection.set("scm:git:https://github.com/dexpace/java-sdk.git")
57-
developerConnection.set("scm:git:ssh://github.com/dexpace/java-sdk.git")
58-
url.set("https://github.com/dexpace/java-sdk")
59-
}
60-
}
61-
}
62-
}
63-
repositories {
64-
maven {
65-
name = "local"
66-
url = uri(rootProject.layout.buildDirectory.dir("staging-repo"))
67-
}
68-
}
69-
}
70-
71-
signing {
72-
isRequired = (System.getenv("CI") == "true")
73-
val signingKey = project.findProperty("signing.key") as String? ?: System.getenv("SIGNING_KEY")
74-
val signingPassword = project.findProperty("signing.password") as String? ?: System.getenv("SIGNING_PASSWORD")
75-
if (!signingKey.isNullOrBlank() && !signingPassword.isNullOrBlank()) {
76-
useInMemoryPgpKeys(signingKey, signingPassword)
77-
}
78-
sign(publishing.publications["library"])
79-
}

sdk-async-reactor/build.gradle.kts

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@
88
plugins {
99
kotlin("jvm")
1010
id("org.jetbrains.kotlinx.kover")
11-
`maven-publish`
12-
signing
11+
// Publishing, signing, POM metadata, and coordinates come from this convention plugin
12+
// (build-logic/src/main/kotlin/dexpace.published-module.gradle.kts).
13+
id("dexpace.published-module")
1314
}
1415

15-
group = "org.dexpace"
16-
version = "0.0.1-alpha.1"
17-
1816
dependencies {
1917
implementation(project(":sdk-core"))
2018
// Reactor itself is Java 8 compatible and ships with `Mono.fromFuture(...)` / `Mono.toFuture()`
@@ -33,50 +31,3 @@ dependencies {
3331
tasks.test {
3432
useJUnitPlatform()
3533
}
36-
37-
publishing {
38-
publications {
39-
create<MavenPublication>("library") {
40-
from(components["java"])
41-
pom {
42-
name.set(project.name)
43-
description.set("Dexpace Java SDK — ${project.name}")
44-
url.set("https://github.com/dexpace/java-sdk")
45-
licenses {
46-
license {
47-
name.set("MIT License")
48-
url.set("https://github.com/dexpace/java-sdk/blob/main/LICENSE")
49-
distribution.set("repo")
50-
}
51-
}
52-
developers {
53-
developer {
54-
id.set("dexpace")
55-
name.set("Dexpace SDK Team")
56-
}
57-
}
58-
scm {
59-
connection.set("scm:git:https://github.com/dexpace/java-sdk.git")
60-
developerConnection.set("scm:git:ssh://github.com/dexpace/java-sdk.git")
61-
url.set("https://github.com/dexpace/java-sdk")
62-
}
63-
}
64-
}
65-
}
66-
repositories {
67-
maven {
68-
name = "local"
69-
url = uri(rootProject.layout.buildDirectory.dir("staging-repo"))
70-
}
71-
}
72-
}
73-
74-
signing {
75-
isRequired = (System.getenv("CI") == "true")
76-
val signingKey = project.findProperty("signing.key") as String? ?: System.getenv("SIGNING_KEY")
77-
val signingPassword = project.findProperty("signing.password") as String? ?: System.getenv("SIGNING_PASSWORD")
78-
if (!signingKey.isNullOrBlank() && !signingPassword.isNullOrBlank()) {
79-
useInMemoryPgpKeys(signingKey, signingPassword)
80-
}
81-
sign(publishing.publications["library"])
82-
}

sdk-async-virtualthreads/build.gradle.kts

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
1111
plugins {
1212
kotlin("jvm")
1313
id("org.jetbrains.kotlinx.kover")
14-
`maven-publish`
15-
signing
14+
// Publishing, signing, POM metadata, and coordinates come from this convention plugin
15+
// (build-logic/src/main/kotlin/dexpace.published-module.gradle.kts).
16+
id("dexpace.published-module")
1617
}
1718

18-
group = "org.dexpace"
19-
version = "0.0.1-alpha.1"
20-
2119
// Virtual threads require JDK 21+. The root build script applies Java 8 to every Kotlin
2220
// module; we override here. The output bytecode targets Java 21 — consumers MUST be on
2321
// JDK 21 or newer to depend on this module. Both Kotlin and Java compile tasks must agree
@@ -63,53 +61,6 @@ tasks.test {
6361
useJUnitPlatform()
6462
}
6563

66-
publishing {
67-
publications {
68-
create<MavenPublication>("library") {
69-
from(components["java"])
70-
pom {
71-
name.set(project.name)
72-
description.set("Dexpace Java SDK — ${project.name}")
73-
url.set("https://github.com/dexpace/java-sdk")
74-
licenses {
75-
license {
76-
name.set("MIT License")
77-
url.set("https://github.com/dexpace/java-sdk/blob/main/LICENSE")
78-
distribution.set("repo")
79-
}
80-
}
81-
developers {
82-
developer {
83-
id.set("dexpace")
84-
name.set("Dexpace SDK Team")
85-
}
86-
}
87-
scm {
88-
connection.set("scm:git:https://github.com/dexpace/java-sdk.git")
89-
developerConnection.set("scm:git:ssh://github.com/dexpace/java-sdk.git")
90-
url.set("https://github.com/dexpace/java-sdk")
91-
}
92-
}
93-
}
94-
}
95-
repositories {
96-
maven {
97-
name = "local"
98-
url = uri(rootProject.layout.buildDirectory.dir("staging-repo"))
99-
}
100-
}
101-
}
102-
103-
signing {
104-
isRequired = (System.getenv("CI") == "true")
105-
val signingKey = project.findProperty("signing.key") as String? ?: System.getenv("SIGNING_KEY")
106-
val signingPassword = project.findProperty("signing.password") as String? ?: System.getenv("SIGNING_PASSWORD")
107-
if (!signingKey.isNullOrBlank() && !signingPassword.isNullOrBlank()) {
108-
useInMemoryPgpKeys(signingKey, signingPassword)
109-
}
110-
sign(publishing.publications["library"])
111-
}
112-
11364
// Detekt analysis is disabled on this module because detekt 1.23.x (incl. 1.23.6 and 1.23.8)
11465
// embeds a Kotlin compiler whose `org.jetbrains.kotlin.com.intellij.util.lang.JavaVersion.parse`
11566
// throws `IllegalArgumentException: 25.0.2` when running on JDK 25+ — the system JDK on this

0 commit comments

Comments
 (0)