# Deploy a Java app built by Gradle on Yeeted

A small slug API in **Java 21** on the JDK's own HTTP server, built by
**Gradle from `build.gradle` with no Dockerfile**. Yeeted detects
`build.gradle`, runs `gradle build -x test` in a Gradle 8 image, copies the
jar from `build/libs/` into a Java 21 runtime image, and starts it with
`java -jar`.

The source is identical to the [Maven twin](slug-maven.md) apart
from its name, so a difference between the two deployments is the build tool,
not the app. JUnit is the sole dependency, at test scope; the deployed build
skips the tests and never resolves it.

- `GET /api/slug?text=...` returns `{"text": ..., "slug": ...}`; a missing or
  blank `text` returns 400.
- `GET /` is a form that calls the API; `GET /healthz` returns `ok`.
- The server reads `$PORT` (default 8080) and binds `0.0.0.0`.

Tests: `gradle test` (JUnit 5 on the slug rules, query parsing and JSON
escaping) · `./smoke.sh https://...` against a deployment.

## Run locally

Use JDK 21 and Gradle 8. The project carries no Gradle wrapper, because the
deployed build uses the image's own Gradle. From `java/slug-gradle`:

```sh
gradle test
gradle build
PORT=8080 java -jar build/libs/slug-gradle-1.0.0.jar
```

Open `http://localhost:8080`, or call the API directly:

```sh
curl 'http://localhost:8080/api/slug?text=Cr%C3%A8me%20Br%C3%BBl%C3%A9e'
```

## Deploy and verify

Follow the [deployment walkthrough](getting-started.md). Deploy this
folder, `build.gradle`, `settings.gradle`, `src/` and `yeeted.yaml`, with no
database and no Dockerfile. Do not upload `build/` or `.gradle/`; the build
runs on Yeeted. The manifest selects port 8080 and `/healthz`.

```sh
sh smoke.sh "$PREVIEW_URL"
```

The script checks the health endpoint, the page, two slugs (one with
accents), and that a blank request is refused with 400.

## What to change before real use

The generated image copies `build/libs/*.jar`, so the build must produce
exactly one jar there. The plain `java` plugin does; the Spring Boot plugin
also writes a `-plain` jar beside the boot jar unless its `jar` task is
disabled. Anything the app needs at runtime has to be inside that one jar.

[All examples](index.md) · [Deploy an example](getting-started.md)
