Appearance
2. Build System
2.1 Root build.gradle
groovy
plugins {
id 'java-library'
}
allprojects {
group = 'me.Maussee.AppelTools'
version = '2.0'
description = 'A plugin for managing AppelCraft'
ext.set("author", "Maussee")
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url 'https://repo.papermc.io/repository/maven-public/' }
maven { url 'https://repo.william278.net/velocity/' }
maven { url 'https://oss.sonatype.org/content/groups/public/' }
maven { url 'https://repo.panda-lang.org/releases' }
maven { url 'https://repo.papermc.io/repository/maven-snapshots/' }
maven { url 'https://repo.opencollab.dev/maven-snapshots/' }
}
}
subprojects {
apply plugin: 'java'
java { toolchain.languageVersion.set(JavaLanguageVersion.of(21)) }
dependencies {
compileOnly 'org.jetbrains:annotations:26.0.2'
compileOnly 'org.projectlombok:lombok:1.18.40'
annotationProcessor 'org.projectlombok:lombok:1.18.40'
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
test { useJUnitPlatform() }
}
tasks.register("deployDev") {
dependsOn ":common:clean", ":paper:clean", ":velocity:clean"
dependsOn ":common:build", ":paper:build", ":velocity:build"
dependsOn ":paper:uploadToDev", ":velocity:uploadToDev"
// force ordering: clean -> build -> upload
}
tasks.register("deployProd") {
dependsOn ":common:clean", ":paper:clean", ":velocity:clean"
dependsOn ":common:build", ":paper:build", ":velocity:build"
dependsOn ":paper:uploadToDev", ":velocity:uploadToDev"
dependsOn ":paper:uploadToProd", ":velocity:uploadToProd"
}2.2 settings.gradle
groovy
rootProject.name = 'AppelTools'
include 'common'
include 'velocity'
include 'paper'2.3 common/build.gradle
- Java 25 source/target; UTF-8 encoding.
- Gradle task
replaceTokenscopiessrc/main/javatobuild/filteredSrc, replacing@version@,@description@,@author@placeholders. compileJavareads frombuild/filteredSrc.- Dependencies: gson, guava, adventure, configurate, luckperms, mysql, hikari, slf4j, JDA — all
compileOnly. shadowJarproducesAppelTools-Common.jar(no classifier).builddepends onshadowJar.
groovy
import org.apache.tools.ant.filters.ReplaceTokens
import java.nio.charset.StandardCharsets
plugins {
id 'java-library'
id 'com.gradleup.shadow' version '9.3.2'
}
java { withSourcesJar() }
group = "${rootProject.group}.common"
version = rootProject.version
base { archivesName.set("${rootProject.name}-Common") }
tasks.register('replaceTokens', Copy) {
from("src/main/java") {
include "**/*.java"
filteringCharset = 'UTF-8'
filter(ReplaceTokens, tokens: [
'version' : project.version,
'description': project.description ?: "",
'author' : rootProject.ext.get("author").toString()
])
}
into "${layout.buildDirectory.get()}/filteredSrc"
}
compileJava {
dependsOn replaceTokens
source = fileTree("${layout.buildDirectory.get()}/filteredSrc")
options.encoding = StandardCharsets.UTF_8.name()
options.release.set(21)
}
dependencies {
compileOnly 'com.google.code.gson:gson:2.15.0'
implementation 'com.google.guava:guava:33.8.0-jre'
compileOnly 'net.kyori:adventure-api:4.26.1'
compileOnly 'net.kyori:adventure-text-minimessage:4.26.1'
compileOnly 'de.exlll:configlib-core:4.8.1'
compileOnly 'net.luckperms:api:5.5'
compileOnly 'com.mysql:mysql-connector-j:26.10.0'
compileOnly 'com.zaxxer:HikariCP:7.1.0'
compileOnly 'org.slf4j:slf4j-api:2.0.20'
compileOnly('net.dv8tion:JDA:6.7.0') { exclude module: 'opus-java'; exclude module: 'tink' }
testImplementation 'org.junit.jupiter:junit-jupiter:6.1.3'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testImplementation 'net.kyori:adventure-api:4.26.1'
testImplementation 'net.kyori:adventure-text-minimessage:4.26.1'
testImplementation 'de.exlll:configlib-core:4.8.1'
}
shadowJar { archiveClassifier.set('') }
build { dependsOn shadowJar }2.4 paper/build.gradle
- Depends on
:common. - Compile-only: paper-api 26.3.build.+, Vault, PremiumVanish, configurate, luckperms, JDA, logback.
- Implementation:
dev.rollczi:litecommands-bukkit:3.11.0. processResourcesexpands${version},${description},${author}inpaper-plugin.yml.shadowJarrelocatesdev.rollczi.litecommandstome.Maussee.AppelTools.libs.litecommandsand depends on:commonshadowJar.- Custom task
uploadToDevanduploadToProduse sshj to SFTP-upload the shadowJar to:appelcraft-hub,appelcraft-survival,appelcraft-devsurvival,appelcraft-devserver.
- Deploy properties:
appelcraft.deploy.host,appelcraft.deploy.port,appelcraft.deploy.password, plus per-server*.deploy.username.
groovy
import net.schmizz.sshj.SSHClient
import net.schmizz.sshj.sftp.SFTPClient
import net.schmizz.sshj.transport.verification.PromiscuousVerifier
import java.nio.charset.StandardCharsets
buildscript {
repositories { mavenCentral() }
dependencies { classpath 'com.hierynomus:sshj:0.40.0' }
}
plugins {
id 'java'
id 'com.gradleup.shadow' version '9.3.2'
}
group = "${rootProject.group}.paper"
version = rootProject.version
base { archivesName.set("${rootProject.name}-Paper") }
dependencies {
implementation project(':common')
compileOnly 'ch.qos.logback:logback-classic:1.6.6'
compileOnly 'io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT'
compileOnly('com.github.MilkBowl:VaultAPI:1.7') { exclude group: 'org.bukkit', module: 'bukkit' }
compileOnly 'com.github.LeonMangler:PremiumVanishAPI:2.9.18-2'
compileOnly 'de.exlll:configlib-core:4.8.1'
compileOnly 'net.luckperms:api:5.5'
compileOnly('net.dv8tion:JDA:6.7.0') { exclude module: 'opus-java'; exclude module: 'tink' }
implementation 'dev.rollczi:litecommands-bukkit:3.11.0'
testImplementation 'org.junit.jupiter:junit-jupiter:6.1.3'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks {
compileJava {
options.encoding = StandardCharsets.UTF_8.name()
options.release.set(21)
options.compilerArgs.add("-parameters")
}
processResources {
filesMatching("paper-plugin.yml") {
expand([
'version' : project.version,
'description': project.description ?: "",
'author' : rootProject.ext.get("author").toString()
])
}
}
shadowJar {
archiveClassifier.set('')
manifest { attributes 'Main-Class': "${rootProject.group}.paper.AppelToolsPaperLoader" }
relocate 'dev.rollczi.litecommands', "${rootProject.group}.libs.litecommands"
dependsOn project(':common').tasks.shadowJar
}
build { dependsOn shadowJar }
}
String deployHost = project.hasProperty('appelcraft.deploy.host') ? project['appelcraft.deploy.host'].toString() : ''
int deployPort = project.hasProperty('appelcraft.deploy.port') ? project['appelcraft.deploy.port'].toInteger() : 22
String deployPassword = project.hasProperty('appelcraft.deploy.password') ? project['appelcraft.deploy.password'].toString() : ''
def servers = ['appelcraft-hub', 'appelcraft-survival', 'appelcraft-devsurvival', 'appelcraft-devserver']
tasks.register("uploadToProd") {
dependsOn shadowJar
doLast {
servers.each { server ->
def localFile = file("${layout.buildDirectory.get()}/libs/${shadowJar.archiveFileName.get()}")
def remotePath = "/plugins/"
SSHClient ssh = new SSHClient()
ssh.addHostKeyVerifier(new PromiscuousVerifier())
ssh.connect(deployHost, deployPort)
ssh.authPassword(project["${server}.deploy.username"].toString(), deployPassword)
SFTPClient sftp = ssh.newSFTPClient()
sftp.put(localFile.absolutePath, remotePath + localFile.name)
sftp.close()
ssh.disconnect()
println "Uploaded successfully to ${server}"
}
}
}
tasks.register('uploadToDev') {
dependsOn shadowJar
doLast {
def localFile = file("${layout.buildDirectory.get()}/libs/${shadowJar.archiveFileName.get()}")
def remotePath = "/plugins/"
SSHClient ssh = new SSHClient()
ssh.addHostKeyVerifier(new PromiscuousVerifier())
ssh.connect(deployHost, deployPort)
ssh.authPassword(project["appelcraft-devserver.deploy.username"].toString(), deployPassword)
SFTPClient sftp = ssh.newSFTPClient()
sftp.put(localFile.absolutePath, remotePath + localFile.name)
sftp.close()
ssh.disconnect()
println "Uploaded successfully to appelcraft-devserver"
}
}2.5 velocity/build.gradle
- Depends on
:common. - Compile-only: velocity-api + velocity-proxy 4.2.0, luckperms, vPacketEvents, configurate.
- Implementation: mysql, hikari, litecommands-velocity, litecommands-jda, JDA, javax.annotation-api.
shadowJarrelocatescom.mysql,com.zaxxer.hikari,dev.rollczi.litecommands,net.dv8tion.jdato internal packages (to avoid conflicts on the proxy classpath).- Custom task
uploadToDevanduploadToProduse sshj to SFTP-upload the shadowJar to:appelcraft-proxy,appelcraft-devproxy.
groovy
import net.schmizz.sshj.SSHClient
import net.schmizz.sshj.sftp.SFTPClient
import net.schmizz.sshj.transport.verification.PromiscuousVerifier
import java.nio.charset.StandardCharsets
buildscript {
repositories { mavenCentral() }
dependencies { classpath 'com.hierynomus:sshj:0.40.0' }
}
plugins {
id 'java'
id 'com.gradleup.shadow' version '9.3.2'
}
group = "${rootProject.group}.velocity"
version = rootProject.version
base { archivesName.set("${rootProject.name}-Velocity") }
dependencies {
implementation project(':common')
compileOnly 'com.velocitypowered:velocity-api:4.2.0'
compileOnly 'com.velocitypowered:velocity-proxy:4.2.0'
annotationProcessor 'com.velocitypowered:velocity-api:4.2.0'
compileOnly 'net.luckperms:api:5.5'
compileOnly 'io.github.4drian3d:vpacketevents-api:1.2.0'
compileOnly 'de.exlll:configlib-core:4.8.1'
implementation 'javax.annotation:javax.annotation-api:1.3.2'
implementation 'com.mysql:mysql-connector-j:26.10.0'
implementation 'com.zaxxer:HikariCP:7.1.0'
implementation 'dev.rollczi:litecommands-velocity:3.11.0'
implementation 'dev.rollczi:litecommands-jda:3.11.0'
implementation('net.dv8tion:JDA:6.7.0') { exclude module: 'opus-java'; exclude module: 'tink' }
testImplementation 'org.junit.jupiter:junit-jupiter:6.1.3'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks {
compileJava {
options.encoding = StandardCharsets.UTF_8.name()
options.release.set(21)
options.compilerArgs.add("-parameters")
}
shadowJar {
archiveClassifier.set('')
manifest { attributes 'Main-Class': "${rootProject.group}.velocity.AppelToolsVelocity" }
relocate 'com.mysql', "${rootProject.group}.libs.mysql"
relocate 'com.zaxxer.hikari', "${rootProject.group}.libs.hikari"
relocate 'dev.rollczi.litecommands', "${rootProject.group}.libs.litecommands"
relocate 'net.dv8tion.jda', "${rootProject.group}.libs.jda"
dependsOn project(':common').tasks.shadowJar
}
build { dependsOn shadowJar }
}
String deployHost = project.hasProperty('appelcraft.deploy.host') ? project['appelcraft.deploy.host'].toString() : ''
int deployPort = project.hasProperty('appelcraft.deploy.port') ? project['appelcraft.deploy.port'].toInteger() : 22
String deployPassword = project.hasProperty('appelcraft.deploy.password') ? project['appelcraft.deploy.password'].toString() : ''
def servers = ['appelcraft-proxy', 'appelcraft-devproxy']
tasks.register("uploadToProd") { /* same shape as paper uploadToProd */ }
tasks.register('uploadToDev') { /* same shape, dev only */ }2.6 Build Commands
bash
./gradlew build # build all modules
./gradlew build -x test # skip tests
./gradlew test # run all tests
./gradlew test --tests "me.Maussee.AppelTools.common.Utils.TextUtilsTest"
./gradlew deployDev # clean, build, SFTP to dev servers
./gradlew deployProd # clean, build, SFTP to dev + prod2.7 Required Gradle Properties for Deploy
In ~/.gradle/gradle.properties or via -P flags:
appelcraft.deploy.host— SSH host.appelcraft.deploy.port— SSH port (default 22).appelcraft.deploy.password— SSH password.appelcraft-hub.deploy.username,appelcraft-survival.deploy.username,appelcraft-devsurvival.deploy.username,appelcraft-devserver.deploy.username(paper).appelcraft-proxy.deploy.username,appelcraft-devproxy.deploy.username(velocity).