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

Commit79118e3

Browse files
authored
fix: skip installed EAP, RC, NIGHTLY and PREVIEW ides from showing if they are superseded (#548)
* chore: build and test with newer Gateway versionThe existing EAP snapshot was removed from the repo* fix: skip installed EAP, RC, NIGHTLY and PREVIEW ides from showing if they are supersededThe IDE and Project view will no longer show IDEs that are installed and which are not yet released, butthey have a released version available for download.* impl: add UTs for installed IDEs filtering
1 parent39a2942 commit79118e3

File tree

5 files changed

+461
-47
lines changed

5 files changed

+461
-47
lines changed

‎CHANGELOG.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66

77
###Changed
88

9-
Retrieve workspace directly in link handler when using wildcardSSH feature
9+
- Retrieve workspace directly in link handler when using wildcardSSH feature
10+
11+
###Fixed
12+
13+
- installed EAP, RC, NIGHTLY and PREVIEW IDEs are no longer displayed if there is a higher released version available for download.
1014

1115
##2.19.0 - 2025-02-21
1216

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pluginUntilBuild=251.*
2626
# that exists, ideally the most recent one, for example
2727
# 233.15325-EAP-CANDIDATE-SNAPSHOT).
2828
platformType=GW
29-
platformVersion=233.15619-EAP-CANDIDATE-SNAPSHOT
29+
platformVersion=241.19416-EAP-CANDIDATE-SNAPSHOT
3030
instrumentationCompiler=243.15521-EAP-CANDIDATE-SNAPSHOT
3131
# Gateway does not have open sources.
3232
platformDownloadSources=true

‎src/main/kotlin/com/coder/gateway/models/WorkspaceProjectIDE.kt‎

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import com.jetbrains.gateway.ssh.IdeStatus
66
importcom.jetbrains.gateway.ssh.IdeWithStatus
77
importcom.jetbrains.gateway.ssh.InstalledIdeUIEx
88
importcom.jetbrains.gateway.ssh.IntelliJPlatformProduct
9+
importcom.jetbrains.gateway.ssh.ReleaseType
910
importcom.jetbrains.gateway.ssh.deploy.ShellArgument
1011
importjava.net.URL
1112
importjava.nio.file.Path
1213
importkotlin.io.path.name
1314

15+
privatevalNON_STABLE_RELEASE_TYPES=setOf("EAP","RC","NIGHTLY","PREVIEW")
16+
1417
/**
1518
* Validated parameters for downloading and opening a project using an IDE on a
1619
* workspace.
@@ -101,7 +104,8 @@ class WorkspaceProjectIDE(
101104
name= name,
102105
hostname= hostname,
103106
projectPath= projectPath,
104-
ideProduct=IntelliJPlatformProduct.fromProductCode(ideProductCode)?:throwException("invalid product code"),
107+
ideProduct=IntelliJPlatformProduct.fromProductCode(ideProductCode)
108+
?:throwException("invalid product code"),
105109
ideBuildNumber= ideBuildNumber,
106110
idePathOnHost= idePathOnHost,
107111
downloadSource= downloadSource,
@@ -126,13 +130,13 @@ fun RecentWorkspaceConnection.toWorkspaceProjectIDE(): WorkspaceProjectIDE {
126130
// connections page, so it could be missing. Try to get it from the
127131
// host name.
128132
name=
129-
if (name.isNullOrBlank()&&!hostname.isNullOrBlank()) {
130-
hostname
131-
.removePrefix("coder-jetbrains--")
132-
.removeSuffix("--${hostname.split("--").last()}")
133-
}else {
134-
name
135-
},
133+
if (name.isNullOrBlank()&&!hostname.isNullOrBlank()) {
134+
hostname
135+
.removePrefix("coder-jetbrains--")
136+
.removeSuffix("--${hostname.split("--").last()}")
137+
}else {
138+
name
139+
},
136140
hostname= hostname,
137141
projectPath= projectPath,
138142
ideProductCode= ideProductCode,
@@ -146,17 +150,17 @@ fun RecentWorkspaceConnection.toWorkspaceProjectIDE(): WorkspaceProjectIDE {
146150
// the config directory). For backwards compatibility with existing
147151
// entries, extract the URL from the config directory or host name.
148152
deploymentURL=
149-
if (deploymentURL.isNullOrBlank()) {
150-
if (!dir.isNullOrBlank()) {
151-
"https://${Path.of(dir).parent.name}"
152-
}elseif (!hostname.isNullOrBlank()) {
153-
"https://${hostname.split("--").last()}"
153+
if (deploymentURL.isNullOrBlank()) {
154+
if (!dir.isNullOrBlank()) {
155+
"https://${Path.of(dir).parent.name}"
156+
}elseif (!hostname.isNullOrBlank()) {
157+
"https://${hostname.split("--").last()}"
158+
}else {
159+
deploymentURL
160+
}
154161
}else {
155162
deploymentURL
156-
}
157-
}else {
158-
deploymentURL
159-
},
163+
},
160164
lastOpened= lastOpened,
161165
)
162166
}
@@ -195,6 +199,39 @@ fun AvailableIde.toIdeWithStatus(): IdeWithStatus = IdeWithStatus(
195199
remoteDevType= remoteDevType,
196200
)
197201

202+
/**
203+
* Returns a list of installed IDEs that don't have a RELEASED version available for download.
204+
* Typically, installed EAP, RC, nightly or preview builds should be superseded by released versions.
205+
*/
206+
fun List<InstalledIdeUIEx>.filterOutAvailableReleasedIdes(availableIde:List<AvailableIde>):List<InstalledIdeUIEx> {
207+
val availableReleasedByProductCode= availableIde
208+
.filter { it.releaseType==ReleaseType.RELEASE }
209+
.groupBy { it.product.productCode }
210+
val result= mutableListOf<InstalledIdeUIEx>()
211+
212+
this.forEach { installedIde->
213+
// installed IDEs have the release type embedded in the presentable version
214+
// which is a string in the form: 2024.2.4 NIGHTLY
215+
if (NON_STABLE_RELEASE_TYPES.any { itin installedIde.presentableVersion }) {
216+
// we can show the installed IDe if there isn't a higher released version available for download
217+
if (installedIde.isSNotSupersededBy(availableReleasedByProductCode[installedIde.product.productCode])) {
218+
result.add(installedIde)
219+
}
220+
}else {
221+
result.add(installedIde)
222+
}
223+
}
224+
225+
return result
226+
}
227+
228+
privatefun InstalledIdeUIEx.isSNotSupersededBy(availableIdes:List<AvailableIde>?):Boolean {
229+
if (availableIdes.isNullOrEmpty()) {
230+
returntrue
231+
}
232+
return!availableIdes.any { it.buildNumber>=this.buildNumber }
233+
}
234+
198235
/**
199236
* Convert an installed IDE to an IDE with status.
200237
*/

‎src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt‎

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.coder.gateway.CoderGatewayBundle
44
importcom.coder.gateway.cli.CoderCLIManager
55
importcom.coder.gateway.icons.CoderIcons
66
importcom.coder.gateway.models.WorkspaceProjectIDE
7+
importcom.coder.gateway.models.filterOutAvailableReleasedIdes
78
importcom.coder.gateway.models.toIdeWithStatus
89
importcom.coder.gateway.models.withWorkspaceProject
910
importcom.coder.gateway.sdk.v2.models.Workspace
@@ -82,9 +83,12 @@ import javax.swing.SwingConstants
8283
importjavax.swing.event.DocumentEvent
8384

8485
// Just extracting the way we display the IDE info into a helper function.
85-
privatefundisplayIdeWithStatus(ideWithStatus:IdeWithStatus):String="${ideWithStatus.product.productCode}${ideWithStatus.presentableVersion}${ideWithStatus.buildNumber} |${ideWithStatus.status.name.lowercase(
86-
Locale.getDefault(),
87-
)}"
86+
privatefundisplayIdeWithStatus(ideWithStatus:IdeWithStatus):String=
87+
"${ideWithStatus.product.productCode}${ideWithStatus.presentableVersion}${ideWithStatus.buildNumber} |${
88+
ideWithStatus.status.name.lowercase(
89+
Locale.getDefault(),
90+
)
91+
}"
8892

