All jobs

Upgrade a Quarkus App to Java 25

Yes. An agent moves your Quarkus build, Dockerfiles and CI to Java 25, runs the tests on JDK 25, fixes what breaks and opens a pull request.

Run this on RushIn a Project that has your repository.

What the agent does

The agent clones the repository into its own cloud sandbox and lists every place a Java version is written, because a Quarkus project spreads it across the build, the container images and CI. In a project shaped like the getting-started module of quarkusio/quarkus-quickstarts, pom.xml sets <maven.compiler.source>17</maven.compiler.source> and <maven.compiler.target>17</maven.compiler.target> next to quarkus.platform.version 3.40.1, compiler-plugin.version 3.15.0 and surefire-plugin.version 3.5.4. Across the whole quickstarts repository, 102 modules use the source and target pair and 11 use maven.compiler.release, so the agent changes each one in the form it already has rather than mixing the two.

It then reads the container images, which are easy to miss because the build never touches them. src/main/docker/Dockerfile.jvm starts FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.24, and Dockerfile.legacy-jar sits beside it, while Dockerfile.native and Dockerfile.native-micro ship a native binary with no JVM at all. A class file compiled for Java 25 will not load on a Java 21 runtime, so the JVM images move to the matching Java 25 runtime image and the native ones are left alone, with a line in the pull request saying why. A Kotlin module needs one more change: hibernate-orm-panache-kotlin-quickstart/pom.xml sets <jvmTarget>11</jvmTarget> for kotlin.version 2.3.0, and the agent decides whether that target should follow the Java version.

CI comes next. .github/workflows/build-pr-development.yml installs the JDK with actions/setup-java@v4, distribution: temurin and a java: [ 21 ] matrix, and keys the Maven cache on the JDK as q2maven-pr-jdk-${{ matrix.java }}. The agent changes the matrix to 25, so the cache key follows by itself. The Maven wrapper, .mvn/wrapper/maven-wrapper.properties, points at Maven 3.9.11; the agent checks that it runs on JDK 25 before it builds anything.

Then it installs JDK 25 in the sandbox and runs the build the workflow runs: ./mvnw -e -B clean install, which compiles, runs the @QuarkusTest classes such as GreetingResourceTest through Surefire, and the GreetingResourceIT integration tests through Failsafe. When Quarkus Dev Services needs a container for a database or a broker and none can start in the sandbox, the agent says which modules it could not test there. For each compile error, removed API or failing test it fixes the cause, reruns, and only then opens the pull request.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Upgrade this Quarkus project to Java 25. Find every place the Java version is set: maven.compiler.source, target or release in each pom.xml (keep the form each module already uses), the Kotlin jvmTarget if any, the runtime image in each src/main/docker/Dockerfile.jvm and Dockerfile.legacy-jar, and the java-version matrix in the GitHub Actions workflows. Leave native Dockerfiles alone. Check that the Maven wrapper and the Quarkus, compiler and Surefire plugins run on JDK 25 and update only what needs it. Install JDK 25 in the sandbox, run ./mvnw -B clean install, fix what breaks, and say which tests could not run there and why. Open a pull request listing each file changed, each fix, and anything left for a separate change.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

What comes back is a pull request on a new branch. In a Quarkus service it changes the compiler properties in pom.xml to 25, the FROM line of Dockerfile.jvm and Dockerfile.legacy-jar to a Java 25 runtime image, and the workflow matrix to [ 25 ], plus any source or test changes the new JDK forced. The description lists each file with the reason, each failure the agent hit with its fix, the modules whose tests could not run in the sandbox, and follow-ups it kept out, such as a Quarkus platform upgrade.

The checks are the repository's own: the pull request workflow builds every module on JDK 25 on GitHub's runners, where Dev Services can start its containers. The session's transcript keeps each command the agent ran, from java -version to every ./mvnw run, with its output.

Before merging, a reviewer checks that the new runtime image is one the team is allowed to deploy, that the Kotlin jvmTarget choice is deliberate, and that nothing in the description says a test was skipped without a reason. If the service is built as a native image, they confirm the native build still passes, since the JVM version change does not cover it.

Run it on every new JDK release

Java ships a feature release every six months and Quarkus follows with support for it. A scheduled job can send this request with the new version in the prompt once the platform supports it, one request per service, each with its repository in resources. Each run has its own sandbox and branch, so a team with many Quarkus services sees which ones move cleanly.

Set a webhook URL on the API key and Rush posts run.completed or run.failed when each run's turn finishes, with session_url to read the result. A key runs at most max_concurrent sessions at once, 4 by default, and answers 429 past that, so the job should queue its requests.

The use case this job follows, with its automation and trigger: Upgrade dependencies weekly.

Why run it on Rush?

A JDK upgrade is mostly about the machine it runs on: a fresh JDK, the Maven wrapper downloading its distribution, the whole dependency tree resolved again and every test run on the new version. In a Rush sandbox the agent installs JDK 25 on its own disk, so the build cannot quietly run on whatever JAVA_HOME a laptop has, and nobody's local toolchain changes.

The result carries its own proof. The transcript keeps every Maven run and its output, and the pull request's workflow builds again on JDK 25 with Dev Services available. Because each run is separate, a team can send one request per service at the same time and review the pull requests as they arrive.

Frequently asked questions

Does it upgrade the Quarkus platform version too?

Not unless you ask. The prompt changes the Java version and only the plugins that need it to run on JDK 25. A Quarkus upgrade has its own migration guide and risks, so it belongs in its own pull request.

What happens to my native image Dockerfiles?

They stay as they are. Dockerfile.native and Dockerfile.native-micro copy a native executable and need no JVM, so the Java runtime version does not apply to them. The pull request says so, and notes that the native build itself should be checked on CI.

Can it run tests that need Dev Services?

Dev Services starts databases and brokers in containers. When those cannot start in the sandbox, the agent lists the modules it could not test and the pull request's workflow runs them on GitHub's runners.

Should I use maven.compiler.release instead of source and target?

release also checks that the code uses only APIs from that Java version, which source and target do not. The agent keeps the form each module already uses so the diff stays small, and suggests the switch as a follow-up if you want it.