Skip to content
Merged
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
9 changes: 4 additions & 5 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Use `make verify` to validate the project
Use `make check` to validate the project

## Tech Stack
- Java 21, DropWizard (HTTP server), JDBI (no ORM), Postgres, Lombok
- Gradle build with shadow JAR as deployment artifact
- Java 21, Quarkus (HTTP server), JDBI (no ORM), Postgres, Lombok
- Quarkus fast-jar (`build/quarkus-app/`) as deployment artifact
- Docker + docker-compose for local dev and integration tests

## Testing
- `src/test/` — unit tests; no database or server required
- `src/testInteg/` — integration tests; require Docker (docker-compose spins up a live DB and server automatically via Gradle)
- `src/testInteg/` — integration tests; require Docker (`docker compose up database flyway` starts Postgres on port 5432; Quarkus starts in-process via `@QuarkusTest`)
- Do not put integration tests in `src/test/` or unit tests in `src/testInteg/`

## Code Style
Expand All @@ -17,5 +17,4 @@ Use `make verify` to validate the project

## Database
- No ORM — use JDBI with SQL object pattern
- Database migrations go in `database/migrations/` as Flyway `.sql` files
- Migration naming convention: `V{major}.{minor}.{patch}__description.sql`
11 changes: 8 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
FROM eclipse-temurin:21

EXPOSE 8080
ADD configuration.yml /
ADD build/libs/support-server.jar /
CMD java -jar support-server.jar server /configuration.yml

