Skip to content

feature/add-gradle-init#178

Open
KevinGruber2001 wants to merge 1 commit intomainfrom
feat/gradle-daemon-init
Open

feature/add-gradle-init#178
KevinGruber2001 wants to merge 1 commit intomainfrom
feat/gradle-daemon-init

Conversation

@KevinGruber2001
Copy link

@KevinGruber2001 KevinGruber2001 commented Mar 9, 2026

Description

Pre-warms the Gradle daemon in the background immediately after cloning a Java exercise. This eliminates the ~3s daemon initialization overhead on the student's first ./gradlew build.

  • New gradle.service.ts: checks for gradlew, chmod +xes it, and spawns ./gradlew --daemon as a detached fire-and-forget process
  • Only runs for Java exercises (checked via programmingLanguage), silently skips on Windows or non-Gradle projects
  • Called in cloning.service.ts right after clone completes, before the "Open folder" dialog — so the daemon warms up while the student is still clicking

Steps for Testing

  1. Open Scorpio and select a Java exercise
  2. Clone the exercise
  3. Run ./gradlew --status in the cloned repo — a daemon should already be running
  4. Run ./gradlew build — should skip daemon initialization
  5. Repeat with a non-Java exercise (e.g. Python) — no daemon should be spawned, no errors

Review Progress

Code Review

  • Review 1
  • Review 2

Manual Tests

  • Test 1
  • Test 2

Summary by CodeRabbit

  • Performance Improvements
    • Java programming exercises now include automatic build environment initialization that runs in the background immediately after repository cloning, improving startup performance and accelerating subsequent build operations.
    • Enhancement operates silently without requiring any user action or configuration.

@KevinGruber2001 KevinGruber2001 self-assigned this Mar 9, 2026
@KevinGruber2001 KevinGruber2001 added the enhancement New feature or request label Mar 9, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

📝 Walkthrough

Walkthrough

This PR introduces a background Gradle daemon warmup mechanism that activates after cloning a Java programming exercise repository. A new warmupGradleDaemon function pre-initializes the Gradle daemon in a detached process to reduce subsequent build latency, with platform detection and error handling included.

Changes

Cohort / File(s) Summary
Gradle Daemon Warmup
src/participation/gradle.service.ts
New exported function warmupGradleDaemon() that launches Gradle daemon in detached background process via ./gradlew --daemon, with platform checks (skips on Windows), executable permission setup, and error logging.
Cloning Service Integration
src/participation/cloning.service.ts
Integrated warmupGradleDaemon invocation after repository clone completes, with conditional logic to trigger only for Java programming language exercises.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 With a hop and a skip through Java's embrace,
The daemon now warms up with graceful pace,
Building faster, no lingering delay—
Pre-warmed and ready to brighten your day! ⚡

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'feature/add-gradle-init' is a branch naming convention label rather than a descriptive pull request title; it does not clearly summarize the main change for someone reviewing commit history. Replace with a descriptive title like 'Pre-warm Gradle daemon on Java exercise clone' or 'Add background Gradle daemon initialization after cloning' that clearly conveys the purpose and benefit.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/gradle-daemon-init

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/participation/cloning.service.ts (1)

53-57: Consider removing the JAVA gate and letting the service decide.

warmupGradleDaemon() already checks the platform and whether gradlew exists. Keeping the language check here duplicates that policy and prevents other Gradle-backed exercises from benefiting later. Calling the service unconditionally after a successful clone would keep the logic in one place and still no-op for non-Gradle repos.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/participation/cloning.service.ts` around lines 53 - 57, The conditional
guard on ProgrammingLanguage.JAVA before calling warmupGradleDaemon duplicates
the service's platform/gradlew checks and blocks other Gradle-backed exercises;
remove the language check and call warmupGradleDaemon(clonePath) unconditionally
after clone success (leave warmupGradleDaemon implementation intact so it can
no-op when appropriate), locating the call near getState().displayedExercise and
clonePath usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/participation/gradle.service.ts`:
- Around line 23-31: The code currently changes permissions and auto-spawns the
repository-controlled wrapper (gradlewPath, chmodSync and spawn("./gradlew",
["--daemon"], ...), child.unref()) which executes code from the cloned repo;
change this so the Gradle warmup is not auto-run during cloning: remove or
disable the spawn/unref call in src/participation/gradle.service.ts and instead
gate warmup behind an explicit trust/opt-in or defer it until the first
user-initiated Gradle command (e.g., add a check like
isRepositoryTrusted()/userOptIn flag before calling spawn or expose a separate
warmup method invoked only by the user-triggered Gradle flow), and ensure
cloning.service no longer invokes the warmup automatically.
- Around line 26-31: Attach an "error" handler to the spawned child process to
catch synchronous spawn failures that aren’t covered by the surrounding
try/catch: after creating const child = spawn("./gradlew", ["--daemon"], { ...
}) (in gradle.service.ts) add child.on("error", (err) => { /* handle failure */
}) before calling child.unref(); inside the handler log the error (e.g., using
the existing logger), perform any necessary cleanup, and propagate the failure
(throw or reject the surrounding Promise) so callers know the wrapper failed to
start.

