# Review Pull Requests Automatically in a Spring Boot App

Yes. An agent checks out the Spring Boot pull request, runs ./mvnw test, and posts one review of the owner and visit controllers.

[Run this on Rush](https://cloud.getrush.ai/run/review-pull-requests/spring-boot/), in a Project that has your repository.

## What the agent does

The agent checks out the pull request and reads the build before it picks a wrapper. In an app shaped like spring-projects/spring-petclinic, pom.xml sets java.version to 17 and the parent to spring-boot-starter-parent 4.1.0. The Maven wrapper's distributionUrl is apache-maven 3.9.16. A Gradle build is also in the tree, with gradlew, build.gradle and .github/workflows/gradle-build.yml beside maven-build.yml. The request says ./mvnw test, so that is the command. maven-build.yml itself runs ./mvnw -B verify on Temurin-shaped setup-java with Java 17. The agent does not switch to Gradle because a second build file exists.

Owner and visit code is under src/main/java/org/springframework/samples/petclinic/owner. OwnerController maps /owners/new, /owners/find, /owners, /owners/{ownerId}/edit and /owners/{ownerId}. processFindForm takes page with default 1, strips lastName, and calls findPaginatedForOwnersLastName, which uses page size 5 and PageRequest.of(validatedPage - 1, pageSize). If page is below 1 or above the total, it redirects to /owners with page 1. One owner redirects to that owner's detail. VisitController maps GET and POST /owners/{ownerId}/pets/{petId}/visits/new. initNewVisitForm returns pets/createOrUpdateVisitForm. processNewVisitForm rejects a date that is not after LocalDate.now(), and minVisitDate returns tomorrow. On success it calls owner.addVisit(petId, visit), saves, and flashes Your visit has been booked.

./mvnw test runs the owner tests with the rest of the suite. src/test/java holds OwnerControllerTests, VisitControllerTests, PetControllerTests, OwnerTests, PetValidatorTests, PetTypeFormatterTests, ClinicServiceTests, the vet tests, and PetClinicIntegrationTests. MySqlIntegrationTests and PostgresIntegrationTests are in the same tree and pull in testcontainers, so a run that includes them needs a container runtime. The agent runs ./mvnw test as the wrapper resolves it and quotes the Surefire summary. A container failure stays in the test paragraph as an environment failure. The agent does not add -DskipTests or exclude those classes to produce a shorter log, and it does not push a change to pom.xml.

The review cites file and line in the two controllers and in the test that covers the behavior the diff touches. Blocking is a page check that no longer redirects an out-of-range page, a visit date comparison that accepts today when minVisitDate is tomorrow, or a binding error that returns the wrong template. A suggestion is a new query with no method in OwnerControllerTests, or a Gradle-only change the Maven command did not compile. One review. The author's branch is not updated.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Review this pull request on Spring PetClinic. Check it out and run ./mvnw test. The project is Java 17 and Spring Boot 4.1.0, and the wrapper uses Maven 3.9.16. Do not use Gradle. Read the diff with src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java and VisitController.java, and with OwnerControllerTests and VisitControllerTests. Post one GitHub review that cites file and line for every finding, separates blocking issues from suggestions, and includes the Maven test result. Do not push commits.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app/pull/1"
    }
  ]
}
```

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 review on the open pull request. The session read names the repository and the pull request. The review starts with the ./mvnw test summary, including skipped or failed classes if Surefire printed them, then blocking notes and suggestions. Citations land in OwnerController.processFindForm, VisitController.processNewVisitForm, or the matching test method when the diff changes them. No new commit appears on the branch.

A reviewer checks that the command was the Maven wrapper and not gradlew, because both are present and CI runs both workflows on different files. A green test paragraph that omits MySqlIntegrationTests should say whether Surefire excluded it or the run failed to start a container. The transcript holds the wrapper output as a tool_result. The live stream is GET /o/{org}/sessions/{id}/events. After the turn, the answer is on the session, and the webhook's result field includes it up to 16 KiB.

## Run it on every pull request opened

On pull_request.opened, POST this session with the pull request URL in resources. The GitHub App must cover the repository. Idempotency-Key equal to the delivery id makes a retry safe: the same key and body return the original session, and a completed run keeps its key, so the next push needs a new key. One repository per run, which matters here because the Maven reactor and the Gradle build would otherwise fight over one target directory.

Subscribe the API key to a webhook to hear run.completed or run.failed. Maven on this tree downloads Spring Boot 4.1.0 and may start testcontainers, so the turn is long and a second copy should wait. max_concurrent defaults to 4 and the next start is 429. The sandbox parks when the turn ends, which keeps the local Maven repository for a follow-up on that same session.

## Why run it on Rush?

Reviewing PetClinic on a laptop means a JDK 17 install, a full Maven dependency fetch, and a choice between mvnw and gradlew that is easy to get wrong. The sandbox runs the wrapper the request names and keeps the Surefire log. Your own Java install and your local .m2 are not involved. If the turn is still going when you leave, it keeps going. A follow-up wakes the parked sandbox instead of resolving Spring Boot again from scratch.

The review is checkable because the date rule and the page redirect are in specific methods, and the test log says whether those tests ran. A comment from the diff alone cannot tell you that ./mvnw test compiled the main sources or that a testcontainers class failed to start. Each pull request is a separate sandbox, so two reviews do not share a Maven repository or a Docker daemon on your machine, and a person still decides whether the finding blocks merge.

## Frequently asked questions

### The repo has gradlew and mvnw. Which one runs?

./mvnw test, because that is the request. maven-build.yml runs ./mvnw -B verify on Java 17, and a separate workflow uses Gradle. The review says Maven was the command. It does not edit either workflow.

### Will testcontainers stop the review?

If MySqlIntegrationTests or PostgresIntegrationTests run and no container runtime is available, that failure is the test result in the review. The agent does not delete those classes or add an exclude to pom.xml. You can name -Dtest=OwnerControllerTests,VisitControllerTests in the input when you want only those classes quoted, and the review should say the rest were not run.

### Does it change the visit date rule?

It does not push. processNewVisitForm rejects a date that is not after today, and minVisitDate is tomorrow. If the diff changes either method, the review cites that line and the test that covers it. The form template name pets/createOrUpdateVisitForm stays as the branch has it.

### What is a blocking finding on the owner list?

A change that breaks the out-of-range redirect in processFindForm, the page size of 5, or the single-owner redirect to /owners/{id}. The review cites the line in OwnerController and the assertion in OwnerControllerTests when the diff touches that path. A rename of a model attribute is a suggestion unless a template still reads the old name.

### Can a teammate add a note after the review is posted?

The GitHub review is already on the pull request. A Rush follow-up is separate: POST /o/{org}/sessions/{id}/messages once status is not running. That wakes the parked sandbox and can ask for a second pass on one method. It does not edit the GitHub review unless the new input says to post another one.
