From 9266dc48c76cc89ccd57c64fb33a23c835409793 Mon Sep 17 00:00:00 2001 From: Pudong Zheng Date: Mon, 7 Feb 2022 08:40:29 +0000 Subject: [PATCH] allow user select eap version of JetBrains IDE --- chart/templates/_helpers.tpl | 7 +++ chart/templates/server-ide-configmap.yaml | 4 ++ .../dashboard/src/settings/Preferences.tsx | 24 +++++++--- .../gitpod-protocol/src/ide-protocol.ts | 5 +++ components/gitpod-protocol/src/protocol.ts | 1 + components/server/src/ide-config.ts | 15 +++++++ .../server/src/workspace/workspace-starter.ts | 5 ++- .../pkg/components/server/ide/configmap.go | 44 ++++++++++--------- installer/pkg/components/server/ide/types.go | 1 + 9 files changed, 79 insertions(+), 27 deletions(-) diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl index 43951935c9106a..7e8f42c1586e9d 100644 --- a/chart/templates/_helpers.tpl +++ b/chart/templates/_helpers.tpl @@ -310,6 +310,13 @@ registry.{{ .Values.hostname }} {{ template "gitpod.comp.imageRepo" . }}:{{- template "gitpod.comp.version" . -}} {{- end -}} +{{- define "gitpod.comp.imageLatest" -}} +{{- $ := .root -}} +{{- $gp := .gp -}} +{{- $comp := .comp -}} +{{ template "gitpod.comp.imageRepo" . }}:latest +{{- end -}} + {{- define "gitpod.comp.configMap" -}} {{- $comp := .comp -}} {{ $comp.configMapName | default (printf "%s-config" $comp.name) }} diff --git a/chart/templates/server-ide-configmap.yaml b/chart/templates/server-ide-configmap.yaml index 831ee3728df866..8eabddebdd9701 100644 --- a/chart/templates/server-ide-configmap.yaml +++ b/chart/templates/server-ide-configmap.yaml @@ -79,24 +79,28 @@ options: type: "desktop" logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/intellijIdeaLogo.svg" image: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.intellij)) }} + latestImage: {{ (include "gitpod.comp.imageLatest" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.intellij)) }} goland: orderKey: "05" title: "GoLand" type: "desktop" logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/golandLogo.svg" image: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.goland)) }} + latestImage: {{ (include "gitpod.comp.imageLatest" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.goland)) }} pycharm: orderKey: "06" title: "PyCharm" type: "desktop" logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/pycharmLogo.svg" image: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.pycharm)) }} + latestImage: {{ (include "gitpod.comp.imageLatest" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.pycharm)) }} phpstorm: orderKey: "07" title: "PhpStorm" type: "desktop" logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/phpstormLogo.svg" image: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.phpstorm)) }} + latestImage: {{ (include "gitpod.comp.imageLatest" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.phpstorm)) }} defaultIde: "code" defaultDesktopIde: "code-desktop" diff --git a/components/dashboard/src/settings/Preferences.tsx b/components/dashboard/src/settings/Preferences.tsx index 468adbf99e564f..882ffe76d8e554 100644 --- a/components/dashboard/src/settings/Preferences.tsx +++ b/components/dashboard/src/settings/Preferences.tsx @@ -17,6 +17,7 @@ import { UserContext } from "../user-context"; import settingsMenu from "./settings-menu"; import IDENone from '../icons/IDENone.svg'; import IDENoneDark from '../icons/IDENoneDark.svg'; +import CheckBox from "../components/CheckBox"; type Theme = 'light' | 'dark' | 'system'; @@ -33,7 +34,7 @@ export default function Preferences() { const { user } = useContext(UserContext); const { setIsDark, isDark } = useContext(ThemeContext); - const updateUserIDEInfo = async (defaultDesktopIde: string, defaultIde: string) => { + const updateUserIDEInfo = async (defaultDesktopIde: string, defaultIde: string, useLatestVersion: boolean) => { const useDesktopIde = defaultDesktopIde !== DesktopNoneId; const desktopIde = useDesktopIde ? defaultDesktopIde : undefined; const additionalData = user?.additionalData ?? {}; @@ -41,13 +42,15 @@ export default function Preferences() { settings.useDesktopIde = useDesktopIde; settings.defaultIde = defaultIde; settings.defaultDesktopIde = desktopIde; + settings.useLatestVersion = useLatestVersion; additionalData.ideSettings = settings; getGitpodService().server.trackEvent({ event: "ide_configuration_changed", properties: { useDesktopIde, defaultIde, - defaultDesktopIde: desktopIde + defaultDesktopIde: desktopIde, + useLatestVersion, }, }).then().catch(console.error); await getGitpodService().server.updateLoggedInUser({ additionalData }); @@ -55,16 +58,23 @@ export default function Preferences() { const [defaultIde, setDefaultIde] = useState(user?.additionalData?.ideSettings?.defaultIde || ""); const actuallySetDefaultIde = async (value: string) => { - await updateUserIDEInfo(defaultDesktopIde, value); + await updateUserIDEInfo(defaultDesktopIde, value, useLatestVersion); setDefaultIde(value); } const [defaultDesktopIde, setDefaultDesktopIde] = useState((user?.additionalData?.ideSettings?.useDesktopIde && user?.additionalData?.ideSettings?.defaultDesktopIde) || DesktopNoneId); const actuallySetDefaultDesktopIde = async (value: string) => { - await updateUserIDEInfo(value, defaultIde); + await updateUserIDEInfo(value, defaultIde, useLatestVersion); setDefaultDesktopIde(value); } + const [useLatestVersion, setUseLatestVersion] = useState(user?.additionalData?.ideSettings?.useLatestVersion ?? false); + const actuallySetUseLatestVersion = async (value: boolean) => { + await updateUserIDEInfo(defaultDesktopIde, defaultIde, value); + setUseLatestVersion(value); + } + + const [ideOptions, setIdeOptions] = useState(undefined); useEffect(() => { (async () => { @@ -124,7 +134,10 @@ export default function Preferences() { } } {desktopIdeOptions && <> -

Desktop Editor Beta

+

+ Desktop Editor + Beta +

Optionally, choose the default desktop editor for opening workspaces.

{ @@ -147,6 +160,7 @@ export default function Preferences() { The JetBrains desktop IDEs are currently in beta. Send feedback ยท Documentation

} + actuallySetUseLatestVersion(e.target.checked)}/> }

Theme

Early bird or night owl? Choose your side.

diff --git a/components/gitpod-protocol/src/ide-protocol.ts b/components/gitpod-protocol/src/ide-protocol.ts index 6e3c9980932670..db88d325ca7fd0 100644 --- a/components/gitpod-protocol/src/ide-protocol.ts +++ b/components/gitpod-protocol/src/ide-protocol.ts @@ -102,6 +102,11 @@ export interface IDEOption { */ image: string; + /** + * The latest image ref to the IDE image, this image ref always resolve to digest. + */ + latestImage?: string; + /** * When this is `true`, the tag of this image is resolved to the latest * image digest regularly. diff --git a/components/gitpod-protocol/src/protocol.ts b/components/gitpod-protocol/src/protocol.ts index 07e8a97f970164..2768b2955f2029 100644 --- a/components/gitpod-protocol/src/protocol.ts +++ b/components/gitpod-protocol/src/protocol.ts @@ -119,6 +119,7 @@ export type IDESettings = { defaultIde?: string useDesktopIde?: boolean defaultDesktopIde?: string + useLatestVersion?: boolean } export interface UserPlatform { diff --git a/components/server/src/ide-config.ts b/components/server/src/ide-config.ts index aa1911209f1a0d..0897ee950a07dd 100644 --- a/components/server/src/ide-config.ts +++ b/components/server/src/ide-config.ts @@ -45,6 +45,7 @@ const scheme = { "nodes": { "type": "array", "items": { "type": "string" } }, "hidden": { "type": "boolean" }, "image": { "type": "string" }, + "latestImage": { "type": "string" }, "resolveImageDigest": { "type": "boolean" }, }, "required": [ @@ -190,6 +191,20 @@ export class IDEConfigService { } } + for (const [id, option] of Object.entries(newValue.ideOptions.options).filter(([_, x]) => x.latestImage)) { + try { + value.ideOptions.options[id].latestImage = await this.resolveImageDigest(option.latestImage!); + log.info("ide config: successfully resolved latest image digest", { + ide: id, + latestImage: option.latestImage, + resolvedImage: value.ideOptions.options[id].latestImage, + trigger, + }); + } catch (e) { + log.error('ide config: error while resolving latest image digest', e, { trigger }); + } + } + const key = JSON.stringify(value); if (key === this.state.key) { return; diff --git a/components/server/src/workspace/workspace-starter.ts b/components/server/src/workspace/workspace-starter.ts index 4105646f28dd75..82b896216a91cb 100644 --- a/components/server/src/workspace/workspace-starter.ts +++ b/components/server/src/workspace/workspace-starter.ts @@ -334,9 +334,10 @@ export class WorkspaceStarter { } } + const useLatest = !!user.additionalData?.ideSettings?.useLatestVersion; const referrerIde = this.resolveReferrerIDE(workspace, user, ideConfig); if (referrerIde) { - configuration.desktopIdeImage = referrerIde.option.image; + configuration.desktopIdeImage = useLatest ? (referrerIde.option.latestImage ?? referrerIde.option.image) : referrerIde.option.image if (!user.additionalData?.ideSettings) { // A user does not have IDE settings configured yet configure it with a referrer ide as default. const additionalData = user?.additionalData || {}; @@ -356,7 +357,7 @@ export class WorkspaceStarter { if (!!desktopIdeChoice) { const mappedImage = ideConfig.ideOptions.options[desktopIdeChoice]; if (!!mappedImage && mappedImage.image) { - configuration.desktopIdeImage = mappedImage.image; + configuration.desktopIdeImage = useLatest ? (mappedImage.latestImage ?? mappedImage.image) : mappedImage.image } else if (this.authService.hasPermission(user, "ide-settings")) { // if the IDE choice isn't one of the preconfiured choices, we assume its the image name. // For now, this feature requires special permissions. diff --git a/installer/pkg/components/server/ide/configmap.go b/installer/pkg/components/server/ide/configmap.go index 95d3d602c31dec..7664e8b51a7ca9 100644 --- a/installer/pkg/components/server/ide/configmap.go +++ b/installer/pkg/components/server/ide/configmap.go @@ -92,32 +92,36 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) { Image: common.ImageName(ctx.Config.Repository, ide.CodeDesktopInsidersIDEImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.CodeDesktopImageInsiders.Version), }, intellij: { - OrderKey: pointer.String("04"), - Title: "IntelliJ IDEA", - Type: typeDesktop, - Logo: getIdeLogoPath("intellijIdeaLogo"), - Image: common.ImageName(ctx.Config.Repository, ide.IntelliJDesktopIDEImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.IntelliJImage.Version), + OrderKey: pointer.String("04"), + Title: "IntelliJ IDEA", + Type: typeDesktop, + Logo: getIdeLogoPath("intellijIdeaLogo"), + Image: common.ImageName(ctx.Config.Repository, ide.IntelliJDesktopIDEImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.IntelliJImage.Version), + LatestImage: common.ImageName(ctx.Config.Repository, ide.IntelliJDesktopIDEImage, "latest"), }, goland: { - OrderKey: pointer.String("05"), - Title: "GoLand", - Type: typeDesktop, - Logo: getIdeLogoPath("golandLogo"), - Image: common.ImageName(ctx.Config.Repository, ide.GoLandDesktopIdeImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.GoLandImage.Version), + OrderKey: pointer.String("05"), + Title: "GoLand", + Type: typeDesktop, + Logo: getIdeLogoPath("golandLogo"), + Image: common.ImageName(ctx.Config.Repository, ide.GoLandDesktopIdeImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.GoLandImage.Version), + LatestImage: common.ImageName(ctx.Config.Repository, ide.GoLandDesktopIdeImage, "latest"), }, pycharm: { - OrderKey: pointer.String("06"), - Title: "PyCharm", - Type: typeDesktop, - Logo: getIdeLogoPath("pycharmLogo"), - Image: common.ImageName(ctx.Config.Repository, ide.PyCharmDesktopIdeImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.PyCharmImage.Version), + OrderKey: pointer.String("06"), + Title: "PyCharm", + Type: typeDesktop, + Logo: getIdeLogoPath("pycharmLogo"), + Image: common.ImageName(ctx.Config.Repository, ide.PyCharmDesktopIdeImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.PyCharmImage.Version), + LatestImage: common.ImageName(ctx.Config.Repository, ide.PyCharmDesktopIdeImage, "latest"), }, phpstorm: { - OrderKey: pointer.String("07"), - Title: "PhpStorm", - Type: typeDesktop, - Logo: getIdeLogoPath("phpstormLogo"), - Image: common.ImageName(ctx.Config.Repository, ide.PhpStormDesktopIdeImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.PhpStormImage.Version), + OrderKey: pointer.String("07"), + Title: "PhpStorm", + Type: typeDesktop, + Logo: getIdeLogoPath("phpstormLogo"), + Image: common.ImageName(ctx.Config.Repository, ide.PhpStormDesktopIdeImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.PhpStormImage.Version), + LatestImage: common.ImageName(ctx.Config.Repository, ide.PhpStormDesktopIdeImage, "latest"), }, }, DefaultIDE: "code", diff --git a/installer/pkg/components/server/ide/types.go b/installer/pkg/components/server/ide/types.go index 68114a7b1312d8..d0e2d11be76ea4 100644 --- a/installer/pkg/components/server/ide/types.go +++ b/installer/pkg/components/server/ide/types.go @@ -31,6 +31,7 @@ type IDEOption struct { Notes []string `json:"notes,omitempty"` Hidden *bool `json:"hidden,omitempty"` Image string `json:"image"` + LatestImage string `json:"latestImage,omitempty"` ResolveImageDigest *bool `json:"resolveImageDigest,omitempty"` }