8993
/**
9094
* View for a single workspace. In particular, show available IDEs and a button
@@ -222,12 +226,21 @@ class CoderWorkspaceProjectIDEStepView(
222226
cbIDE.renderer=
223227
if (attempt>1) {
224228
IDECellRenderer(
225-
CoderGatewayBundle.message("gateway.connector.view.coder.connect-ssh.retry", attempt),
229+
CoderGatewayBundle.message(
230+
"gateway.connector.view.coder.connect-ssh.retry",
231+
attempt
232+
),
226233
)
227234
}else {
228235
IDECellRenderer(CoderGatewayBundle.message("gateway.connector.view.coder.connect-ssh"))
229236
}
230-
val executor= createRemoteExecutor(CoderCLIManager(data.client.url).getBackgroundHostName(data.workspace, data.client.me, data.agent))
237+
val executor= createRemoteExecutor(
238+
CoderCLIManager(data.client.url).getBackgroundHostName(
239+
data.workspace,
240+
data.client.me,
241+
data.agent
242+
)
243+
)
231244

232245
if (ComponentValidator.getInstance(tfProject).isEmpty) {
233246
logger.info("Installing remote path validator...")
@@ -238,7 +251,10 @@ class CoderWorkspaceProjectIDEStepView(
238251
cbIDE.renderer=
239252
if (attempt>1) {
240253
IDECellRenderer(
241-
CoderGatewayBundle.message("gateway.connector.view.coder.retrieve-ides.retry", attempt),
254+
CoderGatewayBundle.message(
255+
"gateway.connector.view.coder.retrieve-ides.retry",
256+
attempt
257+
),
242258
)
243259
}else {
244260
IDECellRenderer(CoderGatewayBundle.message("gateway.connector.view.coder.retrieve-ides"))
@@ -247,9 +263,9 @@ class CoderWorkspaceProjectIDEStepView(
247263
},
248264
retryIf= {
249265
itisConnectionException||
250-
itisTimeoutException||
251-
itisSSHException||
252-
itisDeployException
266+
itisTimeoutException||
267+
itisSSHException||
268+
itisDeployException
253269
},
254270
onException= { attempt, nextMs, e->
255271
logger.error("Failed to retrieve IDEs (attempt$attempt; will retry in$nextMs ms)")
@@ -311,7 +327,10 @@ class CoderWorkspaceProjectIDEStepView(
311327
* Validate the remote path whenever it changes.
312328
*/
313329
privatefuninstallRemotePathValidator(executor:HighLevelHostAccessor) {
314-
val disposable=Disposer.newDisposable(ApplicationManager.getApplication(),CoderWorkspaceProjectIDEStepView::class.java.name)
330+
val disposable=Disposer.newDisposable(
331+
ApplicationManager.getApplication(),
332+
CoderWorkspaceProjectIDEStepView::class.java.name
333+
)
315334
ComponentValidator(disposable).installOn(tfProject)
316335

317336
tfProject.document.addDocumentListener(
@@ -324,7 +343,12 @@ class CoderWorkspaceProjectIDEStepView(
324343
val isPathPresent= validateRemotePath(tfProject.text, executor)
325344
if (isPathPresent.pathOrNull==null) {
326345
ComponentValidator.getInstance(tfProject).ifPresent {
327-
it.updateInfo(ValidationInfo("Can't find directory:${tfProject.text}", tfProject))
346+
it.updateInfo(
347+
ValidationInfo(
348+
"Can't find directory:${tfProject.text}",
349+
tfProject
350+
)
351+
)
328352
}
329353
}else {
330354
ComponentValidator.getInstance(tfProject).ifPresent {
@@ -333,7 +357,12 @@ class CoderWorkspaceProjectIDEStepView(
333357
}
334358
}catch (e:Exception) {
335359
ComponentValidator.getInstance(tfProject).ifPresent {
336-
it.updateInfo(ValidationInfo("Can't validate directory:${tfProject.text}", tfProject))
360+
it.updateInfo(
361+
ValidationInfo(
362+
"Can't validate directory:${tfProject.text}",
363+
tfProject
364+
)
365+
)
337366
}
338367
}
339368
}
@@ -377,27 +406,34 @@ class CoderWorkspaceProjectIDEStepView(
377406
}
378407

379408
logger.info("Resolved OS and Arch for$name is:$workspaceOS")
380-
val installedIdesJob=
381-
cs.async(Dispatchers.IO) {
382-
executor.getInstalledIDEs().map { it.toIdeWithStatus()}
383-
}
384-
val idesWithStatusJob=
385-
cs.async(Dispatchers.IO) {
386-
IntelliJPlatformProduct.entries
387-
.filter { it.showInGateway}
388-
.flatMap {CachingProductsJsonWrapper.getInstance().getAvailableIdes(it, workspaceOS) }
389-
.map { it.toIdeWithStatus() }
390-
}
409+
val installedIdesJob= cs.async(Dispatchers.IO) {
410+
executor.getInstalledIDEs()
411+
}
412+
val availableToDownloadIdesJob= cs.async(Dispatchers.IO) {
413+
IntelliJPlatformProduct.entries
414+
.filter { it.showInGateway }
415+
.flatMap {CachingProductsJsonWrapper.getInstance().getAvailableIdes(it, workspaceOS) }
416+
}
417+
418+
val installedIdes= installedIdesJob.await()
419+
val availableIdes= availableToDownloadIdesJob.await()
391420

392-
val installedIdes= installedIdesJob.await().sorted()
393-
val idesWithStatus= idesWithStatusJob.await().sorted()
394421
if (installedIdes.isEmpty()) {
395422
logger.info("No IDE is installed in$name")
396423
}
397-
if (idesWithStatus.isEmpty()) {
424+
if (availableIdes.isEmpty()) {
398425
logger.warn("Could not resolve any IDE for$name, probably$workspaceOS is not supported by Gateway")
399426
}
400-
return installedIdes+ idesWithStatus
427+
428+
val remainingInstalledIdes= installedIdes.filterOutAvailableReleasedIdes(availableIdes)
429+
if (remainingInstalledIdes.size< installedIdes.size) {
430+
logger.info(
431+
"Skipping the following list of installed IDEs because there is already a released version"+
432+
"available for download:${(installedIdes- remainingInstalledIdes).joinToString {"${it.product.productCode}${it.presentableVersion}" }}"
433+
)
434+
}
435+
return remainingInstalledIdes.map { it.toIdeWithStatus() }.sorted()+ availableIdes.map { it.toIdeWithStatus() }
436+
.sorted()
401437
}
402438

403439
privatefuntoDeployedOS(
@@ -455,7 +491,8 @@ class CoderWorkspaceProjectIDEStepView(
455491
overridefungetSelectedItem():IdeWithStatus?=super.getSelectedItem()asIdeWithStatus?
456492
}
457493

458-
privateclassIDECellRenderer(message:String,cellIcon:Icon =AnimatedIcon.Default.INSTANCE) : ListCellRenderer<IdeWithStatus> {
494+
privateclassIDECellRenderer(message:String,cellIcon:Icon =AnimatedIcon.Default.INSTANCE) :
495+
ListCellRenderer<IdeWithStatus> {
459496
privateval loadingComponentRenderer:ListCellRenderer<IdeWithStatus>=
460497
object:ColoredListCellRenderer<IdeWithStatus>() {
461498
overridefuncustomizeCellRenderer(

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp