Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrieve workspace directly in link handler when using wildcardSSH feature #542

Merged
merged 3 commits into from
Mar 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -4,6 +4,10 @@

## Unreleased

### Changed

Retrieve workspace directly in link handler when using wildcardSSH feature

## 2.19.0 - 2025-02-21

### Added
13 changes: 13 additions & 0 deletions src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt
Original file line number Diff line number Diff line change
@@ -176,6 +176,19 @@ open class CoderRestClient(
return workspacesResponse.body()!!.workspaces
}

/**
* Retrieves a specific workspace by owner and name.
* @throws [APIResponseException].
*/
fun workspaceByOwnerAndName(owner: String, workspaceName: String): Workspace {
val workspaceResponse = retroRestClient.workspaceByOwnerAndName(owner, workspaceName).execute()
if (!workspaceResponse.isSuccessful) {
throw APIResponseException("retrieve workspace", url, workspaceResponse)
}

return workspaceResponse.body()!!
}

/**
* Retrieves all the agent names for all workspaces, including those that
* are off. Meant to be used when configuring SSH.
10 changes: 10 additions & 0 deletions src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import com.coder.gateway.sdk.v2.models.BuildInfo
import com.coder.gateway.sdk.v2.models.CreateWorkspaceBuildRequest
import com.coder.gateway.sdk.v2.models.Template
import com.coder.gateway.sdk.v2.models.User
import com.coder.gateway.sdk.v2.models.Workspace
import com.coder.gateway.sdk.v2.models.WorkspaceBuild
import com.coder.gateway.sdk.v2.models.WorkspaceResource
import com.coder.gateway.sdk.v2.models.WorkspacesResponse
@@ -22,6 +23,15 @@ interface CoderV2RestFacade {
@GET("api/v2/users/me")
fun me(): Call<User>

/**
* Retrieves a specific workspace by owner and name.
*/
@GET("api/v2/users/{user}/workspace/{workspace}")
fun workspaceByOwnerAndName(
@Path("user") user: String,
@Path("workspace") workspace: String,
): Call<Workspace>

/**
* Retrieves all workspaces the authenticated user has access to.
*/
40 changes: 22 additions & 18 deletions src/main/kotlin/com/coder/gateway/util/LinkHandler.kt
Original file line number Diff line number Diff line change
@@ -57,11 +57,27 @@
// owner is included, assume the current user.
val owner = (parameters.owner() ?: client.me.username).ifBlank { client.me.username }

val workspaces = client.workspaces()
val workspace =
workspaces.firstOrNull {
it.ownerName == owner && it.name == workspaceName
} ?: throw IllegalArgumentException("The workspace $workspaceName does not exist")
val cli =
ensureCLI(
deploymentURL.toURL(),
client.buildInfo().version,
settings,
indicator,
)

var workspace : Workspace

Check warning on line 68 in src/main/kotlin/com/coder/gateway/util/LinkHandler.kt

GitHub Actions / Build

Local 'var' is never modified and can be declared as 'val'

Variable is never modified, so it can be declared using 'val'
var workspaces : List<Workspace> = emptyList()
var workspacesAndAgents : Set<Pair<Workspace, WorkspaceAgent>> = emptySet()
if (cli.features.wildcardSSH) {
workspace = client.workspaceByOwnerAndName(owner, workspaceName)
} else {
workspaces = client.workspaces()
workspace =
workspaces.firstOrNull {
it.ownerName == owner && it.name == workspaceName
} ?: throw IllegalArgumentException("The workspace $workspaceName does not exist")
workspacesAndAgents = client.withAgents(workspaces)
}

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

val cli =
ensureCLI(
deploymentURL.toURL(),
client.buildInfo().version,
settings,
indicator,
)

// We only need to log in if we are using token-based auth.
if (client.token != null) {
indicator?.invoke("Authenticating Coder CLI...")
cli.login(client.token)
}

indicator?.invoke("Configuring Coder CLI...")
if (cli.features.wildcardSSH) {
cli.configSsh(workspacesAndAgents = emptySet(), currentUser = client.me)
} else {
cli.configSsh(workspacesAndAgents = client.withAgents(workspaces), currentUser = client.me)
}
cli.configSsh(workspacesAndAgents, currentUser = client.me)

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

Unchanged files with check annotations Beta

coderConfigPath.toString(),
"start",
"--yes",
workspaceOwner + "/" + workspaceName,

Check notice on line 487 in src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

GitHub Actions / Build

String concatenation that can be converted to string template

'String' concatenation can be converted to a template
)
private fun exec(vararg args: String): String {
/*
* This function returns the ssh-host-prefix used for Host entries.
*/
fun getHostPrefix(): String = "coder-jetbrains-${deploymentURL.safeHost()}"

Check notice on line 521 in src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

GitHub Actions / Build

Class member can have 'private' visibility

Function 'getHostPrefix' could be private
/**
* This function returns the ssh host name generated for connecting to the workspace.
}
// non-wildcard case
if (parts[0] == "coder-jetbrains") {
return hostname + "--bg"

Check notice on line 577 in src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

GitHub Actions / Build

String concatenation that can be converted to string template

'String' concatenation can be converted to a template
}
// wildcard case
parts[0] += "-bg"
init {
init()
title = CoderGatewayBundle.message("gateway.connector.view.coder.remoteproject.choose.text", CoderCLIManager.getWorkspaceParts(state.workspace, state.agent))

Check warning on line 41 in src/main/kotlin/com/coder/gateway/util/Dialogs.kt

GitHub Actions / Build

Incorrect string capitalization

String 'Choose IDE and project for workspace {0}' is not properly capitalized. It should have title capitalization
}
override fun show() {
)
// Check the provided setting to see if there's a default IDE to set.
val defaultIde = ides.find { it ->

Check notice on line 276 in src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt

GitHub Actions / Build

Redundant lambda arrow

Redundant lambda arrow
// Using contains on the displayable version of the ide means they can be as specific or as vague as they want
// CL 2023.3.6 233.15619.8 -> a specific Clion build
// CL 2023.3.6 -> a specific Clion version
}
private class WorkspaceVersionColumnInfo(columnName: String) : ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
override fun valueOf(workspace: WorkspaceAgentListModel?): String? = if (workspace == null) {

Check warning on line 913 in src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt

GitHub Actions / Build

Redundant nullable return type

'valueOf' always returns non-null type
"Unknown"
} else if (workspace.workspace.outdated) {
"Outdated"