Skip to content
Closed
Show file tree
Hide file tree
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
63 changes: 63 additions & 0 deletions components/gitpod-cli/cmd/jetbrains-gradle-pause.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package cmd

import (
"os"

"github.com/spf13/cobra"
)

// Note: This location is used on GradleSyncListener.kt
// https://github.com/gitpod-io/gitpod/blob/5317b915e409968af72bd857aa69b3ebf10b6698/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/listeners/GradleSyncListener.kt#L24
const gradleSyncLockFile = "/tmp/gitpod-gradle.lock"

var jetbrainsGradlePauseCmd = &cobra.Command{
Use: "pause",
Short: "Pause JetBrains' builtin automatic Gradle Sync",
Long: `Pause JetBrains' builtin automatic Gradle Sync to prevent performance issues on Gitpod workspace startup when there's no Prebuilds ready.

This command is typically used to prevent concurrent Gradle syncs between:
- Manual gradle initialization in Gitpod init tasks
- JetBrains IDEs' (IDEA) automatic Gradle sync on project open

Typical usage in your .gitpod.yml:

tasks:
- init: |
gp jetbrains gradle pause # Prevent JetBrains' auto gradle sync at beginning
...
./gradlew <init_service> # Run your initialization tasks
gp jetbrains gradle resume # Enable
command: ./gradlew <dev_service>

If you have two init tasks want to pause Gradle Sync:

tasks:
- name: Task 1
init: |
gp jetbrains gradle pause # Prevent JetBrains' auto gradle sync
./gradlew <init_service>
gp sync-await gradle-init-1
gp jetbrains gradle resume # Enable
- name: Task 2
init: |
./gradlew <init_service>
gp sync-done gradle-init-1
- name: Task 3
command: echo hi there
`,
RunE: func(cmd *cobra.Command, args []string) error {
err := os.WriteFile(gradleSyncLockFile, []byte{}, 0644)
if err != nil && os.IsExist(err) {
return nil
}
return err
},
}

func init() {
jetbrainsGradleCmd.AddCommand(jetbrainsGradlePauseCmd)
}
27 changes: 27 additions & 0 deletions components/gitpod-cli/cmd/jetbrains-gradle-resume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package cmd

import (
"os"

"github.com/spf13/cobra"
)

var jetbrainsGradleResumeCmd = &cobra.Command{
Use: "resume",
Short: "Resume paused Gradle Sync",
RunE: func(cmd *cobra.Command, args []string) error {
err := os.Remove(gradleSyncLockFile)
if err != nil && os.IsNotExist(err) {
return nil
}
return err
},
}

func init() {
jetbrainsGradleCmd.AddCommand(jetbrainsGradleResumeCmd)
}
18 changes: 18 additions & 0 deletions components/gitpod-cli/cmd/jetbrains-gradle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package cmd

import (
"github.com/spf13/cobra"
)

var jetbrainsGradleCmd = &cobra.Command{
Use: "gradle",
Short: "Interact with JetBrains Gradle services.",
}

func init() {
jetbrainsCmd.AddCommand(jetbrainsGradleCmd)
}
19 changes: 19 additions & 0 deletions components/gitpod-cli/cmd/jetbrains.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package cmd

import (
"github.com/spf13/cobra"
)

var jetbrainsCmd = &cobra.Command{
Use: "jetbrains",
Aliases: []string{"jb"},
Short: "Interact with JetBrains editor.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Short: "Interact with JetBrains editor.",
Short: "Interact with JetBrains IDEs",

}

func init() {
rootCmd.AddCommand(jetbrainsCmd)
}
2 changes: 2 additions & 0 deletions components/ide/jetbrains/backend-plugin/BUILD.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ packages:
- NO_VERIFY_JB_PLUGIN=true
config:
commands:
- ["rm", "-rf", "src/main/kotlin/io/gitpod/jetbrains/remote/listeners/GradleSyncListener.kt"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need this line because the file exclude in build.gradle.kt somehow not working well. (And I don't want to investigate why)

- ["mv", "build.gradle-stable.kts", "build.gradle.kts"]
- ["./build.sh", "${__git_commit}"]
- name: plugin-latest-rider
Expand Down Expand Up @@ -182,6 +183,7 @@ packages:
- SDKMAN_DIR=/home/gitpod/.sdkman
config:
commands:
- ["rm", "-rf", "src/main/kotlin/io/gitpod/jetbrains/remote/listeners/GradleSyncListener.kt"]
# TODO(hw): remove after 2024.2.* is stable
- ["mv", "build.gradle-latest.kts", "build.gradle.kts"]
- - "bash"
Expand Down
1 change: 1 addition & 0 deletions components/ide/jetbrains/backend-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ project(":") {
if (properties("platformType") == "RD") {
print("Rider: exclude unnecessary files")
sourceSets["main"].kotlin.exclude("**/GitpodForceUpdateMavenProjectsActivity.kt")
sourceSets["main"].kotlin.exclude("**/GradleSyncListener.kt")
sourceSets["main"].kotlin.exclude("**/maven.xml")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package io.gitpod.jetbrains.remote.listeners

import com.intellij.notification.Notification
import com.intellij.notification.NotificationAction
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
import java.io.File

class GradleSyncListener : ExternalSystemTaskNotificationListener {
override fun onStart(id: ExternalSystemTaskId, workingDir: String?) {
if (id.projectSystemId.toString() != "GRADLE" || id.type != ExternalSystemTaskType.RESOLVE_PROJECT) {
return
}
// Note: This file is written by the GP CLI
// https://github.com/gitpod-io/gitpod/blob/5317b915e409968af72bd857aa69b3ebf10b6698/components/gitpod-cli/cmd/jetbrains-gradle-pause.go#L1
val lockFile = File("/tmp/gitpod-gradle.lock")
if (!lockFile.exists()) {
return
}

val notification = Notification(
"gitpod",
"Gitpod: Pause gradle sync",
"Pausing Gradle Sync, execute <code style='color: orange;'>gp jetbrains gradle resume</code> to unblock all builtin Gradle Sync",
Comment on lines +33 to +34
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Gitpod: Pause gradle sync",
"Pausing Gradle Sync, execute <code style='color: orange;'>gp jetbrains gradle resume</code> to unblock all builtin Gradle Sync",
"Gitpod: Gradle sync is paused",
"JetBrains' built-in Gradle sync is paused, execute <code style='color: orange;'>gp jetbrains gradle resume</code> to unblock it",

NotificationType.INFORMATION
)
var isCancelled = false
notification.addAction(object : NotificationAction("Cancel") {
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
isCancelled = true
notification.expire()
}
})
Comment on lines +38 to +43
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this actually cancel the sync? It looks more like it just dismisses the notification. If so, let's rename it to Dismiss. I definitely could be missing something though.

Notifications.Bus.notify(notification)

while (lockFile.exists()) {
if (isCancelled) {
thisLogger().warn("gitpod: gradle sync pausing is cancelled")
break
}
Thread.sleep(1000)
}
thisLogger().warn("gitpod: gradle sync pausing finished")
ApplicationManager.getApplication().invokeLater {
notification.expire()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
<applicationService serviceInterface="io.gitpod.jetbrains.remote.GitpodIgnoredPortsForNotificationService"
serviceImplementation="io.gitpod.jetbrains.remote.internal.GitpodIgnoredPortsForNotificationServiceImpl"
preload="true"/>

<externalSystemTaskNotificationListener
implementation="io.gitpod.jetbrains.remote.listeners.GradleSyncListener"/>
</extensions>

<actions>
Expand Down
Loading