---

Nitpick comments:
In `@src/participation/cloning.service.ts`:
- Around line 53-57: The conditional guard on ProgrammingLanguage.JAVA before
calling warmupGradleDaemon duplicates the service's platform/gradlew checks and
blocks other Gradle-backed exercises; remove the language check and call
warmupGradleDaemon(clonePath) unconditionally after clone success (leave
warmupGradleDaemon implementation intact so it can no-op when appropriate),
locating the call near getState().displayedExercise and clonePath usage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 276d68a4-e614-4bb3-9b84-c5ad8c96e429

📥 Commits

Reviewing files that changed from the base of the PR and between efa5e14 and b5317ea.

📒 Files selected for processing (2)
  • src/participation/cloning.service.ts
  • src/participation/gradle.service.ts

Comment on lines +23 to +31
try {
fs.chmodSync(gradlewPath, 0o755);

const child = spawn("./gradlew", ["--daemon"], {
cwd: projectPath,
detached: true,
stdio: "ignore",
});
child.unref();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't auto-execute repository-controlled gradlew during clone.

Because src/participation/cloning.service.ts:53-57 invokes this immediately after cloning, this executes code from the freshly cloned repository before the user has opened or trusted it. gradlew and the wrapper configuration are part of the repo, so a compromised template or participation repository turns this into unintended code execution. Gate this behind explicit opt-in/trust, or defer warmup until the first user-initiated Gradle command.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/participation/gradle.service.ts` around lines 23 - 31, The code currently
changes permissions and auto-spawns the repository-controlled wrapper
(gradlewPath, chmodSync and spawn("./gradlew", ["--daemon"], ...),
child.unref()) which executes code from the cloned repo; change this so the
Gradle warmup is not auto-run during cloning: remove or disable the spawn/unref
call in src/participation/gradle.service.ts and instead gate warmup behind an
explicit trust/opt-in or defer it until the first user-initiated Gradle command
(e.g., add a check like isRepositoryTrusted()/userOptIn flag before calling
spawn or expose a separate warmup method invoked only by the user-triggered
Gradle flow), and ensure cloning.service no longer invokes the warmup
automatically.

Comment on lines +26 to +31
const child = spawn("./gradlew", ["--daemon"], {
cwd: projectPath,
detached: true,
stdio: "ignore",
});
child.unref();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n src/participation/gradle.service.ts | head -50

Repository: EduIDE/scorpio

Length of output: 1234


Handle detached spawn failures on the child "error" event.

try/catch only covers the synchronous setup here. If the wrapper cannot be launched at all, Node reports that via child.on("error"), which currently goes unhandled.

Suggested fix
     const child = spawn("./gradlew", ["--daemon"], {
       cwd: projectPath,
       detached: true,
       stdio: "ignore",
     });
+    child.on("error", (error) => {
+      console.warn(`Gradle daemon warmup failed: ${error.message}`);
+    });
     child.unref();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const child = spawn("./gradlew", ["--daemon"], {
cwd: projectPath,
detached: true,
stdio: "ignore",
});
child.unref();
const child = spawn("./gradlew", ["--daemon"], {
cwd: projectPath,
detached: true,
stdio: "ignore",
});
child.on("error", (error) => {
console.warn(`Gradle daemon warmup failed: ${error.message}`);
});
child.unref();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/participation/gradle.service.ts` around lines 26 - 31, Attach an "error"
handler to the spawned child process to catch synchronous spawn failures that
aren’t covered by the surrounding try/catch: after creating const child =
spawn("./gradlew", ["--daemon"], { ... }) (in gradle.service.ts) add
child.on("error", (err) => { /* handle failure */ }) before calling
child.unref(); inside the handler log the error (e.g., using the existing
logger), perform any necessary cleanup, and propagate the failure (throw or
reject the surrounding Promise) so callers know the wrapper failed to start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant