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

Test preview #19597

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
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
Prev Previous commit
Next Next commit
WIP: upgrade to latest version
  • Loading branch information
mustard-mh committed Jan 24, 2025
commit 4ba498710a912e32953d087f1f05d9b96317bd39
29 changes: 18 additions & 11 deletions components/ide/jetbrains/toolbox/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
# Gitpod Toolbox Plugin
# Gitpod Classic Toolbox Plugin

To load plugin into the provided Toolbox App, run `./gradlew build copyPlugin`
Provides a way to connect to Gitpod Classic workspaces within the JetBrains Toolbox App.

or put files in the following directory:
## How to Develop

* Windows: `%LocalAppData%/JetBrains/Toolbox/cache/plugins/plugin-id`
* macOS: `~/Library/Caches/JetBrains/Toolbox/plugins/plugin-id`
* Linux: `~/.local/share/JetBrains/Toolbox/plugins/plugin-id`
### Requires
- Java 21
- IntelliJ IDEA
- Toolbox App

### Steps
- Clone and open this project locally in IntelliJ IDEA
- Run the `./gradlew copyPlugin` task to build and copy the plugin into Toolbox's plugin directory
- Restart the Toolbox Application if needed (for macOS, it can restart by copyPlugin task)

## How to Develop
> To open the Toolbox App in debug mode
> ```bash
> TOOLBOX_DEV_DEBUG_SUSPEND=true && open /Applications/JetBrains\ Toolbox.app
> ```

## Install Plugin manually

- Open the Toolbox App in debug mode
```bash
TOOLBOX_DEV_DEBUG_SUSPEND=true && open /Applications/JetBrains\ Toolbox.app
```
If you download the plugin from the summary of GitHub Actions, you will need to install it manually. More details can be found [here (internal notes)](https://www.notion.so/gitpod/WIP-Experiment-Toolbox-gateway-feature-with-Gitpod-Classic-14c6425f2d52800297bbf98b88842ac7).
2 changes: 0 additions & 2 deletions components/ide/jetbrains/toolbox/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -5,8 +5,6 @@
import com.github.jk1.license.filter.ExcludeTransitiveDependenciesFilter
import com.github.jk1.license.render.JsonReportRenderer
import org.jetbrains.intellij.pluginRepository.PluginRepositoryFactory
import org.jetbrains.intellij.pluginRepository.model.LicenseUrl
import org.jetbrains.intellij.pluginRepository.model.ProductFamily
import org.jetbrains.kotlin.com.intellij.openapi.util.SystemInfoRt
import java.nio.file.Path
import kotlin.io.path.div
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[versions]
gateway = "2.5.0.32871"
#gateway = "2.4.0.31544"
gateway = "2.6.0.34606"
kotlin = "1.9.0"
coroutines = "1.7.3"
serialization = "1.5.0"
Original file line number Diff line number Diff line change
@@ -158,7 +158,7 @@ class GitpodAuthManager {
val bearerToken = getBearerToken(oAuthToken)
val client = GitpodPublicApiManager.createClient(URI(gitpodHost).host, bearerToken)
val user = GitpodPublicApiManager.tryGetAuthenticatedUser(UserServiceClient(client))
GitpodAccount(bearerToken, user.id, user.name, gitpodHost)
GitpodAccount(bearerToken, user.id, user.name, gitpodHost, authScopesJetBrainsToolbox)
}
}

