diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..8774928e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +# Ignore Git files +.git +.gitignore +.gitattributes + +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/.env b/.env new file mode 100644 index 00000000..192dee3b --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +COMPOSE_PROJECT_NAME=galaxy-raiders + +GALAXY_RAIDERS_IMAGE=galaxy-raiders +GALAXY_RAIDERS_VERSION=dev diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d04cfe42..0ac87e67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,6 +15,6 @@ repos: name: Run Kotlin linters description: This hook runs Gradle to execute linters language: system - entry: bash -c "docker container run --rm --user gradle --volume $PWD:/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle --no-daemon formatKotlin detekt" + entry: docker compose --profile dev run -T --rm linter types: [kotlin] pass_filenames: false diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..7df712d2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,62 @@ +################################################################################ +# BASE IMAGE # +################################################################################ + +# Use Gradle image to run Gradle commands +FROM gradle:7.4.2-jdk17 AS base + +# Set default docker build args +ARG APP_DIR=/home/gradle/galaxy-raiders + +# Change default workdir +WORKDIR ${APP_DIR} + +# Set environment variable to disable Gradle Daemon +ENV GRADLE_OPTS=-Dorg.gradle.daemon=false + +# Give the ownership of workdir to the Gradle user +RUN chown -R gradle:gradle . + +# Change to non-priviled user (PID 1000) +USER gradle + +# NOTE: This repo has gradle wrappers to ensure developers use the same version +# of gradle in every environment. However, using gradle's docker image already +# guarantees that. Therefore, commands below can use the `gradle` CLI directly. + +# Copy source code to workdir +COPY --chown=gradle:gradle . . + +# NOTE: Gradle download dependencies only when they are necessary, which slows +# tasks the first time they execute. Running them here will allow docker to +# cache these dependencies to speed up containers that execute gradle tasks. + +# Force gradle to download dependencies to build, lint and test code +RUN gradle --no-build-cache clean + +################################################################################ +# BUILDER IMAGE # +################################################################################ + +# Use base image to build the project +FROM base AS builder + +# Use gradle wrapper to generate an uber JAR +RUN gradle --no-daemon shadowJar + +################################################################################ +# PRODUCTION IMAGE # +################################################################################ + +# Use Eclipse Temurin image to run the project +FROM eclipse-temurin:17-jdk AS runner + +# Reuse default docker build args +ARG APP_DIR=/home/gradle/galaxy-raiders + +# Copy runtime from image +COPY --from=builder ${APP_DIR}/app/build/libs/galaxy-raiders.jar \ + /bin/runner/galaxy-raiders.jar + +# Run uber JAR to start application +CMD ["java", "-jar", "galaxy-raiders.jar"] diff --git a/README.md b/README.md index dc4048f4..8a07f0fc 100644 --- a/README.md +++ b/README.md @@ -30,19 +30,22 @@ pre-commit run --all-files Alternatively, to execute the linters manually, run: ```bash -docker container run --rm --user gradle --volume "$PWD":/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle --no-daemon formatKotlin detekt +docker compose --profile dev run --rm linter ``` ## Compilation -To compile all classes in the project, run: +The compilation of all classes and the generation of a runnable self-contained +JAR is made "behind the scenes" by [docker][4]. + +To build the development images, run: ```bash -docker container run --rm --user gradle --volume "$PWD":/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle --no-daemon clean assemble +docker compose --profile dev build ``` -To generate a runnable self-contained JAR of the project, run: +To build the production images, run: ```bash -docker container run --rm --user gradle --volume "$PWD":/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle --no-daemon clean shadowJar +docker compose --profile prod build ``` ## Tests @@ -51,32 +54,31 @@ All tests in the project are developed using [JUnit 5][8]. To execute all tests (with live reload), run: ```bash -docker container run --rm --user gradle --volume "$PWD":/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle --continuous test +docker compose --profile dev up tester ``` ## Execution To execute the project in development mode (with live reload), run: ```bash -docker container run --rm --user gradle --volume "$PWD":/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle --continuous run +docker compose --profile dev up demo --build ``` -To execute the project in production mode, generate a runnable self-contained -JAR of the project, then run: +To execute the project in production mode, run: ```bash -docker container run --rm --volume "$PWD"/app/build/libs/galaxy-raiders.jar:/bin/runner/galaxy-raiders.jar --workdir /bin/runner eclipse-temurin:17-jdk java -jar galaxy-raiders.jar +docker compose --profile prod up game --build ``` ## Other tasks To find available gradle tasks, run: ```bash -docker container run --rm --user gradle --volume "$PWD":/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle tasks +docker compose --profile dev run --rm demo gradle --no-daemon tasks ``` To execute any task, run: ```bash -docker container run --rm --user gradle --volume "$PWD":/home/gradle/app --workdir /home/gradle/app gradle:7.4.2-jdk17 gradle {task} +docker compose --profile dev run --rm demo gradle --no-daemon {task} ``` [1]: https://uspdigital.usp.br/jupiterweb/obterDisciplina?sgldis=MAC0218 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..d97c2353 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,48 @@ +services: + # The `game` service is the production app for end users. + game: + image: "${GALAXY_RAIDERS_IMAGE}:${GALAXY_RAIDERS_VERSION}" + build: + context: . + target: "runner" + profiles: + - "prod" + + # The `linter` service allows running all linters. + # Whenever a file changes, Gradle will rerun detekt and ktlint. + linter: + image: "${GALAXY_RAIDERS_IMAGE}:${GALAXY_RAIDERS_VERSION}" + build: + context: . + target: "base" + command: "gradle formatKotlin detekt" + volumes: + - "./:/home/gradle/galaxy-raiders/" + profiles: + - "dev" + + # The `tester` service allows running all tests. + # Whenever a file changes, JUnit will rerun all tests related to it. + tester: + image: "${GALAXY_RAIDERS_IMAGE}:${GALAXY_RAIDERS_VERSION}" + build: + context: . + target: "base" + command: "gradle --continuous test" + volumes: + - "./:/home/gradle/galaxy-raiders/" + profiles: + - "dev" + + # The `demo` service allows running the application. + # Whenever a file changes, the app will be restarted automatically. + demo: + image: "${GALAXY_RAIDERS_IMAGE}:${GALAXY_RAIDERS_VERSION}" + build: + context: . + target: "base" + command: "gradle --continuous runShadow" + volumes: + - "./:/home/gradle/galaxy-raiders/" + profiles: + - "dev"