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.sh
BT-10437
Deepak Bhatt 2024-12-30 15:19:48 +00:00 committed by Harness
parent 15f4adcbe0
commit 887379b94a
24 changed files with 669 additions and 25 deletions

View File

@ -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.")
)

View File

@ -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
}

View File

@ -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,
},

View File

@ -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
}

View File

@ -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}
}

View File

@ -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.

View File

@ -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
}

View File

@ -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"
)

View File

@ -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)
}

View File

@ -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 {

View File

@ -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
app/gitspace/orchestrator/utils/script/os_info.sh Normal file → Executable file
View File

View File

@ -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

View File

@ -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."

View File

@ -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

View File

@ -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"

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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{

View File

@ -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,

View File

@ -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)

21
types/enum/intellij.go Normal file
View File

@ -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"
)

20
types/intellij.go Normal file
View File

@ -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
}