Skip to content

feature: allow to run gateway plugin in IDEA/Remote Development (crw-11741)#340

Open
adietish wants to merge 4 commits into
redhat-developer:mainfrom
adietish:crw-11741
Open

feature: allow to run gateway plugin in IDEA/Remote Development (crw-11741)#340
adietish wants to merge 4 commits into
redhat-developer:mainfrom
adietish:crw-11741

Conversation

@adietish

@adietish adietish commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Signed-off-by: Andre Dietisheim <adietish@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@adietish, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3c4b86a1-fcc3-4d70-9e5b-2733dfa18956

📥 Commits

Reviewing files that changed from the base of the PR and between 25236fa and e1980c9.

📒 Files selected for processing (8)
  • src/main/kotlin/com/redhat/devtools/gateway/DevSpacesConnection.kt
  • src/main/kotlin/com/redhat/devtools/gateway/DevSpacesContext.kt
  • src/main/kotlin/com/redhat/devtools/gateway/devworkspace/DevWorkspace.kt
  • src/main/kotlin/com/redhat/devtools/gateway/server/RemoteIDEServer.kt
  • src/main/kotlin/com/redhat/devtools/gateway/view/steps/DevSpacesWorkspacesStepView.kt
  • src/test/kotlin/com/redhat/devtools/gateway/DevSpacesContextTest.kt
  • src/test/kotlin/com/redhat/devtools/gateway/devworkspace/DevWorkspaceTest.kt
  • src/test/kotlin/com/redhat/devtools/gateway/server/RemoteIDEServerTest.kt
📝 Walkthrough

Walkthrough

The PR adds IntelliJ IDEA-specific Gradle execution support, documents IDEA feasibility, revises workspace and thin-client lifecycle handling, improves wizard disposal safety, and refactors kubeconfig file watching and cluster refresh coordination with expanded tests.

Changes

IDEA build and feasibility

Layer / File(s) Summary
IDEA Gradle platform and run tasks
.run/Run Plugin (IDEA).run.xml, build.gradle.kts, gradle.properties
IDEA mode resolves IntelliJ IDEA Ultimate and the Gateway plugin, registers runIdeIdea, and removes the upper build constraint.
IDEA feasibility evidence
docs/crw-11741-iu-feasibility.md
Documents compatibility evidence, runtime observations, smoke-harness usage, wizard results, known issues, and follow-ups.

Workspace connection and wizard lifecycle

