Skip to content

Commit 74ad635

Browse files
aaronlehmannbcpeinhardt
andauthoredMar 7, 2025
Retrieve workspace directly in link handler when using wildcardSSH feature (#542)
* Retrieve workspace directly in link handler when using wildcardSSH feature Instead of listing all workspaces matching the filter, get info about the specific workspace the user is trying to connect to. This lets jetbrains-gateway:// links to others' workspaces work without needing to modify the workspace filter parameter. * changelog update --------- Co-authored-by: Benjamin Peinhardt <[email protected]> Co-authored-by: Benjamin <[email protected]>
1 parent 64e66d8 commit 74ad635

File tree

4 files changed

+49
-18
lines changed

4 files changed

+49
-18
lines changed
 

‎CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
## Unreleased
66

7+
### Changed
8+
9+
Retrieve workspace directly in link handler when using wildcardSSH feature
10+
711
## 2.19.0 - 2025-02-21
812

913
### Added

‎src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt

+13
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,19 @@ open class CoderRestClient(
176176
return workspacesResponse.body()!!.workspaces
177177
}
178178

179+
/**
180+
* Retrieves a specific workspace by owner and name.
181+
* @throws [APIResponseException].
182+
*/
183+
fun workspaceByOwnerAndName(owner: String, workspaceName: String): Workspace {
184+
val workspaceResponse = retroRestClient.workspaceByOwnerAndName(owner, workspaceName).execute()
185+
if (!workspaceResponse.isSuccessful) {
186+
throw APIResponseException("retrieve workspace", url, workspaceResponse)
187+
}
188+
189+
return workspaceResponse.body()!!
190+
}
191+
179192
/**
180193
* Retrieves all the agent names for all workspaces, including those that
181194
* are off. Meant to be used when configuring SSH.

‎src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.coder.gateway.sdk.v2.models.BuildInfo
44
import com.coder.gateway.sdk.v2.models.CreateWorkspaceBuildRequest
55
import com.coder.gateway.sdk.v2.models.Template
66
import com.coder.gateway.sdk.v2.models.User
7+
import com.coder.gateway.sdk.v2.models.Workspace
78
import com.coder.gateway.sdk.v2.models.WorkspaceBuild
89
import com.coder.gateway.sdk.v2.models.WorkspaceResource
910
import com.coder.gateway.sdk.v2.models.WorkspacesResponse
@@ -22,6 +23,15 @@ interface CoderV2RestFacade {
2223
@GET("api/v2/users/me")
2324
fun me(): Call<User>
2425

26+
/**
27+
* Retrieves a specific workspace by owner and name.
28+
*/
29+
@GET("api/v2/users/{user}/workspace/{workspace}")
30+
fun workspaceByOwnerAndName(
31+
@Path("user") user: String,
32+
@Path("workspace") workspace: String,
33+
): Call<Workspace>
34+
2535
/**
2636
* Retrieves all workspaces the authenticated user has access to.
2737
*/

‎src/main/kotlin/com/coder/gateway/util/LinkHandler.kt

+22-18
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,27 @@ open class LinkHandler(
5757
// owner is included, assume the current user.
5858
val owner = (parameters.owner() ?: client.me.username).ifBlank { client.me.username }
5959

60-
val workspaces = client.workspaces()
61-
val workspace =
62-
workspaces.firstOrNull {
63-
it.ownerName == owner && it.name == workspaceName
64-
} ?: throw IllegalArgumentException("The workspace $workspaceName does not exist")
60+
val cli =
61+
ensureCLI(
62+
deploymentURL.toURL(),
63+
client.buildInfo().version,
64+
settings,
65+
indicator,
66+
)
67+
68+
var workspace : Workspace
69+
var workspaces : List<Workspace> = emptyList()
70+
var workspacesAndAgents : Set<Pair<Workspace, WorkspaceAgent>> = emptySet()
71+
if (cli.features.wildcardSSH) {
72+
workspace = client.workspaceByOwnerAndName(owner, workspaceName)
73+
} else {
74+
workspaces = client.workspaces()
75+
workspace =
76+
workspaces.firstOrNull {
77+
it.ownerName == owner && it.name == workspaceName
78+
} ?: throw IllegalArgumentException("The workspace $workspaceName does not exist")
79+
workspacesAndAgents = client.withAgents(workspaces)
80+
}
6581

6682
when (workspace.latestBuild.status) {
6783
WorkspaceStatus.PENDING, WorkspaceStatus.STARTING ->
@@ -96,26 +112,14 @@ open class LinkHandler(
96112
throw IllegalArgumentException("The agent \"${agent.name}\" has a status of \"${status.toString().lowercase()}\"; unable to connect")
97113
}
98114

99-
val cli =
100-
ensureCLI(
101-
deploymentURL.toURL(),
102-
client.buildInfo().version,
103-
settings,
104-
indicator,
105-
)
106-
107115
// We only need to log in if we are using token-based auth.
108116
if (client.token != null) {
109117
indicator?.invoke("Authenticating Coder CLI...")
110118
cli.login(client.token)
111119
}
112120

113121
indicator?.invoke("Configuring Coder CLI...")
114-
if (cli.features.wildcardSSH) {
115-
cli.configSsh(workspacesAndAgents = emptySet(), currentUser = client.me)
116-
} else {
117-
cli.configSsh(workspacesAndAgents = client.withAgents(workspaces), currentUser = client.me)
118-
}
122+
cli.configSsh(workspacesAndAgents, currentUser = client.me)
119123

120124
val openDialog =
121125
parameters.ideProductCode().isNullOrBlank() ||

0 commit comments

Comments
 (0)