Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitabdf6d8

Browse files
authored
impl: add support for matching agent by name (#146)
This PR adds support for matching workspace agent in the URI via the`agent_name` query param. The existing support for `agent_id` is droppedand replaced by the new param.
1 parent1a2212b commitabdf6d8

File tree

5 files changed

+82
-88
lines changed

5 files changed

+82
-88
lines changed

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@
66

77
- support for basic authentication for HTTP/HTTPS proxy
88
- support for Toolbox 2.7 release
9+
- support for matching workspace agent in the URI via the agent name
910

1011
###Changed
1112

1213
- improved message while loading the workspace
1314

15+
###Removed
16+
17+
- dropped support for`agent_id` as a URI parameter
18+
1419
###Fixed
1520

1621
- URI protocol handler is now able to switch to the Coder provider even if the last opened provider was something else

‎README.md‎

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ You can use specially crafted JetBrains Gateway URIs to automatically:
6464
###Example URIs
6565

6666
```text
67-
jetbrains://gateway/com.coder.toolbox?url=https%3A%2F%2Fdev.coder.com&token=zeoX4SbSpP-j2qGpajkdwxR9jBdcekXS2&workspace=bobiverse-bob&agent=dev&ide_product_code=GO&ide_build_number=241.23774.119&folder=%2Fhome%2Fcoder%2Fworkspace%2Fhello-world-rs
67+
jetbrains://gateway/com.coder.toolbox?url=https%3A%2F%2Fdev.coder.com&token=zeoX4SbSpP-j2qGpajkdwxR9jBdcekXS2&workspace=bobiverse-bob&agent_name=dev&ide_product_code=GO&ide_build_number=241.23774.119&folder=%2Fhome%2Fcoder%2Fworkspace%2Fhello-world-rs
6868
69-
jetbrains://gateway/com.coder.toolbox?url=https%3A%2F%2Fj5gj2r1so5nbi.pit-1.try.coder.app%2F&token=gqEirOoI1U-FfCQ6uj8iOLtybBIk99rr8&workspace=bobiverse-riker&agent=dev&ide_product_code=RR&ide_build_number=243.26053.17&folder=%2Fhome%2Fcoder%2Fworkspace%2Fhello-world-rs
69+
jetbrains://gateway/coder?url=https%3A%2F%2Fj5gj2r1so5nbi.pit-1.try.coder.app%2F&token=gqEirOoI1U-FfCQ6uj8iOLtybBIk99rr8&workspace=bobiverse-riker&agent_name=dev&ide_product_code=RR&ide_build_number=243.26053.17&folder=%2Fhome%2Fcoder%2Fworkspace%2Fhello-world-rs
7070
```
7171

7272
###URI Breakdown
@@ -76,13 +76,15 @@ jetbrains://gateway/com.coder.toolbox
7676
?url=http(s)://<your-coder-deployment>
7777
&token=<auth-token>
7878
&workspace=<workspace-name>
79-
&agent_id=<agent--id>
79+
&agent_name=<agent-name>
8080
&ide_product_code=<IDE-code>
8181
&ide_build_number=<IDE-build>
8282
&folder=<absolute-path-to-a-project-folder>
8383
```
8484

85-
Starting from Toolbox 2.7, you can use`coder` as a shortcut in place of the full plugin ID. The URI can be simplified as:
85+
Starting from Toolbox 2.7, you can use`coder` as a shortcut in place of the full plugin ID. The URI can be simplified
86+
as:
87+
8688
```text
8789
jetbrains://gateway/coder?url=http(s)://<your-coder-deployment>
8890
```
@@ -92,16 +94,16 @@ jetbrains://gateway/coder?url=http(s)://<your-coder-deployment>
9294
| url| Your Coder deployment URL (encoded)| Yes|
9395
| token| Coder authentication token| Yes|
9496
| workspace| Name of the Coder workspace to connect to.| Yes|
95-
|agent_id|IDof the agentassociatedwith the workspace| No|
97+
|agent_name|The nameof the agent with the workspace| No|
9698
| ide_product_code| JetBrains IDE product code (e.g., GO for GoLand, RR for Rider)| No|
9799
| ide_build_number| Specific build number of the JetBrains IDE to install on the workspace| No|
98100
| folder| Absolute path to the project folder to open in the remote IDE (URL-encoded)| No|
99101

100102
>[!NOTE]
101-
>If only a single agent is available, specifying an agentID is optional. However, if multiple agents exist,
102-
>you mustprovideeitherthe ID to target a specific one. Note that this version of the Coder Toolbox plugin
103-
>does not automatically start agents if they are offline, so please ensure the selected agent is running before
104-
>proceeding.
103+
>If only a single agent is available, specifying an agentname is optional. However, if multiple agents exist, you must
104+
>provide the
105+
>agent name. Note that this version of the Coder Toolbox plugin does not automatically start agents if they
106+
>are offline, so please ensure the selected agent is running beforeproceeding.
105107
106108
If`ide_product_code` and`ide_build_number` is missing, Toolbox will only open and highlight the workspace environment
107109
page. Coder Toolbox will attempt to start the workspace if it’s not already running; however, for the most reliable
@@ -151,7 +153,9 @@ mitmweb --ssl-insecure --set stream_large_bodies="10m" --mode socks5
151153
>[!NOTE]
152154
>Coder Toolbox plugin handles only HTTP/HTTPS proxy authentication.
153155
>SOCKS5 proxy authentication is currently not supported due to limitations
154-
>described in:https://youtrack.jetbrains.com/issue/TBX-14532/Missing-proxy-authentication-settings#focus=Comments-27-12265861.0-0
156+
>described
157+
>
158+
in:https://youtrack.jetbrains.com/issue/TBX-14532/Missing-proxy-authentication-settings#focus=Comments-27-12265861.0-0
155159

156160
##Debugging and Reporting issues
157161

@@ -198,56 +202,56 @@ storage paths. The options can be configured from the plugin's main Workspaces p
198202
###CLI related settings
199203

200204
-`Binary source` specifies the source URL or relative path from which the Coder CLI should be downloaded.
201-
If a relative path is provided, it is resolved against the deployment domain.
205+
If a relative path is provided, it is resolved against the deployment domain.
202206

203207
-`Enable downloads` allows automatic downloading of the CLI if the current version is missing or outdated.
204208

205209
-`Binary directory` specifies the directory where CLI binaries are stored. If omitted, it defaults to the data
206-
directory.
210+
directory.
207211

208212
-`Enable binary directory fallback` if enabled, falls back to the data directory when the specified binary
209-
directory is not writable.
213+
directory is not writable.
210214

211215
-`Data directory` directory where plugin-specific data such as session tokens and binaries are stored if not
212-
overridden by the binary directory setting.
216+
overridden by the binary directory setting.
213217

214218
-`Header command` command that outputs additional HTTP headers. Each line of output must be in the format key=value.
215-
The environment variable CODER_URL will be available to the command process.
219+
The environment variable CODER_URL will be available to the command process.
216220

217221
###TLS settings
218222

219223
The following options control the secure communication behavior of the plugin with Coder deployment and its available
220224
API.
221225

222226
-`TLS cert path` path to a client certificate file for TLS authentication with Coder deployment.
223-
The certificate should be in X.509 PEM format.
227+
The certificate should be in X.509 PEM format.
224228

225229
-`TLS key path` path to the private key corresponding to the TLS certificate from above.
226-
The certificate should be in X.509 PEM format.
230+
The certificate should be in X.509 PEM format.
227231

228232
-`TLS CA path` the path of a file containing certificates for an alternate certificate authority used to verify TLS
229-
certs returned by the Coder deployment. The file should be in X.509 PEM format. This option can also be used to verify
230-
proxy certificates.
233+
certs returned by the Coder deployment. The file should be in X.509 PEM format. This option can also be used to verify
234+
proxy certificates.
231235

232236
-`TLS alternate hostname` overrides the hostname used in TLS verification. This is useful when the hostname
233-
used to connect to the Coder deployment does not match the hostname in the TLS certificate.
237+
used to connect to the Coder deployment does not match the hostname in the TLS certificate.
234238

235239
###SSH settings
236240

237241
The following options control the SSH behavior of the Coder CLI.
238242

239243
-`Disable autostart` adds the --disable-autostart flag to the SSH proxy command, preventing the CLI from keeping
240-
workspaces constantly active.
244+
workspaces constantly active.
241245

242246
-`Enable SSH wildcard config` enables or disables wildcard entries in the SSH configuration, which allow generic
243-
rules for matching multiple workspaces.
247+
rules for matching multiple workspaces.
244248

245249
-`SSH proxy log directory` directory where SSH proxy logs are written. Useful for debugging SSH connection issues.
246250

247251
-`SSH network metrics directory` directory where network information used by the SSH proxy is stored.
248252

249253
-`Extra SSH options` additional options appended to the SSH configuration. Can be used to customize the behavior of
250-
SSH connections.
254+
SSH connections.
251255

252256
###Saving Changes
253257

@@ -256,7 +260,7 @@ support, may trigger regeneration of SSH configurations.
256260

257261
###Security considerations
258262

259-
>[!IMPORTANT]
263+
>[!IMPORTANT]
260264
>Token authentication is required when TLS certificates are not configured.
261265
262266
##Releasing
@@ -269,6 +273,7 @@ support, may trigger regeneration of SSH configurations.
269273
JetBrains enabled auto-approval for the plugin, so we need to ensure we continue to meet the following requirements:
270274
- do**not** use Kotlin experimental APIs.
271275
- do**not** add any lambdas, handlers, or class handles to Java runtime hooks.
272-
- do**not** create threads manually (including via libraries). If you must, ensure they are properly cleaned up in the plugin's`CoderRemoteProvider#close()` method.
276+
- do**not** create threads manually (including via libraries). If you must, ensure they are properly cleaned up in
277+
the plugin's`CoderRemoteProvider#close()` method.
273278
- do**not** bundle libraries that are already provided by Toolbox.
274279
- do**not** perform any ill-intentioned actions.

‎src/main/kotlin/com/coder/toolbox/util/CoderProtocolHandler.kt‎

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -258,26 +258,25 @@ open class CoderProtocolHandler(
258258
}
259259

260260
// If the agent is missing and the workspace has only one, use that.
261-
val agent=
262-
if (!parameters.agentID().isNullOrBlank()) {
263-
agents.firstOrNull { it.id.toString()== parameters.agentID() }
264-
}elseif (agents.size==1) {
265-
agents.first()
266-
}else {
267-
null
268-
}
261+
val agent=if (!parameters.agentName().isNullOrBlank()) {
262+
agents.firstOrNull { it.name== parameters.agentName() }
263+
}elseif (agents.size==1) {
264+
agents.first()
265+
}else {
266+
null
267+
}
269268

270269
if (agent==null) {
271-
if (!parameters.agentID().isNullOrBlank()) {
270+
if (!parameters.agentName().isNullOrBlank()) {
272271
context.logAndShowError(
273272
CAN_T_HANDLE_URI_TITLE,
274-
"The workspace\"${workspace.name}\" does not have an agent withID\"${parameters.agentID()}\""
273+
"The workspace\"${workspace.name}\" does not have an agent withname\"${parameters.agentName()}\""
275274
)
276275
returnnull
277276
}else {
278277
context.logAndShowError(
279278
CAN_T_HANDLE_URI_TITLE,
280-
"Unable to determine which agent to connect to;\"$AGENT_ID\" must be set because the workspace\"${workspace.name}\" has more than one agent"
279+
"Unable to determine which agent to connect to;\"$AGENT_NAME\" must be set because the workspace\"${workspace.name}\" has more than one agent"
281280
)
282281
returnnull
283282
}

‎src/main/kotlin/com/coder/toolbox/util/LinkMap.kt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.coder.toolbox.util
33
constvalURL="url"
44
constvalTOKEN="token"
55
constvalWORKSPACE="workspace"
6-
constvalAGENT_ID="agent_id"
6+
constvalAGENT_NAME="agent_name"
77
privateconstvalIDE_PRODUCT_CODE="ide_product_code"
88
privateconstvalIDE_BUILD_NUMBER="ide_build_number"
99
privateconstvalFOLDER="folder"
@@ -14,7 +14,7 @@ fun Map<String, String>.token() = this[TOKEN]
1414

1515
funMap<String,String>.workspace()=this[WORKSPACE]
1616

17-
funMap<String,String?>.agentID()=this[AGENT_ID]
17+
funMap<String,String?>.agentName()=this[AGENT_NAME]
1818

1919
funMap<String,String>.ideProductCode()=this[IDE_PRODUCT_CODE]
2020

‎src/test/kotlin/com/coder/toolbox/util/CoderProtocolHandlerTest.kt‎

Lines changed: 35 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import io.mockk.mockk
1818
importkotlinx.coroutines.CoroutineScope
1919
importkotlinx.coroutines.flow.MutableStateFlow
2020
importkotlinx.coroutines.runBlocking
21+
importorg.junit.jupiter.api.DisplayName
2122
importjava.util.UUID
2223
importkotlin.test.Test
2324
importkotlin.test.assertEquals
@@ -47,40 +48,34 @@ internal class CoderProtocolHandlerTest {
4748

4849
privateval agents=
4950
mapOf(
50-
"agent_name_3" to"b0e4c54d-9ba9-4413-8512-11ca1e826a24",
51-
"agent_name_2" to"fb3daea4-da6b-424d-84c7-36b90574cfef",
52-
"agent_name" to"9a920eee-47fb-4571-9501-e4b3120c12f2",
51+
"agent_name_bob" to"b0e4c54d-9ba9-4413-8512-11ca1e826a24",
52+
"agent_name_bill" to"fb3daea4-da6b-424d-84c7-36b90574cfef",
53+
"agent_name_riker" to"9a920eee-47fb-4571-9501-e4b3120c12f2",
5354
)
54-
privatevaloneAgent=
55+
privatevalagentBob=
5556
mapOf(
56-
"agent_name_3" to"b0e4c54d-9ba9-4413-8512-11ca1e826a24",
57+
"agent_name_bob" to"b0e4c54d-9ba9-4413-8512-11ca1e826a24",
5758
)
5859

5960
@Test
60-
funtstgetMatchingAgent() {
61+
@DisplayName("given a ws with multiple agents, expect the correct agent to be resolved if it matches the agent_name query param")
62+
fungetMatchingAgent() {
6163
val ws=DataGen.workspace("ws", agents= agents)
6264

6365
val tests=
6466
listOf(
6567
Pair(
66-
mapOf("agent_id" to"9a920eee-47fb-4571-9501-e4b3120c12f2"),
68+
mapOf("agent_name" to"agent_name_riker"),
6769
"9a920eee-47fb-4571-9501-e4b3120c12f2"
6870
),
6971
Pair(
70-
mapOf("agent_id" to"fb3daea4-da6b-424d-84c7-36b90574cfef"),
72+
mapOf("agent_name" to"agent_name_bill"),
7173
"fb3daea4-da6b-424d-84c7-36b90574cfef"
7274
),
7375
Pair(
74-
mapOf("agent_id" to"b0e4c54d-9ba9-4413-8512-11ca1e826a24"),
76+
mapOf("agent_name" to"agent_name_bob"),
7577
"b0e4c54d-9ba9-4413-8512-11ca1e826a24"
76-
),
77-
// Prefer agent_id.
78-
Pair(
79-
mapOf(
80-
"agent_id" to"b0e4c54d-9ba9-4413-8512-11ca1e826a24",
81-
),
82-
"b0e4c54d-9ba9-4413-8512-11ca1e826a24",
83-
),
78+
)
8479
)
8580
runBlocking {
8681
tests.forEach {
@@ -90,28 +85,20 @@ internal class CoderProtocolHandlerTest {
9085
}
9186

9287
@Test
88+
@DisplayName("given a ws with only multiple agents expect the agent resolution to fail if none match the agent_name query param")
9389
funfailsToGetMatchingAgent() {
9490
val ws=DataGen.workspace("ws", agents= agents)
9591
val tests=
9692
listOf(
9793
Triple(emptyMap(),MissingArgumentException::class,"Unable to determine"),
98-
Triple(mapOf("agent_id" to""),MissingArgumentException::class,"Unable to determine"),
99-
Triple(mapOf("agent_id" tonull),MissingArgumentException::class,"Unable to determine"),
100-
Triple(mapOf("agent_id" to"not-a-uuid"),IllegalArgumentException::class,"agent with ID"),
94+
Triple(mapOf("agent_name" to""),MissingArgumentException::class,"Unable to determine"),
95+
Triple(mapOf("agent_name" tonull),MissingArgumentException::class,"Unable to determine"),
96+
Triple(mapOf("agent_name" to"not-an-agent-name"),IllegalArgumentException::class,"agent with ID"),
10197
Triple(
102-
mapOf("agent_id" to"ceaa7bcf-1612-45d7-b484-2e0da9349168"),
98+
mapOf("agent_name" to"agent_name_homer"),
10399
IllegalArgumentException::class,
104-
"agent with ID"
105-
),
106-
// Will ignore agent if agent_id is set even if agent matches.
107-
Triple(
108-
mapOf(
109-
"agent" to"agent_name",
110-
"agent_id" to"ceaa7bcf-1612-45d7-b484-2e0da9349168",
111-
),
112-
IllegalArgumentException::class,
113-
"agent with ID",
114-
),
100+
"agent with name"
101+
)
115102
)
116103
runBlocking {
117104
tests.forEach {
@@ -121,15 +108,14 @@ internal class CoderProtocolHandlerTest {
121108
}
122109

123110
@Test
111+
@DisplayName("given a ws with only one agent, the agent is selected even when agent_name query param was not provided")
124112
fungetsFirstAgentWhenOnlyOne() {
125-
val ws=DataGen.workspace("ws", agents=oneAgent)
113+
val ws=DataGen.workspace("ws", agents=agentBob)
126114
val tests=
127115
listOf(
128116
emptyMap(),
129-
mapOf("agent" to""),
130-
mapOf("agent_id" to""),
131-
mapOf("agent" tonull),
132-
mapOf("agent_id" tonull),
117+
mapOf("agent_name" to""),
118+
mapOf("agent_name" tonull)
133119
)
134120
runBlocking {
135121
tests.forEach {
@@ -145,43 +131,42 @@ internal class CoderProtocolHandlerTest {
145131
}
146132

147133
@Test
134+
@DisplayName("given a ws with only one agent, the agent is NOT selected when agent_name query param was provided but does not match")
148135
funfailsToGetAgentWhenOnlyOne() {
149-
valws=DataGen.workspace("ws", agents=oneAgent)
136+
valwsWithAgentBob=DataGen.workspace("ws", agents=agentBob)
150137
val tests=
151138
listOf(
152139
Triple(
153-
mapOf("agent_id" to"ceaa7bcf-1612-45d7-b484-2e0da9349168"),
140+
mapOf("agent_name" to"agent_name_garfield"),
154141
IllegalArgumentException::class,
155-
"agent withID"
142+
"agent withname"
156143
),
157144
)
158145
runBlocking {
159146
tests.forEach {
160-
assertNull(protocolHandler.getMatchingAgent(it.first,ws)?.id)
147+
assertNull(protocolHandler.getMatchingAgent(it.first,wsWithAgentBob))
161148
}
162149
}
163150
}
164151

165152
@Test
166-
funfailsToGetAgentWithoutAgents() {
167-
val ws=DataGen.workspace("ws")
153+
@DisplayName("fails to resolve any agent when the workspace has no agents")
154+
funfailsToGetAgentWhenWorkspaceHasNoAgents() {
155+
val wsWithoutAgents=DataGen.workspace("ws")
168156
val tests=
169157
listOf(
170158
Triple(emptyMap(),IllegalArgumentException::class,"has no agents"),
171-
Triple(mapOf("agent" to""),IllegalArgumentException::class,"has no agents"),
172-
Triple(mapOf("agent_id" to""),IllegalArgumentException::class,"has no agents"),
173-
Triple(mapOf("agent" tonull),IllegalArgumentException::class,"has no agents"),
174-
Triple(mapOf("agent_id" tonull),IllegalArgumentException::class,"has no agents"),
175-
Triple(mapOf("agent" to"agent_name"),IllegalArgumentException::class,"has no agents"),
159+
Triple(mapOf("agent_name" to""),IllegalArgumentException::class,"has no agents"),
160+
Triple(mapOf("agent_name" tonull),IllegalArgumentException::class,"has no agents"),
176161
Triple(
177-
mapOf("agent_id" to"9a920eee-47fb-4571-9501-e4b3120c12f2"),
162+
mapOf("agent_name" to"agent_name_riker"),
178163
IllegalArgumentException::class,
179164
"has no agents"
180165
),
181166
)
182167
runBlocking {
183168
tests.forEach {
184-
assertNull(protocolHandler.getMatchingAgent(it.first,ws)?.id)
169+
assertNull(protocolHandler.getMatchingAgent(it.first,wsWithoutAgents))
185170
}
186171
}
187172
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp