mirror of https://github.com/harness/drone.git
feat: [CDE-563]: add intellij support (#3193)
* feat: [CDE-552]: fix lint * feat: [CDE-552]: wait for the ide to run * feat: [CDE-552}: fix lint * feat: [CDE-552}: address comments * feat: [CDE-552}: add support for arm and amd architecture * feat: [CDE-552}: fix lint * feat: [CDE-552}: fix build * Merge branch 'main' of https://git0.harness.io/l7B_kbSEQD2wjrM7PShm5w/PROD/Harness_Commons/gitness into CDE-563-intellij-support * feat: [CDE-552}: fix installation for intellij * feat: [CDE-552}: fix installation for intellij * feat: [CDE-552}: add install tools, setup and run scripts for intellij * add intellij support # Conflicts: # app/gitspace/infrastructure/trigger_infra_event.go # app/gitspace/orchestrator/utils/script_templates/setup_intellij.shBT-10437
parent
15f4adcbe0
commit
887379b94a
|
@ -37,7 +37,7 @@ import (
|
|||
const defaultResourceIdentifier = "default"
|
||||
|
||||
var (
|
||||
// errSecretRequiresParent if the user tries to create a secret without a parent space.
|
||||
// ErrGitspaceRequiresParent if the user tries to create a secret without a parent space.
|
||||
ErrGitspaceRequiresParent = usererror.BadRequest(
|
||||
"Parent space required - standalone gitspace are not supported.")
|
||||
)
|
||||
|
|
|
@ -17,6 +17,7 @@ package container
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
|
@ -197,8 +198,8 @@ func ExtractLifecycleCommands(actionType PostAction, devcontainerConfig types.De
|
|||
func ExtractIDECustomizations(
|
||||
ideService ide.IDE,
|
||||
devcontainerConfig types.DevcontainerConfig,
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
) map[gitspaceTypes.IDEArg]interface{} {
|
||||
var args = make(map[gitspaceTypes.IDEArg]interface{})
|
||||
if ideService.Type() == enum.IDETypeVSCodeWeb || ideService.Type() == enum.IDETypeVSCode {
|
||||
if devcontainerConfig.Customizations.ExtractVSCodeSpec() != nil {
|
||||
args[gitspaceTypes.VSCodeCustomizationArg] = *devcontainerConfig.Customizations.ExtractVSCodeSpec()
|
||||
|
@ -206,3 +207,29 @@ func ExtractIDECustomizations(
|
|||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func ExtractIDEDownloadURL(
|
||||
ideService ide.IDE,
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
) map[gitspaceTypes.IDEArg]interface{} {
|
||||
if ideService.Type() == enum.IDETypeIntellij {
|
||||
args[gitspaceTypes.IDEDownloadURLArg] = types.IntellijDownloadURL{
|
||||
Arm64: fmt.Sprintf(enum.IDEIntellijDownloadURLArm64Template, enum.IDEIntellijVer),
|
||||
Amd64: fmt.Sprintf(enum.IDEIntellijDownloadURLAmd64Template, enum.IDEIntellijVer),
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func ExtractIDEDirName(
|
||||
ideService ide.IDE,
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
) map[gitspaceTypes.IDEArg]interface{} {
|
||||
if ideService.Type() == enum.IDETypeIntellij {
|
||||
dirname := path.Join(".cache", "JetBrains", "RemoteDev", "dist", "intellij")
|
||||
args[gitspaceTypes.IDEDIRNameArg] = dirname
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
|
|
@ -560,8 +560,12 @@ func (e *EmbeddedDockerOrchestrator) buildSetupSteps(
|
|||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
// Run IDE setup
|
||||
args := ExtractIDECustomizations(ideService, resolvedRepoDetails.DevcontainerConfig)
|
||||
args := make(map[gitspaceTypes.IDEArg]interface{})
|
||||
args = ExtractIDECustomizations(ideService, resolvedRepoDetails.DevcontainerConfig, args)
|
||||
args[gitspaceTypes.IDERepoNameArg] = resolvedRepoDetails.RepoName
|
||||
args = ExtractIDEDownloadURL(ideService, args)
|
||||
args = ExtractIDEDirName(ideService, args)
|
||||
|
||||
return ideService.Setup(ctx, exec, args, gitspaceLogger)
|
||||
},
|
||||
StopOnFailure: true,
|
||||
|
@ -573,7 +577,10 @@ func (e *EmbeddedDockerOrchestrator) buildSetupSteps(
|
|||
exec *devcontainer.Exec,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
return ideService.Run(ctx, exec, nil, gitspaceLogger)
|
||||
args := make(map[gitspaceTypes.IDEArg]interface{})
|
||||
args[gitspaceTypes.IDERepoNameArg] = resolvedRepoDetails.RepoName
|
||||
args = ExtractIDEDirName(ideService, args)
|
||||
return ideService.Run(ctx, exec, args, gitspaceLogger)
|
||||
},
|
||||
StopOnFailure: true,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ide
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
func getIDEDownloadURL(
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
) (types.IntellijDownloadURL, error) {
|
||||
downloadURL, exists := args[gitspaceTypes.IDEDownloadURLArg]
|
||||
if !exists {
|
||||
return types.IntellijDownloadURL{}, fmt.Errorf("ide download url not found")
|
||||
}
|
||||
|
||||
downloadURLStr, ok := downloadURL.(types.IntellijDownloadURL)
|
||||
if !ok {
|
||||
return types.IntellijDownloadURL{}, fmt.Errorf("ide download url is not of type IntellijDownloadURL")
|
||||
}
|
||||
|
||||
return downloadURLStr, nil
|
||||
}
|
||||
|
||||
func getIDEDirName(args map[gitspaceTypes.IDEArg]interface{}) (string, error) {
|
||||
dirName, exists := args[gitspaceTypes.IDEDIRNameArg]
|
||||
if !exists {
|
||||
return "", fmt.Errorf("ide dirname not found")
|
||||
}
|
||||
|
||||
dirNameStr, ok := dirName.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("ide dirname is not of type string")
|
||||
}
|
||||
|
||||
return dirNameStr, nil
|
||||
}
|
||||
|
||||
func getRepoName(
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
) (string, error) {
|
||||
repoName, exists := args[gitspaceTypes.IDERepoNameArg]
|
||||
if !exists {
|
||||
return "", nil // No repo name found, nothing to do
|
||||
}
|
||||
|
||||
repoNameStr, ok := repoName.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("repo name is not of type string")
|
||||
}
|
||||
|
||||
return repoNameStr, nil
|
||||
}
|
|
@ -24,10 +24,11 @@ type Factory struct {
|
|||
ides map[enum.IDEType]IDE
|
||||
}
|
||||
|
||||
func NewFactory(vscode *VSCode, vscodeWeb *VSCodeWeb) Factory {
|
||||
func NewFactory(vscode *VSCode, vscodeWeb *VSCodeWeb, intellij *Intellij) Factory {
|
||||
ides := make(map[enum.IDEType]IDE)
|
||||
ides[enum.IDETypeVSCode] = vscode
|
||||
ides[enum.IDETypeVSCodeWeb] = vscodeWeb
|
||||
ides[enum.IDETypeIntellij] = intellij
|
||||
return Factory{ides: ides}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,11 @@ import (
|
|||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
const (
|
||||
templateSetupSSHServer string = "setup_ssh_server.sh"
|
||||
templateRunSSHServer string = "run_ssh_server.sh"
|
||||
)
|
||||
|
||||
type IDE interface {
|
||||
// Setup is responsible for doing all the operations for setting up the IDE in the container e.g. installation,
|
||||
// copying settings and configurations.
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ide
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/utils"
|
||||
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
var _ IDE = (*Intellij)(nil)
|
||||
|
||||
const (
|
||||
templateSetupIntellij string = "setup_intellij.sh"
|
||||
templateRunRemoteIDEIntellij string = "run_intellij.sh"
|
||||
)
|
||||
|
||||
type IntellijConfig struct {
|
||||
Port int
|
||||
}
|
||||
|
||||
type Intellij struct {
|
||||
config IntellijConfig
|
||||
}
|
||||
|
||||
func NewIntellijService(config *IntellijConfig) *Intellij {
|
||||
return &Intellij{config: *config}
|
||||
}
|
||||
|
||||
// Setup installs the SSH server inside the container.
|
||||
func (ij *Intellij) Setup(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
gitspaceLogger.Info("Installing ssh-server inside container")
|
||||
err := ij.setupSSHServer(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to setup SSH server: %w", err)
|
||||
}
|
||||
gitspaceLogger.Info("Successfully installed ssh-server")
|
||||
|
||||
gitspaceLogger.Info("Installing intelliJ IDE inside container")
|
||||
gitspaceLogger.Info("IDE setup output...")
|
||||
err = ij.setupIntellijIDE(ctx, exec, args, gitspaceLogger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to setup IntelliJ IDE: %w", err)
|
||||
}
|
||||
gitspaceLogger.Info("Successfully installed IntelliJ IDE")
|
||||
gitspaceLogger.Info("Successfully set up IDE inside container")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ij *Intellij) setupSSHServer(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
osInfoScript := utils.GetOSInfoScript()
|
||||
payload := gitspaceTypes.SetupSSHServerPayload{
|
||||
Username: exec.RemoteUser,
|
||||
AccessType: exec.AccessType,
|
||||
OSInfoScript: osInfoScript,
|
||||
}
|
||||
sshServerScript, err := utils.GenerateScriptFromTemplate(
|
||||
templateSetupSSHServer, &payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to setup ssh server from template %s: %w", templateSetupSSHServer, err)
|
||||
}
|
||||
err = exec.ExecuteCommandInHomeDirAndLog(ctx, sshServerScript, true, gitspaceLogger, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to setup SSH serverr: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ij *Intellij) setupIntellijIDE(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
payload := gitspaceTypes.SetupIntellijIDEPayload{
|
||||
Username: exec.RemoteUser,
|
||||
}
|
||||
|
||||
// get Download URL
|
||||
downloadURL, err := getIDEDownloadURL(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
payload.IdeDownloadURLArm64 = downloadURL.Arm64
|
||||
payload.IdeDownloadURLAmd64 = downloadURL.Amd64
|
||||
|
||||
// get DIR name
|
||||
dirName, err := getIDEDirName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
payload.IdeDirName = dirName
|
||||
|
||||
intellijIDEScript, err := utils.GenerateScriptFromTemplate(
|
||||
templateSetupIntellij, &payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to setup intellij idea from template %s: %w",
|
||||
templateSetupIntellij,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
err = exec.ExecuteCommandInHomeDirAndLog(ctx, intellijIDEScript,
|
||||
true, gitspaceLogger, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to setup intellij IDE: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run runs the SSH server inside the container.
|
||||
func (ij *Intellij) Run(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
gitspaceLogger.Info("SSH server run output...")
|
||||
err := ij.runSSHServer(ctx, exec, args, gitspaceLogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gitspaceLogger.Info("Successfully run ssh-server")
|
||||
gitspaceLogger.Info("Run Remote IntelliJ IDE...")
|
||||
err = ij.runRemoteIDE(ctx, exec, args, gitspaceLogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gitspaceLogger.Info("Successfully Run Remote IntelliJ IDE")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ij *Intellij) runSSHServer(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
_ map[gitspaceTypes.IDEArg]interface{},
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
payload := gitspaceTypes.RunSSHServerPayload{
|
||||
Port: strconv.Itoa(ij.config.Port),
|
||||
}
|
||||
runSSHScript, err := utils.GenerateScriptFromTemplate(
|
||||
templateRunSSHServer, &payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to run ssh server from template %s: %w", templateRunSSHServer, err)
|
||||
}
|
||||
|
||||
err = exec.ExecuteCommandInHomeDirAndLog(ctx, runSSHScript, true, gitspaceLogger, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run SSH server: %w", err)
|
||||
}
|
||||
gitspaceLogger.Info("Successfully run ssh-server")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ij *Intellij) runRemoteIDE(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
args map[gitspaceTypes.IDEArg]interface{},
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
payload := gitspaceTypes.RunIntellijIDEPayload{
|
||||
Username: exec.RemoteUser,
|
||||
}
|
||||
// get Repository Name
|
||||
repoName, err := getRepoName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
payload.RepoName = repoName
|
||||
|
||||
// get DIR name
|
||||
dirName, err := getIDEDirName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
payload.IdeDirName = dirName
|
||||
|
||||
runSSHScript, err := utils.GenerateScriptFromTemplate(
|
||||
templateRunRemoteIDEIntellij, &payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to run intelliJ IDE from template %s: %w", templateRunSSHServer, err)
|
||||
}
|
||||
|
||||
err = exec.ExecuteCommandInHomeDirAndLog(ctx, runSSHScript, true, gitspaceLogger, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run intelliJ IDE: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Port returns the port on which the ssh-server is listening.
|
||||
func (ij *Intellij) Port() *types.GitspacePort {
|
||||
return &types.GitspacePort{
|
||||
Port: ij.config.Port,
|
||||
Protocol: enum.CommunicationProtocolSSH,
|
||||
}
|
||||
}
|
||||
|
||||
func (ij *Intellij) Type() enum.IDEType {
|
||||
return enum.IDETypeIntellij
|
||||
}
|
|
@ -32,8 +32,6 @@ import (
|
|||
var _ IDE = (*VSCode)(nil)
|
||||
|
||||
const (
|
||||
templateSetupSSHServer string = "setup_ssh_server.sh"
|
||||
templateRunSSHServer string = "run_ssh_server.sh"
|
||||
templateSetupVSCodeExtensions string = "setup_vscode_extensions.sh"
|
||||
)
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
var WireSet = wire.NewSet(
|
||||
ProvideVSCodeWebService,
|
||||
ProvideVSCodeService,
|
||||
ProvideIntellijService,
|
||||
ProvideIDEFactory,
|
||||
)
|
||||
|
||||
|
@ -32,6 +33,14 @@ func ProvideVSCodeService(config *VSCodeConfig) *VSCode {
|
|||
return NewVsCodeService(config)
|
||||
}
|
||||
|
||||
func ProvideIDEFactory(vscode *VSCode, vscodeWeb *VSCodeWeb) Factory {
|
||||
return NewFactory(vscode, vscodeWeb)
|
||||
func ProvideIntellijService(config *IntellijConfig) *Intellij {
|
||||
return NewIntellijService(config)
|
||||
}
|
||||
|
||||
func ProvideIDEFactory(
|
||||
vscode *VSCode,
|
||||
vscodeWeb *VSCodeWeb,
|
||||
intellij *Intellij,
|
||||
) Factory {
|
||||
return NewFactory(vscode, vscodeWeb, intellij)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -229,14 +230,15 @@ func generateIDEURL(
|
|||
),
|
||||
}
|
||||
case enum.IDETypeIntellij:
|
||||
idePath := relativeRepoPath + "/.cache"
|
||||
homePath := getHomePath(startResponse.AbsoluteRepoPath)
|
||||
idePath := path.Join(homePath, ".cache", "JetBrains", "RemoteDev", "dist", "intellij")
|
||||
ideURL = url.URL{
|
||||
Scheme: gitspaceTypes.IntellijURLScheme,
|
||||
Host: "", // Empty since we include the host and port in the path
|
||||
Path: "connect",
|
||||
Fragment: fmt.Sprintf("idePath=%s&projectPath=%s&host=%s&port=%s&user=%s&type=%s&deploy=%s",
|
||||
idePath,
|
||||
relativeRepoPath,
|
||||
startResponse.AbsoluteRepoPath,
|
||||
host,
|
||||
forwardedPort,
|
||||
startResponse.RemoteUser,
|
||||
|
@ -250,6 +252,11 @@ func generateIDEURL(
|
|||
return ideURLString
|
||||
}
|
||||
|
||||
func getHomePath(absoluteRepoPath string) string {
|
||||
pathList := strings.Split(absoluteRepoPath, "/")
|
||||
return strings.Join(pathList[:len(pathList)-1], "/")
|
||||
}
|
||||
|
||||
func (o Orchestrator) getSecretResolver(accessType enum.GitspaceAccessType) (secret.Resolver, error) {
|
||||
secretType := secretenum.PasswordSecretType
|
||||
switch accessType {
|
||||
|
|
|
@ -25,14 +25,15 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
templateSupportedOSDistribution = "supported_os_distribution.sh"
|
||||
templateVsCodeWebToolsInstallation = "install_tools_vs_code_web.sh"
|
||||
templateVsCodeToolsInstallation = "install_tools_vs_code.sh"
|
||||
templateSetEnv = "set_env.sh"
|
||||
templateGitInstallScript string = "install_git.sh"
|
||||
templateSetupGitCredentials = "setup_git_credentials.sh" // nolint:gosec
|
||||
templateCloneCode = "clone_code.sh"
|
||||
templateManagerUser = "manage_user.sh"
|
||||
templateSupportedOSDistribution = "supported_os_distribution.sh"
|
||||
templateVsCodeWebToolsInstallation = "install_tools_vs_code_web.sh"
|
||||
templateVsCodeToolsInstallation = "install_tools_vs_code.sh"
|
||||
templateIntellijToolsInstallation = "install_tools_intellij.sh"
|
||||
templateSetEnv = "set_env.sh"
|
||||
templateGitInstallScript = "install_git.sh"
|
||||
templateSetupGitCredentials = "setup_git_credentials.sh" // nolint:gosec
|
||||
templateCloneCode = "clone_code.sh"
|
||||
templateManagerUser = "manage_user.sh"
|
||||
)
|
||||
|
||||
//go:embed script/os_info.sh
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
#!/bin/sh
|
||||
|
||||
osInfoScript={{ .OSInfoScript }}
|
||||
|
||||
# provide distro func to evaluate os distribution
|
||||
eval "$osInfoScript"
|
||||
|
||||
# finding os distribution
|
||||
os_dist=$(distro)
|
||||
|
||||
# List of command-line tools to check and install based on the distribution
|
||||
debian_tools="procps tar unzip curl libxext6 libxrender1 libxtst6 libxi6 freetype* procps"
|
||||
fedora_tools="procps-ng tar unzip curl libxext6 libxrender1 libxtst6 libxi6 freetype* procps"
|
||||
alpine_tools="tar unzip curl libxext libxrender libxtst libxi freetype* procps gcompat"
|
||||
|
||||
# Install tool based on the distribution
|
||||
install_tool() {
|
||||
tool=$1
|
||||
|
||||
case "$os_dist" in
|
||||
debian|ubuntu)
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y "$tool"
|
||||
;;
|
||||
fedora)
|
||||
dnf install -y "$tool"
|
||||
;;
|
||||
opensuse)
|
||||
zypper install -y "$tool"
|
||||
;;
|
||||
alpine)
|
||||
apk add --no-cache "$tool"
|
||||
;;
|
||||
arch)
|
||||
pacman -Syu --noconfirm "$tool"
|
||||
;;
|
||||
freebsd)
|
||||
pkg install -y "$tool"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported OS distribution: $os_dist"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_tools() {
|
||||
case "$os_dist" in
|
||||
debian|ubuntu)
|
||||
tools="$debian_tools"
|
||||
;;
|
||||
fedora)
|
||||
tools="$fedora_tools"
|
||||
;;
|
||||
alpine)
|
||||
tools="$alpine_tools"
|
||||
;;
|
||||
*)
|
||||
echo "no tools to install, distribution: $os_dist"
|
||||
;;
|
||||
esac
|
||||
|
||||
for tool in $tools; do
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
echo "$tool is not installed. Installing..."
|
||||
install_tool "$tool"
|
||||
else
|
||||
echo "$tool is already installed."
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
install_tools
|
|
@ -29,7 +29,7 @@ if ! command -v curl >/dev/null 2>&1; then
|
|||
pkg install -y curl
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution: $distro."
|
||||
echo "Unsupported distribution: $(distro)."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
@ -50,7 +50,7 @@ if ! command -v npm >/dev/null 2>&1; then
|
|||
pkg install -y node
|
||||
;;
|
||||
*)
|
||||
echo "Distribution: $distro. npm installation not required"
|
||||
echo "Distribution: $(distro). npm installation not required"
|
||||
;;
|
||||
esac
|
||||
echo "npm installation completed."
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/sh
|
||||
|
||||
username={{ .Username }}
|
||||
repoName="{{ .RepoName }}"
|
||||
ideDirName="{{ .IdeDirName}}"
|
||||
|
||||
# Create .cache/JetBrains for the current user
|
||||
USER_HOME=$(eval echo ~$username)
|
||||
INTELLIJ_PATH="$USER_HOME/$ideDirName"
|
||||
|
||||
# check is intellij is downloaded
|
||||
if [ ! -d "$INTELLIJ_PATH" ]; then
|
||||
echo "IntelliJ IDE is not downloaded."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "registering remote Intellij IDE..."
|
||||
INTELLIJ_LOG_FILE="$INTELLIJ_PATH/jetbrains.log"
|
||||
echo "storing ide logs in $INTELLIJ_LOG_FILE..."
|
||||
nohup "$INTELLIJ_PATH/bin/remote-dev-server.sh" run "$USER_HOME/$repoName" --ssh-link-user "$username" > "$INTELLIJ_LOG_FILE" 2>&1 &
|
||||
|
||||
is_ide_running(){
|
||||
retries=5
|
||||
sleep_interval=2
|
||||
log_entry="Gateway link: "
|
||||
|
||||
# Loop for the retry count
|
||||
iteration_cnt=1
|
||||
while [ $iteration_cnt -le $retries ]; do
|
||||
echo "checking ide logs, iteration: #$iteration_cnt... "
|
||||
# Check for gateway link log to confirm everything is working
|
||||
if grep -q "$log_entry" "$INTELLIJ_LOG_FILE"; then
|
||||
# If the entry is found, return true
|
||||
return 0
|
||||
fi
|
||||
# Wait for the interval before retrying
|
||||
sleep $sleep_interval
|
||||
iteration_cnt=$((iteration_cnt + 1))
|
||||
done
|
||||
}
|
||||
|
||||
echo "waiting for ide to run..."
|
||||
if is_ide_running; then
|
||||
echo "intellij ide is running"
|
||||
else
|
||||
echo "intellij ide is not running"
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,67 @@
|
|||
#!/bin/sh
|
||||
|
||||
username={{ .Username }}
|
||||
ideDownloadUrlArm64="{{ .IdeDownloadURLArm64}}"
|
||||
ideDownloadUrlAmd64="{{ .IdeDownloadURLAmd64}}"
|
||||
ideDirName="{{ .IdeDirName}}"
|
||||
TMP_DOWNLOAD_DIR="/tmp/harness/"
|
||||
|
||||
# is_arm checks if underlying image is arm based.
|
||||
is_arm() {
|
||||
case "$(uname -a)" in
|
||||
*arm* ) true;;
|
||||
*arm64* ) true;;
|
||||
*aarch* ) true;;
|
||||
*aarch64* ) true;;
|
||||
* ) false;;
|
||||
esac
|
||||
}
|
||||
|
||||
ideDownloadUrl="$ideDownloadUrlAmd64"
|
||||
if is_arm; then
|
||||
echo "Detected arm architecture."
|
||||
ideDownloadUrl="$ideDownloadUrlArm64"
|
||||
fi
|
||||
|
||||
# Create $TMP_DOWNLOAD_DIR directory with correct ownership
|
||||
if [ ! -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||
mkdir -p "$TMP_DOWNLOAD_DIR"
|
||||
chown "$username:$username" "$TMP_DOWNLOAD_DIR"
|
||||
fi
|
||||
|
||||
USER_HOME=$(eval echo ~$username)
|
||||
INTELLIJ_PATH="$USER_HOME/$ideDirName"
|
||||
|
||||
# Get the tarball file name from the URL
|
||||
echo "Downloading IDE from $ideDownloadUrl ..."
|
||||
TARBALL_NAME=$(basename "$ideDownloadUrl")
|
||||
# Download JetBrains product
|
||||
curl --no-progress-meter -L -o "$TMP_DOWNLOAD_DIR/$TARBALL_NAME" "$ideDownloadUrl"
|
||||
|
||||
# Verify the download
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Download failed. Please check the product name, version, or URL."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create INTELLIJ_PATH directory with correct ownership
|
||||
if [ ! -d "$INTELLIJ_PATH" ]; then
|
||||
echo "Creating directory: $INTELLIJ_PATH"
|
||||
mkdir -p "$INTELLIJ_PATH"
|
||||
fi
|
||||
|
||||
echo "extracting $TARBALL_NAME..."
|
||||
tar -xzf "$TMP_DOWNLOAD_DIR/$TARBALL_NAME" -C "$INTELLIJ_PATH"
|
||||
|
||||
EXTRACTED_DIRNAME=$(basename "$(find "$INTELLIJ_PATH" -maxdepth 1 -type d)")
|
||||
|
||||
mv "$INTELLIJ_PATH/$EXTRACTED_DIRNAME/"* "$INTELLIJ_PATH"
|
||||
rm -r "$INTELLIJ_PATH/$EXTRACTED_DIRNAME"
|
||||
|
||||
if [ -d "$INTELLIJ_PATH" ]; then
|
||||
chown -R "$username:$username" "$INTELLIJ_PATH"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
echo "Cleaning up tarball..."
|
||||
rm -r "$TMP_DOWNLOAD_DIR"
|
|
@ -43,7 +43,10 @@ func InstallTools(
|
|||
}
|
||||
return nil
|
||||
case enum.IDETypeIntellij:
|
||||
// not installing any tools for intellij
|
||||
err := InstallToolsForIntellij(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
@ -97,3 +100,27 @@ func InstallToolsForVsCode(
|
|||
gitspaceLogger.Info("Successfully installed tools for vs code")
|
||||
return nil
|
||||
}
|
||||
|
||||
func InstallToolsForIntellij(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger types.GitspaceLogger,
|
||||
) error {
|
||||
script, err := GenerateScriptFromTemplate(
|
||||
templateIntellijToolsInstallation, &types.InstallToolsPayload{
|
||||
OSInfoScript: osDetectScript,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to install tools for intellij from template %s: %w",
|
||||
templateIntellijToolsInstallation, err)
|
||||
}
|
||||
|
||||
gitspaceLogger.Info("Installing tools for intellij in container")
|
||||
err = exec.ExecuteCommandInHomeDirAndLog(ctx, script, true, gitspaceLogger, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to install tools for intellij: %w", err)
|
||||
}
|
||||
gitspaceLogger.Info("Successfully installed tools for intellij")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -77,3 +77,17 @@ type SupportedOSDistributionPayload struct {
|
|||
type SetEnvPayload struct {
|
||||
EnvVariables []string
|
||||
}
|
||||
|
||||
type SetupIntellijIDEPayload struct {
|
||||
Username string
|
||||
IdeDownloadURLArm64 string
|
||||
IdeDownloadURLAmd64 string
|
||||
IdeDirName string
|
||||
}
|
||||
|
||||
type RunIntellijIDEPayload struct {
|
||||
Username string
|
||||
RepoName string
|
||||
IdeDownloadURL string
|
||||
IdeDirName string
|
||||
}
|
||||
|
|
|
@ -26,8 +26,11 @@ const (
|
|||
VSCodeCustomizationArg IDEArg = "VSCODE_CUSTOMIZATION"
|
||||
VSCodeProxyURIArg IDEArg = "VSCODE_PROXY_URI"
|
||||
IDERepoNameArg IDEArg = "IDE_REPO_NAME"
|
||||
VSCodeURLScheme = "vscode-remote"
|
||||
IntellijURLScheme = "jetbrains-gateway"
|
||||
IDEDownloadURLArg IDEArg = "IDE_DOWNLOAD_URL"
|
||||
IDEDIRNameArg IDEArg = "IDE_DIR_NAME"
|
||||
|
||||
VSCodeURLScheme string = "vscode-remote"
|
||||
IntellijURLScheme string = "jetbrains-gateway"
|
||||
)
|
||||
|
||||
type GitspaceLogger interface {
|
||||
|
|
|
@ -442,6 +442,13 @@ func ProvideIDEVSCodeConfig(config *types.Config) *ide.VSCodeConfig {
|
|||
}
|
||||
}
|
||||
|
||||
// ProvideIDEIntellijConfig loads the Intellij IDE config from the main config.
|
||||
func ProvideIDEIntellijConfig(config *types.Config) *ide.IntellijConfig {
|
||||
return &ide.IntellijConfig{
|
||||
Port: config.IDE.Intellij.Port,
|
||||
}
|
||||
}
|
||||
|
||||
// ProvideGitspaceOrchestratorConfig loads the Gitspace orchestrator config from the main config.
|
||||
func ProvideGitspaceOrchestratorConfig(config *types.Config) *orchestrator.Config {
|
||||
return &orchestrator.Config{
|
||||
|
|
|
@ -273,6 +273,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
|||
gitspaceservice.WireSet,
|
||||
cliserver.ProvideGitspaceInfraProvisionerConfig,
|
||||
cliserver.ProvideIDEVSCodeConfig,
|
||||
cliserver.ProvideIDEIntellijConfig,
|
||||
instrument.WireSet,
|
||||
aiagentservice.WireSet,
|
||||
aiagent.WireSet,
|
||||
|
|
|
@ -333,7 +333,9 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||
vsCode := ide.ProvideVSCodeService(vsCodeConfig)
|
||||
vsCodeWebConfig := server.ProvideIDEVSCodeWebConfig(config)
|
||||
vsCodeWeb := ide.ProvideVSCodeWebService(vsCodeWebConfig)
|
||||
ideFactory := ide.ProvideIDEFactory(vsCode, vsCodeWeb)
|
||||
intellijConfig := server.ProvideIDEIntellijConfig(config)
|
||||
intellij := ide.ProvideIntellijService(intellijConfig)
|
||||
ideFactory := ide.ProvideIDEFactory(vsCode, vsCodeWeb, intellij)
|
||||
passwordResolver := secret.ProvidePasswordResolver()
|
||||
resolverFactory := secret.ProvideResolverFactory(passwordResolver)
|
||||
orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, platformConnector, infraProvisioner, containerOrchestrator, eventsReporter, orchestratorConfig, ideFactory, resolverFactory)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package enum
|
||||
|
||||
const (
|
||||
IDEIntellijDownloadURLAmd64Template string = "https://download.jetbrains.com/idea/ideaIU-%s.tar.gz"
|
||||
IDEIntellijDownloadURLArm64Template string = "https://download.jetbrains.com/idea/ideaIU-%s-aarch64.tar.gz"
|
||||
IDEIntellijVer string = "2024.3"
|
||||
)
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
type IntellijDownloadURL struct {
|
||||
Arm64 string
|
||||
Amd64 string
|
||||
}
|
Loading…
Reference in New Issue