Layer / File(s) Summary
Workspace identity and active tracking
src/main/kotlin/.../DevWorkspace.kt, DevSpacesContext.kt, DevSpacesWorkspacesStepView.kt, src/test/kotlin/.../DevWorkspaceTest.kt, DevSpacesContextTest.kt
Workspace identity and active tracking use namespace and name, with corresponding connection-state and equality tests.
Thin-client connection teardown
src/main/kotlin/.../DevSpacesConnection.kt
Connection callbacks distinguish establishing sessions from established sessions and route client loss through idempotent cleanup.
Remote IDE readiness polling
src/main/kotlin/.../RemoteIDEServer.kt, src/test/kotlin/.../RemoteIDEServerTest.kt
Readiness probes use separate execution and overall wait limits and refresh pod/container references while checking readiness.
Wizard disposal and navigation guards
src/main/kotlin/.../view/DevSpacesWizardView.kt, src/main/kotlin/.../view/steps/*, src/test/kotlin/.../DevSpacesWizardViewDisposeTest.kt
Wizard steps are disposed explicitly, asynchronous updates stop after disposal, and navigation accesses validate step bounds.

Kubeconfig monitoring

Layer / File(s) Summary
Filesystem watch lifecycle
src/main/kotlin/.../kubeconfig/FileWatcher.kt
FileWatcher tracks monitored paths and registered directories, handles asynchronous events, and serializes callbacks.
Cluster refresh coordination
src/main/kotlin/.../kubeconfig/KubeConfigMonitor.kt
KubeConfigMonitor exposes cluster state through StateFlow, reconciles monitored paths, coalesces refreshes, and skips unchanged results.
Watcher and refresh validation
src/test/kotlin/.../kubeconfig/*Test.kt
Tests cover nonexistent files, directory registration, filesystem events, monitored state, refresh coalescing, and unchanged cluster results.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: azatsarynnyy, vrubezhny

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: enabling the gateway plugin to run in IDEA and Remote Development.
Description check ✅ Passed The description references the tracked issue that this pull request implements, so it is related to the changeset.

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.

@codecov-commenter

codecov-commenter commented Jul 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 53.59477% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 33.16%. Comparing base (71098f6) to head (e1980c9).
⚠️ Report is 394 commits behind head on main.

Files with missing lines Patch % Lines
...com/redhat/devtools/gateway/DevSpacesConnection.kt 0.00% 28 Missing ⚠️
...edhat/devtools/gateway/view/DevSpacesWizardView.kt 9.09% 10 Missing ⚠️
.../redhat/devtools/gateway/kubeconfig/FileWatcher.kt 82.60% 0 Missing and 8 partials ⚠️
.../gateway/view/steps/DevSpacesWorkspacesStepView.kt 0.00% 7 Missing ⚠️
.../redhat/devtools/gateway/server/RemoteIDEServer.kt 64.70% 5 Missing and 1 partial ⚠️
...ools/gateway/view/steps/DevSpacesServerStepView.kt 0.00% 6 Missing ⚠️
...t/devtools/gateway/kubeconfig/KubeConfigMonitor.kt 84.00% 2 Missing and 2 partials ⚠️
...in/com/redhat/devtools/gateway/DevSpacesContext.kt 80.00% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            main     #340       +/-   ##
==========================================
+ Coverage   0.00%   33.16%   +33.16%     
==========================================
  Files          4      111      +107     
  Lines         26     4640     +4614     
  Branches       0      880      +880     
==========================================
+ Hits           0     1539     +1539     
- Misses        26     2889     +2863     
- Partials       0      212      +212     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…partial (crw-11741)

Signed-off-by: Andre Dietisheim <adietish@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Late kubeconfig cluster updates raced dispose clearing steps; stop
monitoring on dispose and skip nav updates when the step list is empty.

Signed-off-by: Andre Dietisheim <adietish@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@adietish
adietish marked this pull request as ready for review July 23, 2026 14:20

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/kotlin/com/redhat/devtools/gateway/server/RemoteIDEServer.kt (1)

143-158: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Pod is re-resolved on every 500ms poll while waiting for readiness.

refreshPodBeforeCheck = isReadyState causes findPod()/findContainer() (a K8s list call) on every poll iteration for up to readyTimeout (120s) — up to ~240 extra API calls per connection attempt. Correctness-wise this is fine, but consider throttling the refresh (e.g., every few seconds instead of every poll) to reduce API load, especially under many concurrent users.

As per path instructions, "Focus on major issues impacting performance."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/kotlin/com/redhat/devtools/gateway/server/RemoteIDEServer.kt` around
lines 143 - 158, Throttle pod re-resolution in the readiness wait loop around
isServerState instead of setting refreshPodBeforeCheck to isReadyState on every
500ms poll. Track elapsed time or poll count and refresh only at a multi-second
interval, while continuing readiness checks every poll and preserving
cancellation, timeout, and recycled-pod detection.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/kotlin/com/redhat/devtools/gateway/DevSpacesConnection.kt`:
- Around line 146-158: Update handleClientGone and both call sites in connect,
including the onDisconnectSignal handler and catch block, to pass the
connection’s captured workspace explicitly as the first argument. Ensure
handleClientGone uses that supplied workspace instead of re-reading
devSpacesContext.devWorkspace, so delayed callbacks tear down only the workspace
associated with their connection.

---

Nitpick comments:
In `@src/main/kotlin/com/redhat/devtools/gateway/server/RemoteIDEServer.kt`:
- Around line 143-158: Throttle pod re-resolution in the readiness wait loop
around isServerState instead of setting refreshPodBeforeCheck to isReadyState on
every 500ms poll. Track elapsed time or poll count and refresh only at a
multi-second interval, while continuing readiness checks every poll and
preserving cancellation, timeout, and recycled-pod detection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dfccbbc5-db46-4819-bd27-e85ecaa5f67a

📥 Commits

Reviewing files that changed from the base of the PR and between 07ca022 and 25236fa.

📒 Files selected for processing (19)
  • .run/Run Plugin (IDEA).run.xml
  • build.gradle.kts
  • docs/crw-11741-iu-feasibility.md
  • gradle.properties
  • src/main/kotlin/com/redhat/devtools/gateway/DevSpacesConnection.kt
  • src/main/kotlin/com/redhat/devtools/gateway/DevSpacesContext.kt
  • src/main/kotlin/com/redhat/devtools/gateway/devworkspace/DevWorkspace.kt
  • src/main/kotlin/com/redhat/devtools/gateway/kubeconfig/FileWatcher.kt
  • src/main/kotlin/com/redhat/devtools/gateway/kubeconfig/KubeConfigMonitor.kt
  • src/main/kotlin/com/redhat/devtools/gateway/server/RemoteIDEServer.kt
  • src/main/kotlin/com/redhat/devtools/gateway/view/DevSpacesWizardView.kt
  • src/main/kotlin/com/redhat/devtools/gateway/view/steps/DevSpacesServerStepView.kt
  • src/main/kotlin/com/redhat/devtools/gateway/view/steps/DevSpacesWorkspacesStepView.kt
  • src/test/kotlin/com/redhat/devtools/gateway/DevSpacesContextTest.kt
  • src/test/kotlin/com/redhat/devtools/gateway/devworkspace/DevWorkspaceTest.kt
  • src/test/kotlin/com/redhat/devtools/gateway/kubeconfig/FileWatcherTest.kt
  • src/test/kotlin/com/redhat/devtools/gateway/kubeconfig/KubeConfigMonitorTest.kt
  • src/test/kotlin/com/redhat/devtools/gateway/server/RemoteIDEServerTest.kt
  • src/test/kotlin/com/redhat/devtools/gateway/view/DevSpacesWizardViewDisposeTest.kt
💤 Files with no reviewable changes (1)
  • gradle.properties

Comment on lines +146 to 158
val onDisconnectSignal: () -> Unit = {
finished.set(true)
// Ignore ephemeral closes during connect wait; teardown runs via catch.
if (sessionEstablished.get()) {
handleClientGone(
thinClient,
onDisconnected,
onDevWorkspaceStopped,
remoteIdeServer,
forwarder
)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

handleClientGone reads the shared mutable devSpacesContext.devWorkspace instead of the connection's captured workspace.

connect() snapshots workspace at line 64 for this connection's lifetime, but handleClientGone (called from onDisconnectSignal and the catch block) ignores that and re-reads devSpacesContext.devWorkspace live. Since the thin-client's clientClosed/clientFailedToOpenProject callbacks are registered for Lifetime.Eternal (not scoped to this connect() call), a delayed disconnect signal from an earlier connection can fire after the user has already selected and connected to a different workspace. devSpacesContext.devWorkspace will then point at the new workspace, so the stale teardown calls removeWorkspace(newWorkspace) and can even stop() the wrong, currently-active DevWorkspace. This is made more likely now that isNextEnabled() no longer blocks starting a new connection while "already connected".

🐛 Proposed fix: thread `workspace` through instead of re-reading shared state
     `@Suppress`("UnstableApiUsage")
     private fun handleClientGone(
+        workspace: DevWorkspace,
         client: ThinClientHandle? = null,
         onDisconnected: () -> Unit,
         onDevWorkspaceStopped: () -> Unit,
         remoteIdeServer: RemoteIDEServer?,
         forwarder: Closeable?
     ) {
         if (!clientGoneHandled.compareAndSet(false, true)) {
             return
         }
-        val workspace = devSpacesContext.devWorkspace
         // Clear tracking + refresh UI before any remote wait so Connect is not stuck
         // behind waitServerTerminated (up to 10s) when the wizard stays open in IDEA.
         devSpacesContext.removeWorkspace(workspace)
         runCatching { onDisconnected() }

Update both call sites accordingly:

// onDisconnectSignal
handleClientGone(
    workspace,
    thinClient,
    onDisconnected,
    onDevWorkspaceStopped,
    remoteIdeServer,
    forwarder
)

// catch block
handleClientGone(workspace, client, onDisconnected, onDevWorkspaceStopped, remoteIdeServer, forwarder)

As per path instructions, "Focus on major issues impacting performance, readability, maintainability and security."

Also applies to: 190-194, 228-252

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/kotlin/com/redhat/devtools/gateway/DevSpacesConnection.kt` around
lines 146 - 158, Update handleClientGone and both call sites in connect,
including the onDisconnectSignal handler and catch block, to pass the
connection’s captured workspace explicitly as the first argument. Ensure
handleClientGone uses that supplied workspace instead of re-reading
devSpacesContext.devWorkspace, so delayed callbacks tear down only the workspace
associated with their connection.

Source: Path instructions

Drop unused ThinClientSessionContext ahead of a later CRW-11119
rebase. Clear workspace tracking on disconnect before remote stop
waits; gate Connect on Running only. Keep name/namespace
bookkeeping and shorter status-exec probes (120s ready wait).

Signed-off-by: Andre Dietisheim <adietish@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants