diff --git a/backend-bukkit-api/build.gradle.kts b/backend-bukkit-api/build.gradle.kts deleted file mode 100644 index 50dbb26..0000000 --- a/backend-bukkit-api/build.gradle.kts +++ /dev/null @@ -1,77 +0,0 @@ -import java.io.DataInputStream -import java.util.jar.JarFile - -plugins { - `java-library` - `maven-publish` -} - -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(25)) - withSourcesJar() - withJavadocJar() -} - -tasks.withType().configureEach { - options.release.set(8) - options.encoding = "UTF-8" -} - -dependencies { - api(project(":messaging-api")) - // Consumers compile with their server API; the running server supplies Bukkit. - compileOnly("org.spigotmc:spigot-api:1.8-R0.1-SNAPSHOT") { isTransitive = false } -} - -val verifyApiJar = tasks.register("verifyApiJar") { - group = "verification" - dependsOn(tasks.jar) - val apiJar = tasks.jar.flatMap { it.archiveFile } - inputs.file(apiJar) - doLast { - JarFile(apiJar.get().asFile).use { archive -> - val entries = archive.entries().asSequence().toList() - val classes = entries.filter { it.name.endsWith(".class") } - check(classes.map { it.name }.toSet() == setOf( - "dev/moonbridge/bukkit/BackendPlayerSession.class", - "dev/moonbridge/bukkit/BukkitMessagingService.class", - "dev/moonbridge/bukkit/BukkitSessionService.class")) { - "Bukkit API artifact must contain only the public service contract" - } - check(entries.none { it.name == "plugin.yml" }) { "API is not a deployable plugin" } - classes.forEach { entry -> - DataInputStream(archive.getInputStream(entry)).use { input -> - input.readInt() - input.readUnsignedShort() - check(input.readUnsignedShort() == 52) { "Bukkit API must target Java 8" } - } - } - } - } -} - -tasks.named("check") { dependsOn(verifyApiJar) } - -publishing { - publications { - create("bukkitApi") { - from(components["java"]) - artifactId = "backend-bukkit-api" - pom { - name.set("MoonBridge Bukkit API") - description.set("Java 8 service contract for plugins using the shared MoonBridge backend host.") - } - } - } - repositories { - maven { - name = "giteaPackages" - url = uri(providers.environmentVariable("MAVEN_URL") - .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven").get()) - credentials { - username = providers.environmentVariable("MAVEN_USER").orElse("NONE").get() - password = providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() - } - } - } -} diff --git a/backend-bukkit/build.gradle.kts b/backend-bukkit/build.gradle.kts deleted file mode 100644 index c4354a4..0000000 --- a/backend-bukkit/build.gradle.kts +++ /dev/null @@ -1,102 +0,0 @@ -import java.io.DataInputStream -import java.util.jar.JarFile - -plugins { - `java-library` - `maven-publish` -} - -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(25)) - withSourcesJar() - withJavadocJar() -} - -tasks.withType().configureEach { - options.release.set(8) - options.encoding = "UTF-8" -} - -dependencies { - api(project(":backend-bukkit-api")) - implementation(project(":backend-channel-client")) - compileOnly("org.spigotmc:spigot-api:1.8-R0.1-SNAPSHOT") { isTransitive = false } - testImplementation("org.spigotmc:spigot-api:1.8-R0.1-SNAPSHOT") { isTransitive = false } - // Plugin's legacy API signature references Ebean; needed by the test proxy only. - testRuntimeOnly("org.avaje:ebean:2.8.1") { isTransitive = false } - testImplementation(platform("org.junit:junit-bom:5.14.1")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} - -tasks.withType().configureEach { useJUnitPlatform() } - -// One provider owns the API classes, codec and transport. Consumers use compileOnly -// and plugin.yml depend, so Bukkit resolves the same service class identity. -tasks.jar { - archiveBaseName.set("moonbridge-backend-bukkit") - dependsOn(configurations.runtimeClasspath) - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - from({ configurations.runtimeClasspath.get().filter { it.extension == "jar" }.map { zipTree(it) } }) - exclude("META-INF/*.SF", "META-INF/*.RSA", "META-INF/*.DSA") -} - -val verifyHostJar = tasks.register("verifyHostJar") { - group = "verification" - dependsOn(tasks.jar) - val hostJar = tasks.jar.flatMap { it.archiveFile } - inputs.file(hostJar) - doLast { - JarFile(hostJar.get().asFile).use { archive -> - val entries = archive.entries().asSequence().toList() - val names = entries.map { it.name } - listOf("plugin.yml", "config.yml", - "dev/moonbridge/bukkit/BukkitMessagingService.class", - "dev/moonbridge/bukkit/BukkitSessionService.class", - "dev/moonbridge/bukkit/BackendPlayerSession.class", - "dev/moonbridge/messaging/Message.class", - "dev/moonbridge/messaging/internal/LocalMessaging.class", - "dev/moonbridge/messaging/protocol/MessageCodec.class", - "dev/moonbridge/messaging/session/ForwardedSessionProof.class", - "dev/moonbridge/messaging/session/ForwardedSessionProof\$Claims.class", - "dev/moonbridge/backendchannel/BackendChannelClient.class", - "dev/moonbridge/backendchannel/Wire\$RegisteredIdentity.class").forEach { - check(names.count { name -> name == it } == 1) { "Host jar must contain exactly one $it" } - } - check(names.none { it.startsWith("org/bukkit/") }) { "Bukkit API must remain server-provided" } - entries.filter { it.name.endsWith(".class") }.forEach { entry -> - DataInputStream(archive.getInputStream(entry)).use { input -> - input.readInt() - input.readUnsignedShort() - check(input.readUnsignedShort() <= 52) { "Host class is newer than Java 8: ${entry.name}" } - } - } - } - } -} - -tasks.named("check") { dependsOn(verifyHostJar) } - -publishing { - publications { - create("bukkitHost") { - from(components["java"]) - artifactId = "backend-bukkit" - pom { - name.set("MoonBridge Backend Host") - description.set("Java 8 shared channel messaging service for Bukkit and Uranium plugins.") - } - } - } - repositories { - maven { - name = "giteaPackages" - url = uri(providers.environmentVariable("MAVEN_URL") - .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven").get()) - credentials { - username = providers.environmentVariable("MAVEN_USER").orElse("NONE").get() - password = providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() - } - } - } -} diff --git a/backend-channel-client/build.gradle.kts b/backend-channel-client/build.gradle.kts deleted file mode 100644 index 3f9ceac..0000000 --- a/backend-channel-client/build.gradle.kts +++ /dev/null @@ -1,51 +0,0 @@ -plugins { - `java-library` - `maven-publish` -} - -java { - withSourcesJar() - withJavadocJar() - toolchain.languageVersion.set(JavaLanguageVersion.of(25)) -} - -tasks.withType().configureEach { - options.release.set(8) - options.encoding = "UTF-8" -} - -tasks.withType().configureEach { - useJUnitPlatform() -} - -dependencies { - api(project(":messaging-api")) - api(project(":messaging-protocol")) - testImplementation(platform("org.junit:junit-bom:5.14.1")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} - -publishing { - publications { - create("backendChannelClient") { - from(components["java"]) - artifactId = "backend-channel-client" - pom { - name.set("MoonBridge Backend Channel Client") - description.set("Java 8-compatible backend control channel SDK.") - } - } - } - repositories { - maven { - name = "giteaPackages" - url = uri(providers.environmentVariable("MAVEN_URL") - .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven").get()) - credentials { - username = providers.environmentVariable("MAVEN_USER").orElse("NONE").get() - password = providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() - } - } - } -} diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts new file mode 100644 index 0000000..88bfb73 --- /dev/null +++ b/backend/build.gradle.kts @@ -0,0 +1,71 @@ +import java.io.DataInputStream +import java.util.jar.JarFile + +plugins { + id("moonbridge.java8-library-conventions") + id("moonbridge.publishing-conventions") +} + +val spigotApi = "org.spigotmc:spigot-api:1.8-R0.1-SNAPSHOT" + +dependencies { + api(project(":messaging")) + // The running server supplies Bukkit; business plugins compile against their own server API. + compileOnly(spigotApi) { isTransitive = false } + testImplementation(spigotApi) { isTransitive = false } + // Plugin's legacy API signature references Ebean; needed by the test proxy only. + testRuntimeOnly("org.avaje:ebean:2.8.1") { isTransitive = false } +} + +moonbridgePublication { + artifactId.set("backend") + displayName.set("MoonBridge Backend") + description.set("Java 8 backend side of MoonBridge: the shared Bukkit host plugin (MoonBridgeBackend), its " + + "service API and the control channel client for other hosts.") +} + +// The jar is the deployable Bukkit plugin and the one copy of the messaging classes on a server. +// Business plugins use it compileOnly plus plugin.yml depend, so Bukkit resolves one service class identity. +tasks.jar { + archiveBaseName.set("moonbridge-backend") + dependsOn(configurations.runtimeClasspath) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from({ configurations.runtimeClasspath.get().filter { it.extension == "jar" }.map { zipTree(it) } }) + exclude("META-INF/*.SF", "META-INF/*.RSA", "META-INF/*.DSA") +} + +val verifyBackendJar = tasks.register("verifyBackendJar") { + group = "verification" + dependsOn(tasks.jar) + val backendJar = tasks.jar.flatMap { it.archiveFile } + inputs.file(backendJar) + doLast { + JarFile(backendJar.get().asFile).use { archive -> + val entries = archive.entries().asSequence().toList() + val names = entries.map { it.name } + listOf("plugin.yml", "config.yml", + "dev/moonbridge/bukkit/BukkitMessagingService.class", + "dev/moonbridge/bukkit/BukkitSessionService.class", + "dev/moonbridge/bukkit/BackendPlayerSession.class", + "dev/moonbridge/messaging/Message.class", + "dev/moonbridge/messaging/internal/LocalMessaging.class", + "dev/moonbridge/messaging/protocol/MessageCodec.class", + "dev/moonbridge/messaging/session/ForwardedSessionProof.class", + "dev/moonbridge/messaging/session/ForwardedSessionProof\$Claims.class", + "dev/moonbridge/backendchannel/BackendChannelClient.class", + "dev/moonbridge/backendchannel/Wire\$RegisteredIdentity.class").forEach { + check(names.count { name -> name == it } == 1) { "Backend jar must contain exactly one $it" } + } + check(names.none { it.startsWith("org/bukkit/") }) { "Bukkit API must remain server-provided" } + entries.filter { it.name.endsWith(".class") }.forEach { entry -> + DataInputStream(archive.getInputStream(entry)).use { input -> + input.readInt() + input.readUnsignedShort() + check(input.readUnsignedShort() <= 52) { "Backend class is newer than Java 8: ${entry.name}" } + } + } + } + } +} + +tasks.named("check") { dependsOn(verifyBackendJar) } diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/BackendChannelClient.java b/backend/src/main/java/dev/moonbridge/backendchannel/BackendChannelClient.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/BackendChannelClient.java rename to backend/src/main/java/dev/moonbridge/backendchannel/BackendChannelClient.java diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/ClientSession.java b/backend/src/main/java/dev/moonbridge/backendchannel/ClientSession.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/ClientSession.java rename to backend/src/main/java/dev/moonbridge/backendchannel/ClientSession.java diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/Failures.java b/backend/src/main/java/dev/moonbridge/backendchannel/Failures.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/Failures.java rename to backend/src/main/java/dev/moonbridge/backendchannel/Failures.java diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/FrameCodec.java b/backend/src/main/java/dev/moonbridge/backendchannel/FrameCodec.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/FrameCodec.java rename to backend/src/main/java/dev/moonbridge/backendchannel/FrameCodec.java diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/InboundDispatcher.java b/backend/src/main/java/dev/moonbridge/backendchannel/InboundDispatcher.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/InboundDispatcher.java rename to backend/src/main/java/dev/moonbridge/backendchannel/InboundDispatcher.java diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/PendingOperation.java b/backend/src/main/java/dev/moonbridge/backendchannel/PendingOperation.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/PendingOperation.java rename to backend/src/main/java/dev/moonbridge/backendchannel/PendingOperation.java diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/Wire.java b/backend/src/main/java/dev/moonbridge/backendchannel/Wire.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/Wire.java rename to backend/src/main/java/dev/moonbridge/backendchannel/Wire.java diff --git a/backend-channel-client/src/main/java/dev/moonbridge/backendchannel/WriteTask.java b/backend/src/main/java/dev/moonbridge/backendchannel/WriteTask.java similarity index 100% rename from backend-channel-client/src/main/java/dev/moonbridge/backendchannel/WriteTask.java rename to backend/src/main/java/dev/moonbridge/backendchannel/WriteTask.java diff --git a/backend-bukkit-api/src/main/java/dev/moonbridge/bukkit/BackendPlayerSession.java b/backend/src/main/java/dev/moonbridge/bukkit/BackendPlayerSession.java similarity index 100% rename from backend-bukkit-api/src/main/java/dev/moonbridge/bukkit/BackendPlayerSession.java rename to backend/src/main/java/dev/moonbridge/bukkit/BackendPlayerSession.java diff --git a/backend-bukkit-api/src/main/java/dev/moonbridge/bukkit/BukkitMessagingService.java b/backend/src/main/java/dev/moonbridge/bukkit/BukkitMessagingService.java similarity index 100% rename from backend-bukkit-api/src/main/java/dev/moonbridge/bukkit/BukkitMessagingService.java rename to backend/src/main/java/dev/moonbridge/bukkit/BukkitMessagingService.java diff --git a/backend-bukkit-api/src/main/java/dev/moonbridge/bukkit/BukkitSessionService.java b/backend/src/main/java/dev/moonbridge/bukkit/BukkitSessionService.java similarity index 100% rename from backend-bukkit-api/src/main/java/dev/moonbridge/bukkit/BukkitSessionService.java rename to backend/src/main/java/dev/moonbridge/bukkit/BukkitSessionService.java diff --git a/backend-bukkit/src/main/java/dev/moonbridge/bukkit/MoonBridgeBackendPlugin.java b/backend/src/main/java/dev/moonbridge/bukkit/MoonBridgeBackendPlugin.java similarity index 100% rename from backend-bukkit/src/main/java/dev/moonbridge/bukkit/MoonBridgeBackendPlugin.java rename to backend/src/main/java/dev/moonbridge/bukkit/MoonBridgeBackendPlugin.java diff --git a/backend-bukkit/src/main/java/dev/moonbridge/bukkit/OwnedBukkitSessionService.java b/backend/src/main/java/dev/moonbridge/bukkit/OwnedBukkitSessionService.java similarity index 100% rename from backend-bukkit/src/main/java/dev/moonbridge/bukkit/OwnedBukkitSessionService.java rename to backend/src/main/java/dev/moonbridge/bukkit/OwnedBukkitSessionService.java diff --git a/backend-bukkit/src/main/java/dev/moonbridge/bukkit/OwnedMessagingService.java b/backend/src/main/java/dev/moonbridge/bukkit/OwnedMessagingService.java similarity index 100% rename from backend-bukkit/src/main/java/dev/moonbridge/bukkit/OwnedMessagingService.java rename to backend/src/main/java/dev/moonbridge/bukkit/OwnedMessagingService.java diff --git a/backend-bukkit/src/main/resources/config.yml b/backend/src/main/resources/config.yml similarity index 100% rename from backend-bukkit/src/main/resources/config.yml rename to backend/src/main/resources/config.yml diff --git a/backend-bukkit/src/main/resources/plugin.yml b/backend/src/main/resources/plugin.yml similarity index 100% rename from backend-bukkit/src/main/resources/plugin.yml rename to backend/src/main/resources/plugin.yml diff --git a/backend-channel-client/src/test/java/dev/moonbridge/backendchannel/BackendChannelClientTest.java b/backend/src/test/java/dev/moonbridge/backendchannel/BackendChannelClientTest.java similarity index 100% rename from backend-channel-client/src/test/java/dev/moonbridge/backendchannel/BackendChannelClientTest.java rename to backend/src/test/java/dev/moonbridge/backendchannel/BackendChannelClientTest.java diff --git a/backend-bukkit/src/test/java/dev/moonbridge/bukkit/OwnedBukkitSessionServiceTest.java b/backend/src/test/java/dev/moonbridge/bukkit/OwnedBukkitSessionServiceTest.java similarity index 100% rename from backend-bukkit/src/test/java/dev/moonbridge/bukkit/OwnedBukkitSessionServiceTest.java rename to backend/src/test/java/dev/moonbridge/bukkit/OwnedBukkitSessionServiceTest.java diff --git a/backend-bukkit/src/test/java/dev/moonbridge/bukkit/OwnedMessagingServiceTest.java b/backend/src/test/java/dev/moonbridge/bukkit/OwnedMessagingServiceTest.java similarity index 100% rename from backend-bukkit/src/test/java/dev/moonbridge/bukkit/OwnedMessagingServiceTest.java rename to backend/src/test/java/dev/moonbridge/bukkit/OwnedMessagingServiceTest.java diff --git a/build.gradle.kts b/build.gradle.kts index 0625ab6..062046e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,15 +10,17 @@ allprojects { version = releaseVersion } +val luckPerms = findProject(":luckperms-moonbridge") +val published = listOfNotNull(":proxy-plugin-api", ":messaging", ":backend", luckPerms?.path) + tasks.register("check") { group = "verification" - dependsOn(":proxy-plugin-api:check", ":messaging-api:check", ":messaging-protocol:check", - ":backend-channel-client:check", ":backend-bukkit-api:check", ":backend-bukkit:check", ":proxy-core:check", - ":luckperms-moonbridge:check") + description = "Runs every module's checks (add -Pluckperms to include the LuckPerms plugin)." + dependsOn(subprojects.map { "${it.path}:check" }) } tasks.register("publish") { group = "publishing" - dependsOn(":proxy-plugin-api:publish", ":messaging-api:publish", ":messaging-protocol:publish", - ":backend-channel-client:publish", ":backend-bukkit-api:publish", ":backend-bukkit:publish", ":luckperms-moonbridge:publish") + description = "Publishes the Maven modules (CI passes -Pluckperms so the LuckPerms plugin is included)." + dependsOn(published.map { "$it:publish" }) } diff --git a/luckperms-moonbridge/build.gradle.kts b/luckperms-moonbridge/build.gradle.kts index f1e51ef..cbcc9da 100644 --- a/luckperms-moonbridge/build.gradle.kts +++ b/luckperms-moonbridge/build.gradle.kts @@ -4,7 +4,7 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion plugins { id("moonbridge.java-library-conventions") id("com.gradleup.shadow") version "9.6.1" - `maven-publish` + id("moonbridge.publishing-conventions") } val hostBridgeCompileClasspath = configurations.create("hostBridgeCompileClasspath") { @@ -146,15 +146,4 @@ publishing { } } } - repositories { - maven { - name = "giteaPackages" - url = uri(providers.environmentVariable("MAVEN_URL") - .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven").get()) - credentials { - username = providers.environmentVariable("MAVEN_USER").orElse("NONE").get() - password = providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() - } - } - } } diff --git a/messaging-api/build.gradle.kts b/messaging-api/build.gradle.kts deleted file mode 100644 index 4dd3691..0000000 --- a/messaging-api/build.gradle.kts +++ /dev/null @@ -1,49 +0,0 @@ -plugins { - `java-library` - `maven-publish` -} - -java { - withSourcesJar() - withJavadocJar() - toolchain.languageVersion.set(JavaLanguageVersion.of(25)) -} - -tasks.withType().configureEach { - options.release.set(8) - options.encoding = "UTF-8" -} - -tasks.withType().configureEach { - useJUnitPlatform() -} - -dependencies { - testImplementation(platform("org.junit:junit-bom:5.14.1")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} - -publishing { - publications { - create("messagingApi") { - from(components["java"]) - artifactId = "messaging-api" - pom { - name.set("MoonBridge Messaging API") - description.set("Java 8-compatible shared message envelope and channel API.") - } - } - } - repositories { - maven { - name = "giteaPackages" - url = uri(providers.environmentVariable("MAVEN_URL") - .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven").get()) - credentials { - username = providers.environmentVariable("MAVEN_USER").orElse("NONE").get() - password = providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() - } - } - } -} diff --git a/messaging-protocol/build.gradle.kts b/messaging-protocol/build.gradle.kts deleted file mode 100644 index dc545a1..0000000 --- a/messaging-protocol/build.gradle.kts +++ /dev/null @@ -1,50 +0,0 @@ -plugins { - `java-library` - `maven-publish` -} - -java { - withSourcesJar() - withJavadocJar() - toolchain.languageVersion.set(JavaLanguageVersion.of(25)) -} - -tasks.withType().configureEach { - options.release.set(8) - options.encoding = "UTF-8" -} - -tasks.withType().configureEach { - useJUnitPlatform() -} - -dependencies { - api(project(":messaging-api")) - testImplementation(platform("org.junit:junit-bom:5.14.1")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} - -publishing { - publications { - create("messagingProtocol") { - from(components["java"]) - artifactId = "messaging-protocol" - pom { - name.set("MoonBridge Messaging Protocol") - description.set("Java 8-compatible message wire codec shared by proxy and backend clients.") - } - } - } - repositories { - maven { - name = "giteaPackages" - url = uri(providers.environmentVariable("MAVEN_URL") - .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven").get()) - credentials { - username = providers.environmentVariable("MAVEN_USER").orElse("NONE").get() - password = providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() - } - } - } -} diff --git a/messaging/build.gradle.kts b/messaging/build.gradle.kts new file mode 100644 index 0000000..76c7e25 --- /dev/null +++ b/messaging/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("moonbridge.java8-library-conventions") + id("moonbridge.publishing-conventions") +} + +moonbridgePublication { + artifactId.set("messaging") + displayName.set("MoonBridge Messaging") + description.set("Java 8-compatible message envelope, channel API and wire codec shared by the proxy and backends.") +} diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/Endpoint.java b/messaging/src/main/java/dev/moonbridge/messaging/Endpoint.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/Endpoint.java rename to messaging/src/main/java/dev/moonbridge/messaging/Endpoint.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/Message.java b/messaging/src/main/java/dev/moonbridge/messaging/Message.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/Message.java rename to messaging/src/main/java/dev/moonbridge/messaging/Message.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/MessageChannel.java b/messaging/src/main/java/dev/moonbridge/messaging/MessageChannel.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/MessageChannel.java rename to messaging/src/main/java/dev/moonbridge/messaging/MessageChannel.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/MessageHandler.java b/messaging/src/main/java/dev/moonbridge/messaging/MessageHandler.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/MessageHandler.java rename to messaging/src/main/java/dev/moonbridge/messaging/MessageHandler.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/MessageKind.java b/messaging/src/main/java/dev/moonbridge/messaging/MessageKind.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/MessageKind.java rename to messaging/src/main/java/dev/moonbridge/messaging/MessageKind.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/Messaging.java b/messaging/src/main/java/dev/moonbridge/messaging/Messaging.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/Messaging.java rename to messaging/src/main/java/dev/moonbridge/messaging/Messaging.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/MessagingException.java b/messaging/src/main/java/dev/moonbridge/messaging/MessagingException.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/MessagingException.java rename to messaging/src/main/java/dev/moonbridge/messaging/MessagingException.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/PublishResult.java b/messaging/src/main/java/dev/moonbridge/messaging/PublishResult.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/PublishResult.java rename to messaging/src/main/java/dev/moonbridge/messaging/PublishResult.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/SendReceipt.java b/messaging/src/main/java/dev/moonbridge/messaging/SendReceipt.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/SendReceipt.java rename to messaging/src/main/java/dev/moonbridge/messaging/SendReceipt.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/SendResult.java b/messaging/src/main/java/dev/moonbridge/messaging/SendResult.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/SendResult.java rename to messaging/src/main/java/dev/moonbridge/messaging/SendResult.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/Subscription.java b/messaging/src/main/java/dev/moonbridge/messaging/Subscription.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/Subscription.java rename to messaging/src/main/java/dev/moonbridge/messaging/Subscription.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/internal/LocalMessaging.java b/messaging/src/main/java/dev/moonbridge/messaging/internal/LocalMessaging.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/internal/LocalMessaging.java rename to messaging/src/main/java/dev/moonbridge/messaging/internal/LocalMessaging.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/internal/MessagingFailures.java b/messaging/src/main/java/dev/moonbridge/messaging/internal/MessagingFailures.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/internal/MessagingFailures.java rename to messaging/src/main/java/dev/moonbridge/messaging/internal/MessagingFailures.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/internal/Operation.java b/messaging/src/main/java/dev/moonbridge/messaging/internal/Operation.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/internal/Operation.java rename to messaging/src/main/java/dev/moonbridge/messaging/internal/Operation.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/internal/OperationHost.java b/messaging/src/main/java/dev/moonbridge/messaging/internal/OperationHost.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/internal/OperationHost.java rename to messaging/src/main/java/dev/moonbridge/messaging/internal/OperationHost.java diff --git a/messaging-protocol/src/main/java/dev/moonbridge/messaging/protocol/MessageCodec.java b/messaging/src/main/java/dev/moonbridge/messaging/protocol/MessageCodec.java similarity index 100% rename from messaging-protocol/src/main/java/dev/moonbridge/messaging/protocol/MessageCodec.java rename to messaging/src/main/java/dev/moonbridge/messaging/protocol/MessageCodec.java diff --git a/messaging-api/src/main/java/dev/moonbridge/messaging/session/ForwardedSessionProof.java b/messaging/src/main/java/dev/moonbridge/messaging/session/ForwardedSessionProof.java similarity index 100% rename from messaging-api/src/main/java/dev/moonbridge/messaging/session/ForwardedSessionProof.java rename to messaging/src/main/java/dev/moonbridge/messaging/session/ForwardedSessionProof.java diff --git a/messaging-api/src/test/java/dev/moonbridge/messaging/internal/LocalMessagingTest.java b/messaging/src/test/java/dev/moonbridge/messaging/internal/LocalMessagingTest.java similarity index 100% rename from messaging-api/src/test/java/dev/moonbridge/messaging/internal/LocalMessagingTest.java rename to messaging/src/test/java/dev/moonbridge/messaging/internal/LocalMessagingTest.java diff --git a/messaging-protocol/src/test/java/dev/moonbridge/messaging/protocol/MessageCodecTest.java b/messaging/src/test/java/dev/moonbridge/messaging/protocol/MessageCodecTest.java similarity index 100% rename from messaging-protocol/src/test/java/dev/moonbridge/messaging/protocol/MessageCodecTest.java rename to messaging/src/test/java/dev/moonbridge/messaging/protocol/MessageCodecTest.java diff --git a/messaging-api/src/test/java/dev/moonbridge/messaging/session/ForwardedSessionProofTest.java b/messaging/src/test/java/dev/moonbridge/messaging/session/ForwardedSessionProofTest.java similarity index 100% rename from messaging-api/src/test/java/dev/moonbridge/messaging/session/ForwardedSessionProofTest.java rename to messaging/src/test/java/dev/moonbridge/messaging/session/ForwardedSessionProofTest.java diff --git a/proxy-build-logic/build.gradle.kts b/proxy-build-logic/build.gradle.kts index dd9cd49..fda1796 100644 --- a/proxy-build-logic/build.gradle.kts +++ b/proxy-build-logic/build.gradle.kts @@ -8,6 +8,14 @@ gradlePlugin { id = "moonbridge.java-library-conventions" implementationClass = "MoonBridgeJavaLibraryConventionsPlugin" } + register("java8LibraryConventions") { + id = "moonbridge.java8-library-conventions" + implementationClass = "MoonBridgeJava8LibraryConventionsPlugin" + } + register("publishingConventions") { + id = "moonbridge.publishing-conventions" + implementationClass = "MoonBridgePublishingConventionsPlugin" + } register("applicationConventions") { id = "moonbridge.application-conventions" implementationClass = "MoonBridgeApplicationConventionsPlugin" diff --git a/proxy-build-logic/src/main/kotlin/MoonBridgeJava8LibraryConventionsPlugin.kt b/proxy-build-logic/src/main/kotlin/MoonBridgeJava8LibraryConventionsPlugin.kt new file mode 100644 index 0000000..8ec47b0 --- /dev/null +++ b/proxy-build-logic/src/main/kotlin/MoonBridgeJava8LibraryConventionsPlugin.kt @@ -0,0 +1,17 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.kotlin.dsl.withType + +/** Libraries loaded by Java 8 backends (Uranium and similar): compiled with --release 8. */ +class MoonBridgeJava8LibraryConventionsPlugin : Plugin { + override fun apply(project: Project) { + project.plugins.apply(MoonBridgeJavaLibraryConventionsPlugin::class.java) + project.tasks.withType().configureEach { + options.release.set(8) + options.encoding = "UTF-8" + // JDK 25 warns that --release 8 is obsolete; targeting Java 8 is the point of this convention. + options.compilerArgs.add("-Xlint:-options") + } + } +} diff --git a/proxy-build-logic/src/main/kotlin/MoonBridgePublishingConventionsPlugin.kt b/proxy-build-logic/src/main/kotlin/MoonBridgePublishingConventionsPlugin.kt new file mode 100644 index 0000000..9a72e7f --- /dev/null +++ b/proxy-build-logic/src/main/kotlin/MoonBridgePublishingConventionsPlugin.kt @@ -0,0 +1,56 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.provider.Property +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.publish.maven.plugins.MavenPublishPlugin +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.findByType + +/** Name and description of a module's standard Maven publication (its jar, sources and javadoc). */ +abstract class MoonBridgePublicationExtension { + abstract val artifactId: Property + abstract val displayName: Property + abstract val description: Property +} + +/** + * Adds the shared package repository. A module that sets `moonbridgePublication.artifactId` also gets the + * standard publication; a module with an unusual artifact (the LuckPerms plugin) declares its own instead. + */ +class MoonBridgePublishingConventionsPlugin : Plugin { + override fun apply(project: Project) { + project.plugins.apply(MavenPublishPlugin::class.java) + val publication = project.extensions.create("moonbridgePublication") + project.extensions.configure { + repositories.maven { + name = "giteaPackages" + url = project.uri(project.providers.environmentVariable("MAVEN_URL") + .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven").get()) + credentials { + username = project.providers.environmentVariable("MAVEN_USER").orElse("NONE").get() + password = project.providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() + } + } + } + project.afterEvaluate { + if (!publication.artifactId.isPresent) return@afterEvaluate + project.extensions.findByType()?.apply { + withSourcesJar() + withJavadocJar() + } + project.extensions.configure { + publications.create("maven") { + from(project.components.getByName("java")) + artifactId = publication.artifactId.get() + pom { + name.set(publication.displayName) + description.set(publication.description) + } + } + } + } + } +} diff --git a/proxy-core/build.gradle.kts b/proxy-core/build.gradle.kts index 36904ae..e2a7d18 100644 --- a/proxy-core/build.gradle.kts +++ b/proxy-core/build.gradle.kts @@ -7,7 +7,7 @@ plugins { val runtimeJavaHome = System.getProperty("java.home") dependencies { - implementation(project(":messaging-protocol")) + implementation(project(":messaging")) // The plugin contract is the only stable external boundary. Everything else // in this project remains an implementation package of the proxy core. api(project(":proxy-plugin-api")) @@ -32,7 +32,7 @@ dependencies { implementation(libs.findLibrary("adventure-gson").get()) implementation(libs.findLibrary("adventure-plain").get()) runtimeOnly(libs.findLibrary("logback-classic").get()) - testImplementation(project(":backend-channel-client")) + testImplementation(project(":backend")) testImplementation(libs.findLibrary("logback-classic").get()) testImplementation(libs.findLibrary("netty-pkitesting").get()) } @@ -86,13 +86,6 @@ val installedDistVersionSmokeTest = tasks.register("installedDistVersionSm } } -val compilePermissionAcceptance = tasks.register("compilePermissionAcceptance") { - source(rootProject.file("smoke/PermissionAcceptance.java")) - classpath = sourceSets.main.get().runtimeClasspath - destinationDirectory.set(layout.buildDirectory.dir("classes/permissionAcceptance")) - options.release.set(25) -} - // The benchmarks in benchmarks/ declare proxy-core packages to reach package-private classes and are // normally compiled by their PowerShell runners. Compiling them here keeps them building with main. val compileBenchmarks = tasks.register("compileBenchmarks") { @@ -104,21 +97,33 @@ val compileBenchmarks = tasks.register("compileBenchmarks") { options.release.set(25) } -val permissionAcceptance = tasks.register("permissionAcceptance") { - group = "verification" - description = "Loads the packaged LuckPerms plugin and verifies native permissions, commands and H2 persistence." - dependsOn(tasks.named("installDist"), compilePermissionAcceptance) - classpath = sourceSets.main.get().runtimeClasspath + files(compilePermissionAcceptance.flatMap { it.destinationDirectory }) - mainClass.set("PermissionAcceptance") - args(layout.buildDirectory.dir("install/moonbridge").get().asFile.absolutePath, - layout.buildDirectory.dir("permission-acceptance").get().asFile.absolutePath) +// permissionAcceptance needs the LuckPerms plugin, which is only built with -Pluckperms. +val luckPerms = rootProject.findProject(":luckperms-moonbridge") +if (luckPerms != null) { + val compilePermissionAcceptance = tasks.register("compilePermissionAcceptance") { + source(rootProject.file("smoke/PermissionAcceptance.java")) + classpath = sourceSets.main.get().runtimeClasspath + destinationDirectory.set(layout.buildDirectory.dir("classes/permissionAcceptance")) + options.release.set(25) + } + + val permissionAcceptance = tasks.register("permissionAcceptance") { + group = "verification" + description = "Loads the packaged LuckPerms plugin and verifies native permissions, commands and H2 persistence." + dependsOn(tasks.named("installDist"), compilePermissionAcceptance) + classpath = sourceSets.main.get().runtimeClasspath + files(compilePermissionAcceptance.flatMap { it.destinationDirectory }) + mainClass.set("PermissionAcceptance") + args(layout.buildDirectory.dir("install/moonbridge").get().asFile.absolutePath, + layout.buildDirectory.dir("permission-acceptance").get().asFile.absolutePath) + } + + tasks.named("check") { dependsOn(permissionAcceptance) } } tasks.named("check") { dependsOn(installedDistSmokeTest) dependsOn(installedDistHelpSmokeTest) dependsOn(installedDistVersionSmokeTest) - dependsOn(permissionAcceptance) dependsOn(compileBenchmarks) } @@ -147,8 +152,10 @@ distributions { main { contents { from(rootProject.file("README.md")) - from(project(":luckperms-moonbridge").tasks.named("pluginJar")) { - into("plugins") + if (luckPerms != null) { + from(luckPerms.tasks.named("pluginJar")) { + into("plugins") + } } from(rootProject.file("docs")) { into("docs") @@ -162,21 +169,8 @@ distributions { from("src/main/resources/config") { into("config") } - from(project(":backend-channel-client").tasks.named("jar")) { - into("backend-client") - } - from(project(":messaging-api").tasks.named("jar")) { - into("backend-client") - } - from(project(":messaging-protocol").tasks.named("jar")) { - into("backend-client") - } - from(project(":backend-bukkit").tasks.named("jar")) { - into("backend-host") - } - from(listOf(project(":backend-bukkit-api").tasks.named("jar"), - project(":messaging-api").tasks.named("jar"))) { - into("backend-api") + from(project(":backend").tasks.named("jar")) { + into("backend") } } } diff --git a/proxy-plugin-api/build.gradle.kts b/proxy-plugin-api/build.gradle.kts index 8578b31..0e39c02 100644 --- a/proxy-plugin-api/build.gradle.kts +++ b/proxy-plugin-api/build.gradle.kts @@ -1,41 +1,17 @@ plugins { id("moonbridge.java-library-conventions") - `maven-publish` + id("moonbridge.publishing-conventions") } dependencies { - api(project(":messaging-api")) + api(project(":messaging")) api(libs.findLibrary("slf4j-api").get()) api(libs.findLibrary("adventure-api").get()) api(libs.findLibrary("adventure-minimessage").get()) } -java { - withSourcesJar() - withJavadocJar() -} - -publishing { - publications { - create("pluginApi") { - from(components["java"]) - artifactId = "proxy-plugin-api" - pom { - name.set("MoonBridge Plugin API") - description.set("Stable API for MoonBridge proxy-side plugins.") - } - } - } - repositories { - maven { - name = "giteaPackages" - url = uri(providers.environmentVariable("MAVEN_URL") - .orElse("https://git.nest.potatolab.uk:8443/api/packages/layue13/maven") - .get()) - credentials { - username = providers.environmentVariable("MAVEN_USER").orElse("NONE").get() - password = providers.environmentVariable("MAVEN_PASSWORD").orElse("NONE").get() - } - } - } +moonbridgePublication { + artifactId.set("proxy-plugin-api") + displayName.set("MoonBridge Plugin API") + description.set("Stable API for MoonBridge proxy-side plugins.") } diff --git a/settings.gradle.kts b/settings.gradle.kts index 0c614e1..60e034a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,15 +27,19 @@ dependencyResolutionManagement { rootProject.name = "moonbridge" -includeBuild("luckperms-moonbridge/upstream-build") - include( "proxy-core", "proxy-plugin-api", - "backend-channel-client", - "messaging-api", - "messaging-protocol", - "backend-bukkit", - "backend-bukkit-api", - "luckperms-moonbridge", + "messaging", + "backend", ) + +// The LuckPerms platform plugin compiles LuckPerms itself from the vendor/luckperms submodule, which is +// slow and pulls a large dependency tree, so it is opt-in: pass -Pluckperms (CI and release builds do). +if (providers.gradleProperty("luckperms").map { it != "false" }.getOrElse(false)) { + check(file("vendor/luckperms/build.gradle").isFile) { + "-Pluckperms needs the LuckPerms sources: run git submodule update --init --recursive" + } + includeBuild("luckperms-moonbridge/upstream-build") + include("luckperms-moonbridge") +} diff --git a/smoke/backend-uranium.ps1 b/smoke/backend-uranium.ps1 index 045b317..a0866ec 100644 --- a/smoke/backend-uranium.ps1 +++ b/smoke/backend-uranium.ps1 @@ -16,8 +16,8 @@ if ($serverJars.Count -ne 1) { throw 'Expected exactly one Uranium server JAR.' $serverJar = $serverJars[0] $serverHash = (Get-FileHash -LiteralPath $serverJar.FullName -Algorithm SHA256).Hash $dist = Join-Path $repo 'proxy-core/build/install/moonbridge' -$hostJars = @(Get-ChildItem (Join-Path $dist 'backend-host') -Filter 'moonbridge-backend-bukkit-*.jar') -if ($hostJars.Count -ne 1) { throw 'Build the renamed host and installDist first.' } +$hostJars = @(Get-ChildItem (Join-Path $dist 'backend') -Filter 'moonbridge-backend-*.jar') +if ($hostJars.Count -ne 1) { throw 'Build the backend jar and installDist first.' } $run = Join-Path $repo ('build/backend-uranium-' + [guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Force $run | Out-Null Write-Output "ACCEPTANCE_DIRECTORY=$run" @@ -43,8 +43,8 @@ $probeClasses = Join-Path $run 'probe-classes' $proxyClasses = Join-Path $run 'proxy-classes' New-Item -ItemType Directory -Force $controlDir, $proxyPlugins, $probeClasses, $proxyClasses | Out-Null $proxyClasspath = Join-Path $dist 'lib/*' -# Business plugins compile against public API artifacts only, never the host/transport. -$backendApiClasspath = Join-Path $dist 'backend-api/*' +# Business plugins compile against the backend jar (compileOnly) and depend on MoonBridgeBackend at runtime. +$backendApiClasspath = Join-Path $dist 'backend/*' & (Join-Path $Java8Home 'bin/javac.exe') -cp "$backendApiClasspath;$BukkitApiJar" -d $probeClasses ` (Join-Path $PSScriptRoot 'BackendAcceptancePlugin.java') (Join-Path $PSScriptRoot 'BackendObserverPlugin.java') if ($LASTEXITCODE -ne 0) { throw 'Bukkit probe compilation failed.' }