@@ -186,18 +186,21 @@ class GitpodAccount : Account {
private val id: String
private val name: String
private val host: String
private val scopes: List<String>

constructor(credentials: String, id: String, name: String, host: String) {
constructor(credentials: String, id: String, name: String, host: String, scopes: List<String>) {
this.credentials = credentials
this.id = id
this.name = name
this.host = URI(host).host
this.scopes = scopes
}

override fun getId() = id
override fun getFullName() = name
fun getCredentials() = credentials
fun getHost() = host
fun getScopes() = scopes

fun encode(): String {
return Json.encodeToString(this)
@@ -214,6 +217,7 @@ class GitpodAccount : Account {
GitpodLogger.debug("validating account $host")
try {
GitpodPublicApiManager.tryGetAuthenticatedUser(UserServiceClient(client))
// TODO: Verify scopes
return true
} catch (e: ConnectException) {
// TODO(hw): Server close jsonrpc so papi server respond internal error
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ package io.gitpod.toolbox.auth

import com.jetbrains.toolbox.gateway.ui.*
import io.gitpod.toolbox.components.AbstractUiPage
import io.gitpod.toolbox.components.GitpodIcon
import io.gitpod.toolbox.components.GitpodIconColored
import io.gitpod.toolbox.components.SimpleButton
import io.gitpod.toolbox.service.Utils

@@ -33,11 +33,11 @@ class GitpodLoginPage(private val authManager: GitpodAuthManager) : AbstractUiPa
})
}

override fun getTitle() = "Login to Gitpod"
override fun getTitle() = "Log in to Gitpod Classic"

override fun getDescription() = "Always ready to code."

override fun getSvgIcon(): ByteArray {
return GitpodIcon()
return GitpodIconColored()
}
}
Original file line number Diff line number Diff line change
@@ -10,13 +10,18 @@ import java.util.function.BiConsumer
import java.util.function.Function

abstract class AbstractUiPage : UiPage {
private var stateGetter: Function<UiField, *>? = null
private var stateAccessor: UiPage.UiFieldStateAccessor? = null

@Suppress("UNCHECKED_CAST")
fun <T> getFieldValue(field: UiField) = stateGetter?.apply(field) as T?
fun <T> getFieldValue(field: UiField) = stateAccessor?.get(field) as T?

override fun setStateAccessor(setter: BiConsumer<UiField, Any>?, getter: Function<UiField, *>?) {
super.setStateAccessor(setter, getter)
stateGetter = getter
override fun setStateAccessor(stateAccessor: UiPage.UiFieldStateAccessor?) {
super.setStateAccessor(stateAccessor)
this.stateAccessor = stateAccessor
}
}

class EmptyUiPageWithTitle(private val title: String) : UiPage {
override fun getFields(): MutableList<UiField> = mutableListOf()
override fun getTitle() = title
}
Original file line number Diff line number Diff line change
@@ -10,3 +10,8 @@ import io.gitpod.toolbox.gateway.GitpodGatewayExtension
fun GitpodIcon(): ByteArray {
return GitpodGatewayExtension::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf()
}

@Suppress("FunctionName")
fun GitpodIconColored(): ByteArray {
return GitpodGatewayExtension::class.java.getResourceAsStream("/icon-colored.svg")?.readAllBytes() ?: byteArrayOf()
}
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import com.jetbrains.toolbox.gateway.ui.UiPage
import io.gitpod.publicapi.experimental.v1.Workspaces
import io.gitpod.toolbox.auth.GitpodAuthManager
import io.gitpod.toolbox.auth.GitpodLoginPage
import io.gitpod.toolbox.components.EmptyUiPageWithTitle
import io.gitpod.toolbox.components.GitpodIcon
import io.gitpod.toolbox.components.SimpleButton
import io.gitpod.toolbox.service.*
@@ -63,13 +64,15 @@ class GitpodRemoteProvider(
consumer.consumeEnvironments(environmentMap.values.map { it.second })
}
val joinLinkInfo = workspace!!.fetchJoinLink2Info(publicApi.getWorkspaceOwnerToken(workspaceId))
Utils.clientHelper.prepareClient(joinLinkInfo.ideVersion)
Utils.clientHelper.setAutoConnectOnEnvironmentReady(workspaceId, joinLinkInfo.ideVersion, joinLinkInfo.projectPath)
}

private fun showWorkspacesList() {
Utils.coroutineScope.launch {
val workspaces = publicApi.listWorkspaces()
if (workspaces.isEmpty()) {
consumer.consumeEnvironments(emptyList())
return@launch
}
consumer.consumeEnvironments(workspaces.map {
@@ -120,10 +123,10 @@ class GitpodRemoteProvider(

override fun close() {}

override fun getName(): String = "Gitpod"
override fun getName(): String = "Gitpod Classic"
override fun getSvgIcon() = GitpodIcon()

override fun getNewEnvironmentUiPage() = UiPage.empty
override fun getNewEnvironmentUiPage() = EmptyUiPageWithTitle("")

override fun getAccountDropDown(): AccountDropdownField? {
val account = authManger.getCurrentAccount() ?: return null
@@ -138,11 +141,11 @@ class GitpodRemoteProvider(
Utils.openUrl("https://gitpod.io/docs")
},
)

}

override fun canCreateNewEnvironments(): Boolean = false
override fun isSingleEnvironment(): Boolean = false
override fun getNoEnvironmentsDescription() = "No workspaces"

override fun setVisible(visibilityState: ProviderVisibilityState) {}

Original file line number Diff line number Diff line change
@@ -6,7 +6,12 @@ package io.gitpod.toolbox.gateway

import com.jetbrains.toolbox.gateway.AbstractRemoteProviderEnvironment
import com.jetbrains.toolbox.gateway.EnvironmentVisibilityState
import com.jetbrains.toolbox.gateway.deploy.CommandExecution
import com.jetbrains.toolbox.gateway.deploy.HostAccessInterfaces
import com.jetbrains.toolbox.gateway.deploy.HostCommandExecutor
import com.jetbrains.toolbox.gateway.deploy.HostFileAccessor
import com.jetbrains.toolbox.gateway.environments.EnvironmentContentsView
import com.jetbrains.toolbox.gateway.environments.HostAccessCapableEnvironmentContentsView
import com.jetbrains.toolbox.gateway.states.EnvironmentStateConsumer
import com.jetbrains.toolbox.gateway.states.StandardRemoteEnvironmentState
import com.jetbrains.toolbox.gateway.ui.ActionDescription
@@ -82,6 +87,10 @@ class GitpodRemoteProviderEnvironment(

override fun getActionList(): ObservableList<ActionDescription> = actionList

override fun onDelete() {
watchWorkspaceJob?.cancel()
}

override fun dispose() {
watchWorkspaceJob?.cancel()
}
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@

package io.gitpod.toolbox.gateway

import com.jetbrains.toolbox.gateway.environments.CachedIdeStub
import com.jetbrains.toolbox.gateway.environments.CachedProjectStub
import com.jetbrains.toolbox.gateway.environments.ManualEnvironmentContentsView
import com.jetbrains.toolbox.gateway.environments.SshEnvironmentContentsView
import com.jetbrains.toolbox.gateway.ssh.SshConnectionInfo
@@ -34,6 +36,30 @@ class GitpodSSHEnvironmentContentsView(

override fun addEnvironmentContentsListener(p0: ManualEnvironmentContentsView.Listener) {
stateListeners += p0
stateListeners.forEach{
it.onProjectListUpdated(listOf(object : CachedProjectStub {
override fun getPath(): String {
return "/workspace/template-golang-cli"
}

override fun getName(): String? {
return "template-golang-cli"
}

override fun getIdeHint(): String? {
return "GO-243.21565.208"
}
}))
it.onIdeListUpdated(listOf(object: CachedIdeStub {
override fun getProductCode(): String {
return "GO-243.21565.208"
}

override fun isRunning(): Boolean? {
return true
}
}))
}
}

override fun removeEnvironmentContentsListener(p0: ManualEnvironmentContentsView.Listener) {
Original file line number Diff line number Diff line change
@@ -2,14 +2,35 @@
"id": "io.gitpod.toolbox.gateway",
"version": "0.0.1",
"meta": {
"readableName": "Gitpod plugin",
"description": "Gitpod CDE(Cloud Development Environment) integration into JetBrains Toolbox App",
"vendor": "Toolbox + Gateway",
"readableName": "Gitpod Classic",
"description": "Provides a way to connect to Gitpod Classic workspaces",
"vendor": "Gitpod",
"url": "https://github.com/gitpod-io/gitpod",
"backgroundColors": {
"start": { "hex": "#FFB45B", "opacity": 0.7 },
"top": { "hex": "#FFB45B", "opacity": 0.6 },
"end": { "hex": "#FFB45B", "opacity": 0.8 }
"left": {
"light": { "hex": "#FFB45B", "opacity": 0.7 },
"dark": { "hex": "#2C0735", "opacity": 0.8 }
},
"topLarge": {
"light": { "hex": "#FFB45B", "opacity": 0.6 },
"dark": { "hex": "#FF8C42", "opacity": 0.5 }
},
"bottom": {
"light": { "hex": "#FFB45B", "opacity": 0.3 },
"dark": { "hex": "#2C0735", "opacity": 0.8 }
},
"topSmall": {
"light": { "hex": "#FFB6C1", "opacity": 0.6 },
"dark": { "hex": "#FF1493", "opacity": 0.3 }
},
"rightLarge": {
"light": { "hex": "#FFB6C1", "opacity": 0.3 },
"dark": { "hex": "#371340", "opacity": 0.6 }
},
"rightSmall": {
"light": { "hex": "#FFB45B", "opacity": 0.9 },
"dark": { "hex": "#FF69B4", "opacity": 0.2 }
}
}
},
"apiVersion": "0.1.0",
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.