# Quarkus fast-jar layout: quarkus-run.jar delegates to lib/ and app/
COPY build/quarkus-app/lib/ /app/lib/
COPY build/quarkus-app/*.jar /app/
COPY build/quarkus-app/app/ /app/app/
COPY build/quarkus-app/quarkus/ /app/quarkus/

CMD java -jar /app/quarkus-run.jar
11 changes: 5 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ print-versions: ## Prints versions of system dependencies (EG: java, docker)
format: ## Runs formatting
./gradlew spotlessApply

test check: print-versions ## Runs all checks used to verify a Pull-Request
test check: ## Runs all checks used to verify a Pull-Request
./gradlew spotlessApply check

clean: ## Removes build artifacts and stops docker containers and removes docker volumes
Expand All @@ -34,21 +34,20 @@ database-up: ## Launches database
docker compose build flyway
DATABASE_PORT=5432 docker compose up database flyway

up: ## Build & run server, launches a docker database
docker compose build flyway
./gradlew composeUp
up: ## Build & run server in dev mode (Quarkus Dev Services starts Postgres automatically)
./gradlew quarkusDev

psql: ## Connects to locally running docker database
docker exec -u postgres -it support-server-database-1 psql support_db

logs: ## Util command to print the server logs
logs: ## Util command to print the server logs (when running via docker)
docker logs support-server-server-1

local: ## Uses 'triplea' game-client dependency as built from local disc, useful if working on shared libraries between 'support-server' and 'triplea'
./gradlew --info --include-build ../triplea compileJava

build:
./gradlew shadowJar
./gradlew quarkusBuild

docker-build: build ## Creates 'docker container' build artifacts
docker build database -f database/flyway.Dockerfile --tag ghcr.io/triplea-game/support-server/flyway:latest
Expand Down
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
## Tech Overview

- Java 21
- DropWizard (http server)
- Quarkus (http server)
- Junit5 (unit tests)
- assertj (unit tests)
- JDBI (no ORM, JDBI instead)
- Postgres (database layer)
- Docker & Docker Compose
- Docker & Docker Compose
- gradle (build tool)
- Makefile (developer build commands)

Expand All @@ -24,10 +24,22 @@ Warning: First make sure that the local triplea project can build cleanly.

### Integration Tests

These are tests that run against a live database & server running on locally.
The server & database are set up with docker-compose.
First we build a shadow jar, then we use a gradle plugin to launch docker-compose
which stands up database, runs migration (with flyway), and launches the server.
These are tests that run against a live database. They use `@QuarkusTest`, which starts the
Quarkus application in-process - no separately managed server is needed.

Before running integration tests, start Postgres and run Flyway migrations:

```
docker compose up database flyway
```

Then run the tests with:

```
./gradlew check
```

The `make verify` command does both steps in sequence.


## Deployment
Expand Down Expand Up @@ -88,4 +100,3 @@ and can be returned as part of the 'list-maps' payload to clients.
- `MapIndexer`: fetches all the data of a given map, creates a `MapIndexingResult`
- `MapIndexingResult`: represents all desired data of a parsed map, eg: map name, download size, description
- `MapIndexDao`: upserts `MapIndexingResult` into database

105 changes: 39 additions & 66 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
plugins {
id("java")
id("io.freefair.lombok") version "8.14.2"
id("com.diffplug.spotless") version "8.2.1"
id("com.avast.gradle.docker-compose") version "0.17.12"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("com.diffplug.spotless") version "7.2.1"
id("io.quarkus") version "3.34.6"
}

java {
Expand All @@ -16,26 +15,12 @@ repositories {
maven {
url = uri("https://maven.pkg.github.com/triplea-game/triplea")
credentials {
username = System.getenv("GITHUB_ACTOR") ?: project.findProperty("triplea.github.username") as String?
password = System.getenv("GH_TOKEN") ?: project.findProperty("triplea.github.access.token") as String?
username = System.getenv("GITHUB_ACTOR") ?: project.findProperty("triplea_github_username") as String?
password = System.getenv("GH_TOKEN") ?: project.findProperty("triplea_github_access_token") as String?
}
}
}

tasks.jar {
manifest {
attributes["Main-Class"] = "org.triplea.server.SupportServerApplication"
}
}

tasks.shadowJar {
archiveClassifier.set("")
// mergeServiceFiles is needed by dropwizard
// Without this configuration parsing breaks and is unable to find connector type "http" for
// the following YAML snippet: server: {applicationConnectors: [{type: http, port: 8080}]
mergeServiceFiles()
}

/* "testInteg" runs tests that require a database or a server to be running */
val testInteg: SourceSet = sourceSets.create("testInteg") {
java {
Expand All @@ -52,95 +37,83 @@ val testIntegTask = tasks.register<Test>("testInteg") {
group = "verification"
testClassesDirs = sourceSets["testInteg"].output.classesDirs
classpath = sourceSets["testInteg"].runtimeClasspath
// Required for Quarkus @QuarkusTest to use the JBoss log manager
systemProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager")
}

tasks.check {
dependsOn(testIntegTask)
}


///* docker compose used to set up integ tests, starts a server and database */
// See: https://github.com/avast/gradle-docker-compose-plugin
dockerCompose {
captureContainersOutput = true
isRequiredBy(testIntegTask)
setProjectName("support-server")
// suppress unset variable warning, assign variables to empty string (which will result in random port numbers)
environment = mapOf("DATABASE_PORT" to "", "SERVER_PORT" to "")
}

tasks.composeBuild {
dependsOn(tasks.shadowJar)
}

tasks.register<Exec>("dockerComposeClean") {
group = "docker"
description = "Docker compose stop and removes volumes"
commandLine("docker", "compose", "down", "--volumes")
}

tasks.clean {
dependsOn(tasks.findByName("dockerComposeClean"))
// Clean Quarkus build artifacts
delete("build/quarkus-app")
}

tasks {
withType<Test> {
useJUnitPlatform()
testLogging {
events("standardOut", "standardError", "skipped", "failed")
}
jvmArgs("-XX:+EnableDynamicAgentLoading", "-Duser.timezone=UTC")
useJUnitPlatform()
testLogging {
events("standardOut", "standardError", "skipped", "failed")
}
jvmArgs("-XX:+EnableDynamicAgentLoading", "-Duser.timezone=UTC")
}
}

spotless {
java {
googleJavaFormat()
removeUnusedImports()
expandWildcardImports()
}
}

val dropWizardVersion = "4.0.7"
val quarkusPlatformVersion = "3.34.6"
val feignVersion = "13.6"
val gsonVersion = "2.12.1"
val jaxbVersion = "4.0.5"
val junitVersion = "5.13.4"
val mockitoVersion = "5.19.0"
val tripleaVersion = "2.7.15281"

dependencies {
implementation("at.favre.lib:bcrypt:0.10.2")
implementation("be.tomcools:dropwizard-websocket-jsr356-bundle:4.0.0")
implementation("com.google.code.gson:gson:$gsonVersion")
implementation("com.sun.mail:jakarta.mail:2.0.2")
implementation("com.sun.xml.bind:jaxb-core:$jaxbVersion")
implementation("com.sun.xml.bind:jaxb-impl:$jaxbVersion")
implementation("io.dropwizard:dropwizard-auth:$dropWizardVersion")
implementation("io.dropwizard:dropwizard-core:$dropWizardVersion")
implementation("io.dropwizard:dropwizard-jdbi3:$dropWizardVersion")
implementation("javax.activation:activation:1.1.1")
implementation("javax.servlet:servlet-api:2.5")
implementation("javax.xml.bind:jaxb-api:2.3.1")
implementation("org.apache.httpcomponents:httpclient:4.5.14")
implementation("org.java-websocket:Java-WebSocket:1.6.0")
implementation(enforcedPlatform("io.quarkus.platform:quarkus-bom:$quarkusPlatformVersion"))

// Quarkus extensions
implementation("io.quarkus:quarkus-resteasy-jackson") // JAX-RS (Classic) + Jackson
implementation("io.quarkus:quarkus-agroal") // JDBC connection pool
implementation("io.quarkus:quarkus-jdbc-postgresql") // PostgreSQL + Dev Services
implementation("io.quarkus:quarkus-flyway") // DB migrations on startup
implementation("io.quarkus:quarkus-scheduler") // @Scheduled background tasks
implementation("org.flywaydb:flyway-database-postgresql")
// JDBI — framework-agnostic, wires against any DataSource
implementation("org.jdbi:jdbi3-core:3.49.5")
implementation("org.jdbi:jdbi3-sqlobject:3.49.5")

// Gson — used by GithubApiClient
implementation("com.google.code.gson:gson:$gsonVersion")

// SnakeYAML Engine — used by MapNameReader to parse map.yml files
implementation("org.snakeyaml:snakeyaml-engine:2.10")

// Annotations previously pulled in transitively by DropWizard
implementation("com.google.guava:guava:33.4.8-jre") // @VisibleForTesting
implementation("com.google.code.findbugs:jsr305:3.0.2") // @Nonnull

// TripleA shared libraries
implementation("triplea:domain-data:$tripleaVersion")
implementation("triplea:java-extras:$tripleaVersion")
implementation("triplea:lobby-client:$tripleaVersion")
implementation("triplea:websocket-client:$tripleaVersion")
runtimeOnly("org.postgresql:postgresql:42.7.7")

// Test dependencies
testImplementation(enforcedPlatform("io.quarkus.platform:quarkus-bom:$quarkusPlatformVersion"))
testImplementation("io.quarkus:quarkus-junit5") // @QuarkusTest + Dev Services

testImplementation("io.github.openfeign:feign-core:$feignVersion")
testImplementation("io.github.openfeign:feign-gson:$feignVersion")
testImplementation("triplea:feign-common:$tripleaVersion")

testImplementation("com.github.database-rider:rider-junit5:1.44.0")
testImplementation("com.github.npathai:hamcrest-optional:2.0.0")
testImplementation("com.sun.mail:jakarta.mail:2.0.2")
testImplementation("io.dropwizard:dropwizard-testing:$dropWizardVersion")
testImplementation("org.awaitility:awaitility:4.3.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
testImplementation("org.junit.jupiter:junit-jupiter-params:$junitVersion")
Expand Down
50 changes: 0 additions & 50 deletions configuration.yml

This file was deleted.

Loading
Loading