From 87a1e534683c98f2332930cb2285f3bb2fab78d2 Mon Sep 17 00:00:00 2001 From: ilan Date: Tue, 28 Mar 2023 19:24:16 +0300 Subject: [PATCH] 0.5.10 --- CHANGELOG.md | 11 +- Scripts/setup_dependencies.sh | 34 +- package-lock.json | 4 +- package.json | 2 +- src/devEnvs.ts | 1277 +++++++++++++++++++-------------- src/terminalManager.ts | 21 +- src/tools.ts | 38 +- 7 files changed, 773 insertions(+), 614 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbc8efc..6c4af2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,16 @@ # Unreleased - + +# [0.5.10] (2023-03-25) + +- Drop support for installation of `'docker', 'pipx', 'shellcheck'` in **Install XSOAR local development environment**. +- Selecting `python` in **Install XSOAR local development environment** will install the latest version of `python3` and the latest version of `python2` using `pyenv`. +- Selecting `poetry` in **Install XSOAR local development environment** will install the latest version of `poetry` using the official installation script. +- Demisto-SDK commands will now run from the `poetry` environment, if available. +- Demisto-SDK commands will now run from the `content` path, if available. +- Added options to **Install/Update Demisto-SDK**, to install using poetry or pip. + # [0.5.9] (2023-01-25) - Fixed an issue where Dev Container fails to open in arm64 architecture. diff --git a/Scripts/setup_dependencies.sh b/Scripts/setup_dependencies.sh index a988d21..09aa1cc 100755 --- a/Scripts/setup_dependencies.sh +++ b/Scripts/setup_dependencies.sh @@ -1,9 +1,6 @@ #!/bin/bash set -e -# workaround to support M1 and Linux -export PATH=/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:"$PATH" - dependencies=$1 # if empty dependencies @@ -12,27 +9,9 @@ if [ -z "$dependencies" ]; then exit 0 fi -# check if brew installed -if ! [ -x "$(command -v brew)" ]; then - echo "Please install Homebrew first to install dependencies. Homebrew installation command:" - echo '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' - exit 1 -fi -brew update -# check if "docker" in dependencies -if [[ $dependencies == *"docker"* ]]; then - brew install --cask docker || echo "Install Docker manually" -fi - if [[ $dependencies == *"python"* ]]; then - brew install python@3.10 || echo "Install python manually" -fi - - -brew install $dependencies || true - -if [[ $dependencies == *"pyenv"* ]]; then # If pyenv not already exists in zshrc, add it + curl https://pyenv.run | bash || true export PYENV_ROOT="$HOME/.pyenv"; export PATH="$PYENV_ROOT/bin":$PATH; eval "$(pyenv init -)" @@ -43,8 +22,9 @@ if [[ $dependencies == *"pyenv"* ]]; then pyenv install 2.7.18 --force pyenv global $LATEST_PYTHON 2.7.18; fi -# check if python is availible -if ! [ -x "$(command -v python)" ]; then - echo "Python is not availible. setting poetry to python3" - poetry env use python3 || poetry env use /home/linuxbrew/.linuxbrew/bin/python3 || true -fi \ No newline at end of file + +if [[ $dependencies == *"poetry" ]] +then + echo "Installing poetry" + curl -sSL https://install.python-poetry.org | python3 - +fi diff --git a/package-lock.json b/package-lock.json index 2c7acec..6304a32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "xsoar", - "version": "0.5.9", + "version": "0.5.10", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "xsoar", - "version": "0.5.9", + "version": "0.5.10", "license": "SEE LICENSE IN LICENSE", "dependencies": { "envfile": "^6.17.0", diff --git a/package.json b/package.json index 3e50cb6..94acc30 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "xsoar", "displayName": "Cortex XSOAR", "description": "Build, Format, and Validate Cortex XSOAR with ease.", - "version": "0.5.9", + "version": "0.5.10", "engines": { "vscode": "^1.54.0" }, diff --git a/src/devEnvs.ts b/src/devEnvs.ts index 535321f..07282a5 100644 --- a/src/devEnvs.ts +++ b/src/devEnvs.ts @@ -1,606 +1,767 @@ -import { Logger } from "./logger" -import vscode from 'vscode' -import path from 'path' -import JSON5 from 'json5' +import { Logger } from "./logger"; +import vscode from "vscode"; +import path from "path"; +import JSON5 from "json5"; import * as dsdk from "./demistoSDKWrapper"; import * as yaml from "yaml"; import * as fs from "fs-extra"; import { execSync, spawn } from "child_process"; -import { parse, stringify } from "envfile" -import { installDemistoSDKGlobally, getContentPath } from "./tools"; +import { parse, stringify } from "envfile"; import glob from "glob"; +import { getContentPath } from "./tools"; async function addPythonPath(): Promise { - const contentPath = getContentPath() - if (!contentPath) { - return - } - - const pylintPlugins = path.resolve(path.join(contentPath, "..", "demisto_sdk", "demisto_sdk", "commands", "lint", "resources", "pylint_plugins")) - let PYTHONPATH = `${contentPath}/Packs/Base/Scripts/CommonServerPython/:${contentPath}/Tests/demistomock/:` - const apiModules = execSync(`printf '%s:' ${contentPath}/Packs/ApiModules/Scripts/*`).toString().trim() - PYTHONPATH += apiModules - PYTHONPATH += pylintPlugins - const envFilePath = path.join(contentPath, '.env') - if (!await fs.pathExists(envFilePath)) { - fs.createFileSync(envFilePath) - } - const envFile = fs.readFileSync(envFilePath, 'utf8') - Logger.info(`envFile: ${envFile}`) - const env = parse(envFile) - env["PYTHONPATH"] = PYTHONPATH - env["MYPYPATH"] = PYTHONPATH - Logger.info(stringify(env)) - fs.writeFileSync(envFilePath, stringify(env)) - + const contentPath = getContentPath(); + if (!contentPath) { + return; + } + + const pylintPlugins = path.resolve( + path.join( + contentPath, + "..", + "demisto_sdk", + "demisto_sdk", + "commands", + "lint", + "resources", + "pylint_plugins" + ) + ); + let PYTHONPATH = `${contentPath}/Packs/Base/Scripts/CommonServerPython/:${contentPath}/Tests/demistomock/:`; + const apiModules = execSync( + `printf '%s:' ${contentPath}/Packs/ApiModules/Scripts/*` + ) + .toString() + .trim(); + PYTHONPATH += apiModules; + PYTHONPATH += pylintPlugins; + const envFilePath = path.join(contentPath, ".env"); + if (!(await fs.pathExists(envFilePath))) { + fs.createFileSync(envFilePath); + } + const envFile = fs.readFileSync(envFilePath, "utf8"); + Logger.info(`envFile: ${envFile}`); + const env = parse(envFile); + env["PYTHONPATH"] = PYTHONPATH; + env["MYPYPATH"] = PYTHONPATH; + Logger.info(stringify(env)); + fs.writeFileSync(envFilePath, stringify(env)); } export async function installDevEnv(): Promise { - const workspaces = vscode.workspace.workspaceFolders; - if (!workspaces) { - vscode.window.showErrorMessage('Could not find a valid workspace'); - return; - } - const workspace = workspaces[0]; - const dirPath = workspace.uri.fsPath; - // check if content is in dirPath - if (!dirPath.includes('content')) { - vscode.window.showErrorMessage('Please run this command from a content repository'); - return; - } - - // should we install global dependencies? - await vscode.window.showQuickPick(['Yes', 'No'], { - title: "Install global dependencies with Homebrew?", - placeHolder: "Homebrew should be installed to run this step. Skip if you want to install dependencies manually." - }).then(async (answer) => { - if (answer === 'Yes') { - await vscode.window.showQuickPick(['gcc', 'python', 'poetry', 'node', 'docker', 'pyenv', 'pipx', 'shellcheck'], - { title: 'Select dependencies to install', canPickMany: true }).then(async (dependencies) => { - if (dependencies) { - await installGlobalDependencies(dependencies) - } - }) - } + const workspaces = vscode.workspace.workspaceFolders; + if (!workspaces) { + vscode.window.showErrorMessage("Could not find a valid workspace"); + return; + } + const workspace = workspaces[0]; + const dirPath = workspace.uri.fsPath; + // check if content is in dirPath + if (!dirPath.includes("content")) { + vscode.window.showErrorMessage( + "Please run this command from a content repository" + ); + return; + } + + await vscode.window + .showQuickPick(["python", "poetry"], { + title: "Select dependencies to install", + placeHolder: "Leave blank to skip dependencies installation", + canPickMany: true, }) - await vscode.window.showQuickPick(['Yes', 'No'], { - title: 'Install Demisto-SDK globally?', - placeHolder: "This will install demisto-sdk globally in your system with pipx" - }).then(async (answer) => { - if (answer === 'Yes') { - installDemistoSDKGlobally() - } - }) - - // install recommended extensions - // To install recommended extensions, we need to show them first - await vscode.commands.executeCommand('workbench.extensions.action.showRecommendedExtensions') - // sleep for 3 seconds to let the windows load - await new Promise(resolve => setTimeout(resolve, 3000)) - vscode.commands.executeCommand('workbench.extensions.action.installWorkspaceRecommendedExtensions', true) - - let shouldPreCommit = false - await vscode.window.showQuickPick(['Yes', 'No'], { - title: 'Do you want to install pre-commit hooks?', - placeHolder: "Installing pre-commit hooks will run `validate` and `lint` before every commit" - }).then(async (answer) => { - if (answer === 'Yes') { - shouldPreCommit = true - } + .then(async (dependencies) => { + if (dependencies) { + await installGlobalDependencies(dependencies); + } + }); + + // install recommended extensions + // To install recommended extensions, we need to show them first + await vscode.commands.executeCommand( + "workbench.extensions.action.showRecommendedExtensions" + ); + // sleep for 3 seconds to let the windows load + await new Promise((resolve) => setTimeout(resolve, 3000)); + vscode.commands.executeCommand( + "workbench.extensions.action.installWorkspaceRecommendedExtensions", + true + ); + + let shouldPreCommit = false; + await vscode.window + .showQuickPick(["Yes", "No"], { + title: "Do you want to install pre-commit hooks?", + placeHolder: + "Installing pre-commit hooks will run `validate` and `lint` before every commit", }) + .then(async (answer) => { + if (answer === "Yes") { + shouldPreCommit = true; + } + }); + + // bootstrap content (run bootstrap script) + await bootstrapContent(dirPath, shouldPreCommit); + // copy settings file + const settingsFile = path.resolve(__dirname, "../Templates/settings.json"); + const settingsFileOutput = path.resolve(dirPath, ".vscode/settings.json"); + fs.copyFileSync(settingsFile, settingsFileOutput); + + // set up environment variables + await addPythonPath(); + fs.createFileSync( + path.join( + dirPath, + "Packs/Base/Scripts/CommonServerPython/CommonServerUserPython.py" + ) + ); - // bootstrap content (run bootstrap script) - await bootstrapContent(dirPath, shouldPreCommit) - // copy settings file - const settingsFile = path.resolve(__dirname, '../Templates/settings.json') - const settingsFileOutput = path.resolve(dirPath, '.vscode/settings.json') - fs.copyFileSync(settingsFile, settingsFileOutput) - - // set up environment variables - await addPythonPath() - fs.createFileSync(path.join(dirPath, 'Packs/Base/Scripts/CommonServerPython/CommonServerUserPython.py')) - - await vscode.window.showQuickPick(['Yes', 'No'], { - title: 'Would you like to configure the connection to XSOAR?', - placeHolder: "This will ask you to configure the connection XSOAR, allowing Demisto-SDK commands such as upload and download", - }).then(async (answer) => { - if (answer === 'Yes') { - configureDemistoVars() - } + await vscode.window + .showQuickPick(["Yes", "No"], { + title: "Would you like to configure the connection to XSOAR?", + placeHolder: + "This will ask you to configure the connection XSOAR, allowing Demisto-SDK commands such as upload and download", }) - - + .then(async (answer) => { + if (answer === "Yes") { + configureDemistoVars(); + } + }); } function installGlobalDependencies(dependencies: string[]) { - Logger.info('Install global dependencies') - const task = new vscode.Task( - { type: 'dependencies', name: 'Install global dependencies' }, - vscode.TaskScope.Workspace, - 'dependencies', - 'dependencies', - new vscode.ShellExecution(`sh -x ${path.resolve(__dirname, '../Scripts/setup_dependencies.sh')} "${dependencies.join(' ')}"`), + Logger.info("Install global dependencies"); + const task = new vscode.Task( + { type: "dependencies", name: "Install global dependencies" }, + vscode.TaskScope.Workspace, + "dependencies", + "dependencies", + new vscode.ShellExecution( + `bash -x ${path.resolve( + __dirname, + "../Scripts/setup_dependencies.sh" + )} "${dependencies.join(" ")}"` ) - return new Promise(resolve => { - vscode.window.withProgress({ - title: `Bootstrap content`, - location: vscode.ProgressLocation.Notification - }, async (progress) => { - progress.report({ message: `Installing global dependencies` }) - const execution = await vscode.tasks.executeTask(task); - const disposable = vscode.tasks.onDidEndTaskProcess(e => { - if (e.execution === execution) { - if (e.exitCode === 0) { - disposable.dispose() - resolve() - } - else { - vscode.window.showWarningMessage('Could not installing global dependencies') - } - } - }) - progress.report({ message: "Processing..." }); - }) - - }) -} - -async function getDemistoSDKPath(contentPath: string): Promise { - const demistoSDKParentPath = path.resolve(path.join(contentPath, '..')) - let demistoSDKPathString = path.resolve(demistoSDKParentPath, 'demisto-sdk') - if (!await fs.pathExists(demistoSDKPathString)) { - Logger.info(`demisto-sdk not found in ${demistoSDKPathString}`) - const answer = await vscode.window.showQuickPick(['Select Demisto-SDK path', 'Clone repository'], - { - placeHolder: 'Do you want to use an existing repository or clone a new one?', - title: 'Select Demisto-SDK repository path' - }) - if (answer === 'Clone repository') { - // If the user doesn't close the VSCode window, it will not proceed to the next step - vscode.window.showInformationMessage( - 'After cloning, close VSCode message to proceed.', - { modal: true }) - await vscode.commands.executeCommand('git.clone', 'git@github.com:demisto/demisto-sdk.git', demistoSDKParentPath) - } - if (answer === 'Select Demisto-SDK path') { - const demistoSDKPath = await vscode.window.showOpenDialog({ - canSelectFiles: false, - canSelectFolders: true, - openLabel: 'Select demisto-sdk repository', - title: 'Select demisto-sdk repository' - }) - if (!demistoSDKPath) { - return + ); + return new Promise((resolve) => { + vscode.window.withProgress( + { + title: `Bootstrap content`, + location: vscode.ProgressLocation.Notification, + }, + async (progress) => { + progress.report({ message: `Installing global dependencies` }); + const execution = await vscode.tasks.executeTask(task); + const disposable = vscode.tasks.onDidEndTaskProcess((e) => { + if (e.execution === execution) { + if (e.exitCode === 0) { + disposable.dispose(); + resolve(); + } else { + vscode.window.showWarningMessage( + "Could not installing global dependencies" + ); } - demistoSDKPathString = demistoSDKPath[0].fsPath - } + } + }); + progress.report({ message: "Processing..." }); + } + ); + }); +} +async function getDemistoSDKPath( + contentPath: string +): Promise { + const demistoSDKParentPath = path.resolve(path.join(contentPath, "..")); + let demistoSDKPathString = path.resolve(demistoSDKParentPath, "demisto-sdk"); + if (!(await fs.pathExists(demistoSDKPathString))) { + Logger.info(`demisto-sdk not found in ${demistoSDKPathString}`); + const answer = await vscode.window.showQuickPick( + ["Select Demisto-SDK path", "Clone repository"], + { + placeHolder: + "Do you want to use an existing repository or clone a new one?", + title: "Select Demisto-SDK repository path", + } + ); + if (answer === "Clone repository") { + // If the user doesn't close the VSCode window, it will not proceed to the next step + vscode.window.showInformationMessage( + "After cloning, close VSCode message to proceed.", + { modal: true } + ); + await vscode.commands.executeCommand( + "git.clone", + "git@github.com:demisto/demisto-sdk.git", + demistoSDKParentPath + ); + } + if (answer === "Select Demisto-SDK path") { + const demistoSDKPath = await vscode.window.showOpenDialog({ + canSelectFiles: false, + canSelectFolders: true, + openLabel: "Select demisto-sdk repository", + title: "Select demisto-sdk repository", + }); + if (!demistoSDKPath) { + return; + } + demistoSDKPathString = demistoSDKPath[0].fsPath; } - return demistoSDKPathString + } + return demistoSDKPathString; } export async function developDemistoSDK(): Promise { - const contentPath = getContentPath() - if (!contentPath) { - vscode.window.showErrorMessage('Please run this command from a content repository') - return - } - const demistoSDKPathString = await getDemistoSDKPath(contentPath) - if (!demistoSDKPathString) { - vscode.window.showErrorMessage('Please select a valid demisto-sdk repository') - return - } - const vsCodePath = path.join(contentPath, '.vscode') - - vscode.window.showInformationMessage(`Using Demisto-SDK path: ${demistoSDKPathString}`) - Logger.info(`demisto sdk path is ${demistoSDKPathString}`) - const launchDemistoSDK = JSON5.parse(fs.readFileSync(path.resolve(__dirname, '../Templates/launch-demisto-sdk.json'), 'utf-8')) - launchDemistoSDK.configurations[0].cwd = contentPath - fs.writeJSONSync(path.join(demistoSDKPathString, '.vscode', 'launch.json'), launchDemistoSDK, { spaces: 4 }) - fs.copyFileSync(path.resolve(__dirname, '../Templates/demisto_sdk_settings.json'), path.join(demistoSDKPathString, '.vscode', 'settings.json')) - const workspace = { - 'folders': - [{ 'path': contentPath }, { 'path': demistoSDKPathString }], - 'settings': {} - } - const workspaceOutput = path.join(vsCodePath, `demisto-sdk_content.code-workspace`) - fs.writeJsonSync(workspaceOutput, workspace, { spaces: 2 }) - const response = await vscode.window.showQuickPick(['Existing Window', 'New Window'], - { - placeHolder: 'Select if you want to open in existing window or new window', - title: 'Where would you like to open the environment?' - }) - const openInNewWindow = response === 'New Window' - const installDemistoSDK = await vscode.window.showQuickPick(['Yes', 'No'], { - title: 'Do you want to install Demisto-SDK dependencies?', - placeHolder: " Will run poetry install in the demisto-sdk repository" - }) - if (installDemistoSDK === 'Yes') { - spawn(`cd ${demistoSDKPathString} && poetry install`) - } - vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(workspaceOutput), openInNewWindow) - + const contentPath = getContentPath(); + if (!contentPath) { + vscode.window.showErrorMessage( + "Please run this command from a content repository" + ); + return; + } + const demistoSDKPathString = await getDemistoSDKPath(contentPath); + if (!demistoSDKPathString) { + vscode.window.showErrorMessage( + "Please select a valid demisto-sdk repository" + ); + return; + } + const vsCodePath = path.join(contentPath, ".vscode"); + + vscode.window.showInformationMessage( + `Using Demisto-SDK path: ${demistoSDKPathString}` + ); + Logger.info(`demisto sdk path is ${demistoSDKPathString}`); + const launchDemistoSDK = JSON5.parse( + fs.readFileSync( + path.resolve(__dirname, "../Templates/launch-demisto-sdk.json"), + "utf-8" + ) + ); + launchDemistoSDK.configurations[0].cwd = contentPath; + fs.writeJSONSync( + path.join(demistoSDKPathString, ".vscode", "launch.json"), + launchDemistoSDK, + { spaces: 4 } + ); + fs.copyFileSync( + path.resolve(__dirname, "../Templates/demisto_sdk_settings.json"), + path.join(demistoSDKPathString, ".vscode", "settings.json") + ); + const workspace = { + folders: [{ path: contentPath }, { path: demistoSDKPathString }], + settings: {}, + }; + const workspaceOutput = path.join( + vsCodePath, + `demisto-sdk_content.code-workspace` + ); + fs.writeJsonSync(workspaceOutput, workspace, { spaces: 2 }); + const response = await vscode.window.showQuickPick( + ["Existing Window", "New Window"], + { + placeHolder: + "Select if you want to open in existing window or new window", + title: "Where would you like to open the environment?", + } + ); + const openInNewWindow = response === "New Window"; + const installDemistoSDK = await vscode.window.showQuickPick(["Yes", "No"], { + title: "Do you want to install Demisto-SDK dependencies?", + placeHolder: " Will run poetry install in the demisto-sdk repository", + }); + if (installDemistoSDK === "Yes") { + spawn(`cd ${demistoSDKPathString} && poetry install`); + } + vscode.commands.executeCommand( + "vscode.openFolder", + vscode.Uri.file(workspaceOutput), + openInNewWindow + ); } export async function configureDemistoVars(): Promise { - const workspaces = vscode.workspace.workspaceFolders; - if (!workspaces) { - vscode.window.showErrorMessage('Could not find a valid workspace'); - return; - } - const workspace = workspaces[0]; - const dirPath = workspace.uri.fsPath; - const envFilePath = path.join(dirPath, '.env') - if (!await fs.pathExists(envFilePath)) { - fs.createFileSync(envFilePath) - } - vscode.window.showInformationMessage(`Setting up environment in .env file in ${envFilePath}`) - let env = parse(fs.readFileSync(envFilePath, 'utf8')) - if (!env) { - env = {} - } - await vscode.window.showInputBox({ - title: 'XSOAR URL', - value: 'http://localhost:8080', - ignoreFocusOut: true, - }).then(url => { - if (url) { - env["DEMISTO_BASE_URL"] = url - } + const workspaces = vscode.workspace.workspaceFolders; + if (!workspaces) { + vscode.window.showErrorMessage("Could not find a valid workspace"); + return; + } + const workspace = workspaces[0]; + const dirPath = workspace.uri.fsPath; + const envFilePath = path.join(dirPath, ".env"); + if (!(await fs.pathExists(envFilePath))) { + fs.createFileSync(envFilePath); + } + vscode.window.showInformationMessage( + `Setting up environment in .env file in ${envFilePath}` + ); + let env = parse(fs.readFileSync(envFilePath, "utf8")); + if (!env) { + env = {}; + } + await vscode.window + .showInputBox({ + title: "XSOAR URL", + value: "http://localhost:8080", + ignoreFocusOut: true, }) - vscode.window.showInformationMessage('Enter either XSOAR username and password, or an API key') - await vscode.window.showInputBox({ - title: 'XSOAR username (optional)', - value: 'admin', - ignoreFocusOut: true, - }).then(username => { - if (username) { - env["DEMISTO_USERNAME"] = username - } + .then((url) => { + if (url) { + env["DEMISTO_BASE_URL"] = url; + } + }); + vscode.window.showInformationMessage( + "Enter either XSOAR username and password, or an API key" + ); + await vscode.window + .showInputBox({ + title: "XSOAR username (optional)", + value: "admin", + ignoreFocusOut: true, }) - await vscode.window.showInputBox({ - title: 'XSOAR password (optional)', - value: 'admin', - password: true, - ignoreFocusOut: true, - }).then(password => { - if (password) { - env["DEMISTO_PASSWORD"] = password - } + .then((username) => { + if (username) { + env["DEMISTO_USERNAME"] = username; + } + }); + await vscode.window + .showInputBox({ + title: "XSOAR password (optional)", + value: "admin", + password: true, + ignoreFocusOut: true, }) - - await vscode.window.showInputBox({ - title: 'XSOAR API key (optional)', - placeHolder: 'Leaving blank will use username and password', - password: true, - ignoreFocusOut: true, - }).then((apiKey) => { - if (apiKey) { - env["DEMISTO_API_KEY"] = apiKey - } + .then((password) => { + if (password) { + env["DEMISTO_PASSWORD"] = password; + } + }); + + await vscode.window + .showInputBox({ + title: "XSOAR API key (optional)", + placeHolder: "Leaving blank will use username and password", + password: true, + ignoreFocusOut: true, }) - await vscode.window.showQuickPick( - ['true', 'false'], - { - title: "XSOAR SSL verification", - placeHolder: 'Should XSOAR SSL verification be enabled?', - } - ).then(verifySSL => { - if (verifySSL) { - env["DEMISTO_VERIFY_SSL"] = verifySSL - } + .then((apiKey) => { + if (apiKey) { + env["DEMISTO_API_KEY"] = apiKey; + } + }); + await vscode.window + .showQuickPick(["true", "false"], { + title: "XSOAR SSL verification", + placeHolder: "Should XSOAR SSL verification be enabled?", }) - fs.writeFileSync(envFilePath, stringify(env)) - + .then((verifySSL) => { + if (verifySSL) { + env["DEMISTO_VERIFY_SSL"] = verifySSL; + } + }); + fs.writeFileSync(envFilePath, stringify(env)); } -export async function openIntegrationDevContainer(dirPath: string): Promise { - const filePath = path.parse(dirPath) - const packDir = path.resolve(path.join(dirPath, '..', '..')) - - const vsCodePath = path.join(packDir, '.vscode') - - const devcontainerFolder = path.join(packDir, '.devcontainer') - Logger.info(`devcontainerFolder is ${devcontainerFolder}`) - Logger.info('Create json configuration for debugging') - if (!await fs.pathExists(vsCodePath)) { - fs.mkdirSync(vsCodePath) - } - const ymlFilePath = path.join(dirPath, filePath.name.concat('.yml')) - const ymlObject = yaml.parseDocument(fs.readFileSync(ymlFilePath, 'utf8')).toJSON(); - - - let dockerImage = ymlObject.dockerimage || ymlObject?.script.dockerimage - dockerImage = dockerImage.replace('demisto', 'devtestdemisto') - Logger.info(`docker image is ${dockerImage}`) - const devcontainerJsonPath = path.resolve(__dirname, '../Templates/integration_env/.devcontainer/devcontainer.json') - const devcontainer = JSON5.parse(fs.readFileSync(devcontainerJsonPath, 'utf-8')) - vscode.window.showInformationMessage("Building devcontainer folder") - fs.copySync(path.resolve(__dirname, '../Templates/integration_env/.devcontainer'), devcontainerFolder) - fs.copySync(path.resolve(__dirname, '../Scripts/create_certs.sh'), path.join(devcontainerFolder, 'create_certs.sh')) - Logger.info('devcontainer folder created') - vscode.window.showInformationMessage("Starting demisto-sdk lint, please wait") - devcontainer.name = `XSOAR Integration: ${filePath.name}` - - // lint currently does not remove commonserverpython file for some reason - const CommonServerPython = path.join(dirPath, 'CommonServerPython.py') - if (filePath.name !== "CommonServerPython" && await fs.pathExists(CommonServerPython)) { - fs.removeSync(CommonServerPython) - } - createLaunchJson(ymlObject.type, dirPath, filePath, vsCodePath); - createSettings(vsCodePath, dirPath, '/usr/local/bin/python', false) - - await dsdk.lint(dirPath, false, false, false, true) - - // delete cache folders and *.pyc files - fs.rmdir(path.join(dirPath, '__pycache__'), { recursive: true }) - fs.rmdir(path.join(dirPath, '.pytest_cache'), { recursive: true }) - fs.rmdir(path.join(dirPath, '.mypy_cache'), { recursive: true }) - fs.rmdir(path.join(dirPath, '__pycache__'), { recursive: true }) - // glob for *.pyc files and remove - const pycFiles = glob.sync(path.join(dirPath, '*.pyc')) - pycFiles.forEach(file => { fs.remove(file) }) - - try { - const testDockerImage = execSync(`docker images --format "{{.Repository}}:{{.Tag}}" | grep ${dockerImage} | head -1`, - { cwd: dirPath, }).toString().trim() - if (!testDockerImage) { - Logger.error('Docker image not found, exiting') - vscode.window.showErrorMessage('Docker image not found, exiting') - return - } - devcontainer.build.args.IMAGENAME = testDockerImage - fs.writeJSONSync(path.join(devcontainerFolder, 'devcontainer.json'), devcontainer, { spaces: 2 }) - } - catch (err) { - Logger.error(`Could not find docker image ${dockerImage}: ${err}}`) - throw new Error(`Could not find docker image ${dockerImage}: ${err}}`) - } - Logger.info(`remote name is: ${vscode.env.remoteName}`) - Logger.info(`fileName is: ${dirPath}`) - Logger.info(`uri schema is ${vscode.env.uriScheme}`) - let fileNameUri = vscode.Uri.file(packDir) - // if we are already inside a remote, the URI prefix should be `vscode://` - if (vscode.env.remoteName === 'dev-container') { - const local_workspace_path = process.env.LOCAL_WORKSPACE_PATH - if (!local_workspace_path) { - return - } - const reltaveFileName = vscode.workspace.asRelativePath(dirPath) - Logger.debug(`relative pack is ${reltaveFileName}`) - const localFileName = path.join(local_workspace_path, reltaveFileName).replaceAll('\\', '/') - Logger.debug(`local file path is ${localFileName}`) - fileNameUri = vscode.Uri.parse(`vscode://${localFileName}`) - } - else if (vscode.env.remoteName === "wsl") { - fileNameUri = vscode.Uri.parse(`vscode://${packDir}`) - } - - if (!(await vscode.commands.getCommands()).includes('remote-containers.openFolder')) { - vscode.window.showErrorMessage('Please install remote-containers extension to use this feature') - } - else { - // second argument is open in new window - vscode.commands.executeCommand('remote-containers.openFolder', fileNameUri, true) - } +export async function openIntegrationDevContainer( + dirPath: string +): Promise { + const filePath = path.parse(dirPath); + const packDir = path.resolve(path.join(dirPath, "..", "..")); + + const vsCodePath = path.join(packDir, ".vscode"); + + const devcontainerFolder = path.join(packDir, ".devcontainer"); + Logger.info(`devcontainerFolder is ${devcontainerFolder}`); + Logger.info("Create json configuration for debugging"); + if (!(await fs.pathExists(vsCodePath))) { + fs.mkdirSync(vsCodePath); + } + const ymlFilePath = path.join(dirPath, filePath.name.concat(".yml")); + const ymlObject = yaml + .parseDocument(fs.readFileSync(ymlFilePath, "utf8")) + .toJSON(); + + let dockerImage = ymlObject.dockerimage || ymlObject?.script.dockerimage; + dockerImage = dockerImage.replace("demisto", "devtestdemisto"); + Logger.info(`docker image is ${dockerImage}`); + const devcontainerJsonPath = path.resolve( + __dirname, + "../Templates/integration_env/.devcontainer/devcontainer.json" + ); + const devcontainer = JSON5.parse( + fs.readFileSync(devcontainerJsonPath, "utf-8") + ); + vscode.window.showInformationMessage("Building devcontainer folder"); + fs.copySync( + path.resolve(__dirname, "../Templates/integration_env/.devcontainer"), + devcontainerFolder + ); + fs.copySync( + path.resolve(__dirname, "../Scripts/create_certs.sh"), + path.join(devcontainerFolder, "create_certs.sh") + ); + Logger.info("devcontainer folder created"); + vscode.window.showInformationMessage( + "Starting demisto-sdk lint, please wait" + ); + devcontainer.name = `XSOAR Integration: ${filePath.name}`; + + // lint currently does not remove commonserverpython file for some reason + const CommonServerPython = path.join(dirPath, "CommonServerPython.py"); + if ( + filePath.name !== "CommonServerPython" && + (await fs.pathExists(CommonServerPython)) + ) { + fs.removeSync(CommonServerPython); + } + createLaunchJson(ymlObject.type, dirPath, filePath, vsCodePath); + createSettings(vsCodePath, dirPath, "/usr/local/bin/python", false); + + await dsdk.lint(dirPath, false, false, false, true); + + // delete cache folders and *.pyc files + fs.rmdir(path.join(dirPath, "__pycache__"), { recursive: true }); + fs.rmdir(path.join(dirPath, ".pytest_cache"), { recursive: true }); + fs.rmdir(path.join(dirPath, ".mypy_cache"), { recursive: true }); + fs.rmdir(path.join(dirPath, "__pycache__"), { recursive: true }); + // glob for *.pyc files and remove + const pycFiles = glob.sync(path.join(dirPath, "*.pyc")); + pycFiles.forEach((file) => { + fs.remove(file); + }); + + try { + const testDockerImage = execSync( + `docker images --format "{{.Repository}}:{{.Tag}}" | grep ${dockerImage} | head -1`, + { cwd: dirPath } + ) + .toString() + .trim(); + if (!testDockerImage) { + Logger.error("Docker image not found, exiting"); + vscode.window.showErrorMessage("Docker image not found, exiting"); + return; + } + devcontainer.build.args.IMAGENAME = testDockerImage; + fs.writeJSONSync( + path.join(devcontainerFolder, "devcontainer.json"), + devcontainer, + { spaces: 2 } + ); + } catch (err) { + Logger.error(`Could not find docker image ${dockerImage}: ${err}}`); + throw new Error(`Could not find docker image ${dockerImage}: ${err}}`); + } + Logger.info(`remote name is: ${vscode.env.remoteName}`); + Logger.info(`fileName is: ${dirPath}`); + Logger.info(`uri schema is ${vscode.env.uriScheme}`); + let fileNameUri = vscode.Uri.file(packDir); + // if we are already inside a remote, the URI prefix should be `vscode://` + if (vscode.env.remoteName === "dev-container") { + const local_workspace_path = process.env.LOCAL_WORKSPACE_PATH; + if (!local_workspace_path) { + return; + } + const reltaveFileName = vscode.workspace.asRelativePath(dirPath); + Logger.debug(`relative pack is ${reltaveFileName}`); + const localFileName = path + .join(local_workspace_path, reltaveFileName) + .replaceAll("\\", "/"); + Logger.debug(`local file path is ${localFileName}`); + fileNameUri = vscode.Uri.parse(`vscode://${localFileName}`); + } else if (vscode.env.remoteName === "wsl") { + fileNameUri = vscode.Uri.parse(`vscode://${packDir}`); + } + + if ( + !(await vscode.commands.getCommands()).includes( + "remote-containers.openFolder" + ) + ) { + vscode.window.showErrorMessage( + "Please install remote-containers extension to use this feature" + ); + } else { + // second argument is open in new window + vscode.commands.executeCommand( + "remote-containers.openFolder", + fileNameUri, + true + ); + } } -async function createLaunchJson(type: string, dirPath: string, filePath: path.ParsedPath, vsCodePath: string) { - let launchJson; - const cwd = '${workspaceFolder}/' + path.relative(path.join(vsCodePath, '..'), dirPath) - if (type === 'powershell') { - const launchJsonPath = path.resolve(__dirname, '../Templates/launch-powershell.json'); - launchJson = JSON5.parse(fs.readFileSync(launchJsonPath, 'utf-8')); - const script = path.join(cwd, filePath.name.concat('.ps1')); - launchJson.configurations[0].script = script; - launchJson.configurations[0].cwd = cwd; - } - else { - const launchJsonPath = path.resolve(__dirname, '../Templates/launch-python.json'); - launchJson = JSON5.parse(fs.readFileSync(launchJsonPath, 'utf-8')); - const program = path.join(cwd, filePath.name.concat('.py')); - launchJson.configurations[0].program = program; - launchJson.configurations[0].cwd = cwd; - } - const launchJsonOutput = path.join(vsCodePath, 'launch.json'); - if (!await fs.pathExists(vsCodePath)) { - fs.mkdirSync(vsCodePath); - } - Logger.info('Copy launch.json'); - fs.writeJsonSync(launchJsonOutput, launchJson, { spaces: 2 }); +async function createLaunchJson( + type: string, + dirPath: string, + filePath: path.ParsedPath, + vsCodePath: string +) { + let launchJson; + const cwd = + "${workspaceFolder}/" + path.relative(path.join(vsCodePath, ".."), dirPath); + if (type === "powershell") { + const launchJsonPath = path.resolve( + __dirname, + "../Templates/launch-powershell.json" + ); + launchJson = JSON5.parse(fs.readFileSync(launchJsonPath, "utf-8")); + const script = path.join(cwd, filePath.name.concat(".ps1")); + launchJson.configurations[0].script = script; + launchJson.configurations[0].cwd = cwd; + } else { + const launchJsonPath = path.resolve( + __dirname, + "../Templates/launch-python.json" + ); + launchJson = JSON5.parse(fs.readFileSync(launchJsonPath, "utf-8")); + const program = path.join(cwd, filePath.name.concat(".py")); + launchJson.configurations[0].program = program; + launchJson.configurations[0].cwd = cwd; + } + const launchJsonOutput = path.join(vsCodePath, "launch.json"); + if (!(await fs.pathExists(vsCodePath))) { + fs.mkdirSync(vsCodePath); + } + Logger.info("Copy launch.json"); + fs.writeJsonSync(launchJsonOutput, launchJson, { spaces: 2 }); } export async function openInVirtualenv(dirPath: string): Promise { - const contentPath = getContentPath() - if (!contentPath) { - vscode.window.showErrorMessage('Please run this from Content repository') - return - } - Logger.info(`Creating virtualenv in ${dirPath}`) - const filePath = path.parse(dirPath) - const packDir = path.resolve(path.join(dirPath, '..', '..')) - const vsCodePath = path.join(packDir, '.vscode') - if (!await fs.pathExists(vsCodePath)) { - fs.mkdirSync(vsCodePath) - } - - let shouldCreateVirtualenv = true - if (await fs.pathExists(path.join(dirPath, 'venv'))) { - //show input dialog if create virtualenv - Logger.info('Virtualenv exists.') - await vscode.window.showQuickPick(["Open existing virtual environment", "Create new virtual environment"], { - title: `Found virtual environemnt in ${filePath.name}`, - placeHolder: "Creating virtual environment can take few minutes" - }) - .then(async (answer) => { - if (answer === "Create new virtual environment") { - //remove venv dir - await fs.remove(path.join(dirPath, 'venv')) - shouldCreateVirtualenv = true - } - else { - shouldCreateVirtualenv = false - } - } - ) - } - const ymlFilePath = path.join(dirPath, filePath.name.concat('.yml')) - const ymlObject = yaml.parseDocument(fs.readFileSync(ymlFilePath, 'utf8')).toJSON(); - - // lint currently does not remove commonserverpython file for some reason - const CommonServerPython = path.join(dirPath, 'CommonServerPython.py') - if (filePath.name !== "CommonServerPython" && await fs.pathExists(CommonServerPython)) { - fs.removeSync(CommonServerPython) - } - createLaunchJson(ymlObject.type, dirPath, filePath, vsCodePath); - createSettings(vsCodePath, dirPath, path.join(dirPath, 'venv', 'bin', 'python'), true); - await addPythonPath() - fs.copySync(path.join(contentPath, '.env'), path.join(packDir, '.env')) - - Logger.info('Run lint') - await dsdk.lint(dirPath, false, false, false, true) - - if (shouldCreateVirtualenv) { - vscode.window.showInformationMessage('Creating virtual environment. Might take a few minutes.') - - let dockerImage = ymlObject.dockerimage || ymlObject?.script.dockerimage - dockerImage = dockerImage.replace('demisto', 'devtestdemisto') - Logger.info(`docker image is ${dockerImage}, getting data`) - vscode.window.showInformationMessage(`Creating virtualenv, please wait`) - await createVirtualenv(filePath.name, dirPath, dockerImage) - } - const workspace = { 'folders': [{ 'path': contentPath }, { 'path': packDir }], 'settings': {} } - const workspaceOutput = path.join(vsCodePath, `content-${filePath.name}.code-workspace`) - fs.writeJsonSync(workspaceOutput, workspace, { spaces: 2 }) - const response = await vscode.window.showQuickPick(['Existing Window', 'New Window'], + const contentPath = getContentPath(); + if (!contentPath) { + vscode.window.showErrorMessage("Please run this from Content repository"); + return; + } + Logger.info(`Creating virtualenv in ${dirPath}`); + const filePath = path.parse(dirPath); + const packDir = path.resolve(path.join(dirPath, "..", "..")); + const vsCodePath = path.join(packDir, ".vscode"); + if (!(await fs.pathExists(vsCodePath))) { + fs.mkdirSync(vsCodePath); + } + + let shouldCreateVirtualenv = true; + if (await fs.pathExists(path.join(dirPath, "venv"))) { + //show input dialog if create virtualenv + Logger.info("Virtualenv exists."); + await vscode.window + .showQuickPick( + ["Open existing virtual environment", "Create new virtual environment"], { - placeHolder: 'Select if you want to open in existing window or new window', - title: 'Where would you like to open the environment?' - }) - const openInNewWindow = response === 'New Window' - vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(workspaceOutput), openInNewWindow) + title: `Found virtual environemnt in ${filePath.name}`, + placeHolder: "Creating virtual environment can take few minutes", + } + ) + .then(async (answer) => { + if (answer === "Create new virtual environment") { + //remove venv dir + await fs.remove(path.join(dirPath, "venv")); + shouldCreateVirtualenv = true; + } else { + shouldCreateVirtualenv = false; + } + }); + } + const ymlFilePath = path.join(dirPath, filePath.name.concat(".yml")); + const ymlObject = yaml + .parseDocument(fs.readFileSync(ymlFilePath, "utf8")) + .toJSON(); + + // lint currently does not remove commonserverpython file for some reason + const CommonServerPython = path.join(dirPath, "CommonServerPython.py"); + if ( + filePath.name !== "CommonServerPython" && + (await fs.pathExists(CommonServerPython)) + ) { + fs.removeSync(CommonServerPython); + } + createLaunchJson(ymlObject.type, dirPath, filePath, vsCodePath); + createSettings( + vsCodePath, + dirPath, + path.join(dirPath, "venv", "bin", "python"), + true + ); + await addPythonPath(); + fs.copySync(path.join(contentPath, ".env"), path.join(packDir, ".env")); + + Logger.info("Run lint"); + await dsdk.lint(dirPath, false, false, false, true); + + if (shouldCreateVirtualenv) { + vscode.window.showInformationMessage( + "Creating virtual environment. Might take a few minutes." + ); + + let dockerImage = ymlObject.dockerimage || ymlObject?.script.dockerimage; + dockerImage = dockerImage.replace("demisto", "devtestdemisto"); + Logger.info(`docker image is ${dockerImage}, getting data`); + vscode.window.showInformationMessage(`Creating virtualenv, please wait`); + await createVirtualenv(filePath.name, dirPath, dockerImage); + } + const workspace = { + folders: [{ path: contentPath }, { path: packDir }], + settings: {}, + }; + const workspaceOutput = path.join( + vsCodePath, + `content-${filePath.name}.code-workspace` + ); + fs.writeJsonSync(workspaceOutput, workspace, { spaces: 2 }); + const response = await vscode.window.showQuickPick( + ["Existing Window", "New Window"], + { + placeHolder: + "Select if you want to open in existing window or new window", + title: "Where would you like to open the environment?", + } + ); + const openInNewWindow = response === "New Window"; + vscode.commands.executeCommand( + "vscode.openFolder", + vscode.Uri.file(workspaceOutput), + openInNewWindow + ); } -async function createSettings(vsCodePath: string, dirPath: string, interpreterPath: string, changeLinterPath: boolean) { - Logger.info('Getting settings.json'); - const contentPath = getContentPath() - if (!contentPath) { - throw new Error("No content path configured") - } - const settingsPath = path.join(vsCodePath, 'settings.json') - // create if not exists - if (!await fs.pathExists(settingsPath)) { - Logger.info('Creating settings.json') - fs.writeJSONSync(settingsPath, {}) - } - - const settings = JSON5.parse(fs.readFileSync(settingsPath, 'utf-8')); - Logger.info('Setting settings.json to venv'); - const relativePath = '${workspaceFolder}/' + path.relative(path.join(vsCodePath, '..'), dirPath) - settings['python.defaultInterpreterPath'] = interpreterPath; - settings['python.testing.cwd'] = relativePath; - settings["python.testing.pytestEnabled"] = true; - settings["python.testing.pytestArgs"] = ["."]; - settings["python.linting.mypyEnabled"] = true; - settings["python.linting.mypyArgs"] = [ - "--follow-imports=silent", - "--ignore-missing-imports", - "--show-column-numbers", - "--no-pretty", - "--allow-redefinition", - "--check-untyped-defs", - ]; - settings["python.linting.flake8Enabled"] = true; - - if (changeLinterPath && fs.pathExistsSync(path.join(contentPath, ".venv"))) { - settings["python.linting.mypyPath"] = `${contentPath}/.venv/bin/mypy` - settings["python.linting.flake8Path"] = `${contentPath}/.venv/bin/flake8` - settings["python.formatting.autopep8Path"] = `${contentPath}/.venv/bin/autopep8` - } - else { - settings["python.linting.mypyPath"] = 'mypy' - settings["python.linting.flake8Path"] = 'flake8' - settings["python.formatting.autopep8Path"] = 'autopep8' - - } - fs.writeJSONSync(settingsPath, settings, { spaces: 2 }); +async function createSettings( + vsCodePath: string, + dirPath: string, + interpreterPath: string, + changeLinterPath: boolean +) { + Logger.info("Getting settings.json"); + const contentPath = getContentPath(); + if (!contentPath) { + throw new Error("No content path configured"); + } + const settingsPath = path.join(vsCodePath, "settings.json"); + // create if not exists + if (!(await fs.pathExists(settingsPath))) { + Logger.info("Creating settings.json"); + fs.writeJSONSync(settingsPath, {}); + } + + const settings = JSON5.parse(fs.readFileSync(settingsPath, "utf-8")); + Logger.info("Setting settings.json to venv"); + const relativePath = + "${workspaceFolder}/" + path.relative(path.join(vsCodePath, ".."), dirPath); + settings["python.defaultInterpreterPath"] = interpreterPath; + settings["python.testing.cwd"] = relativePath; + settings["python.testing.pytestEnabled"] = true; + settings["python.testing.pytestArgs"] = ["."]; + settings["python.linting.mypyEnabled"] = true; + settings["python.linting.mypyArgs"] = [ + "--follow-imports=silent", + "--ignore-missing-imports", + "--show-column-numbers", + "--no-pretty", + "--allow-redefinition", + "--check-untyped-defs", + ]; + settings["python.linting.flake8Enabled"] = true; + + if (changeLinterPath && fs.pathExistsSync(path.join(contentPath, ".venv"))) { + settings["python.linting.mypyPath"] = `${contentPath}/.venv/bin/mypy`; + settings["python.linting.flake8Path"] = `${contentPath}/.venv/bin/flake8`; + settings[ + "python.formatting.autopep8Path" + ] = `${contentPath}/.venv/bin/autopep8`; + } else { + settings["python.linting.mypyPath"] = "mypy"; + settings["python.linting.flake8Path"] = "flake8"; + settings["python.formatting.autopep8Path"] = "autopep8"; + } + fs.writeJSONSync(settingsPath, settings, { spaces: 2 }); } async function bootstrapContent(dirPath: string, shouldPreCommit: boolean) { - Logger.info('Bootstrap content') - let command = `${dirPath}/.hooks/bootstrap` - if (!shouldPreCommit) { - command = `NO_HOOKS=1 ${command}` - } - command = `export PATH=/opt/homebrew/bin:"$PATH" && ${command}` - const task = new vscode.Task( - { type: 'bootstrap', name: 'Bootstrap content' }, - vscode.TaskScope.Workspace, - 'bootstrap', - 'bootstrap', - new vscode.ShellExecution(command), - ) - return new Promise(resolve => { - vscode.window.withProgress({ - title: `Bootstrap content`, - location: vscode.ProgressLocation.Notification - }, async (progress) => { - progress.report({ message: `In bootstrap please wait` }) - const execution = await vscode.tasks.executeTask(task); - const disposable = vscode.tasks.onDidEndTaskProcess(e => { - if (e.execution === execution) { - if (e.exitCode === 0) { - disposable.dispose() - resolve() - } - else { - vscode.window.showErrorMessage('Could not bootstrap content') - throw new Error('Could not bootstrap content') - } - } - }) - progress.report({ message: "Processing..." }); - }) - - }) - + Logger.info("Bootstrap content"); + let command = `${dirPath}/.hooks/bootstrap`; + if (!shouldPreCommit) { + command = `NO_HOOKS=1 ${command}`; + } + command = `export PATH=/opt/homebrew/bin:"$PATH" && ${command}`; + const task = new vscode.Task( + { type: "bootstrap", name: "Bootstrap content" }, + vscode.TaskScope.Workspace, + "bootstrap", + "bootstrap", + new vscode.ShellExecution(command) + ); + return new Promise((resolve) => { + vscode.window.withProgress( + { + title: `Bootstrap content`, + location: vscode.ProgressLocation.Notification, + }, + async (progress) => { + progress.report({ message: `In bootstrap please wait` }); + const execution = await vscode.tasks.executeTask(task); + const disposable = vscode.tasks.onDidEndTaskProcess((e) => { + if (e.execution === execution) { + if (e.exitCode === 0) { + disposable.dispose(); + resolve(); + } else { + vscode.window.showErrorMessage("Could not bootstrap content"); + throw new Error("Could not bootstrap content"); + } + } + }); + progress.report({ message: "Processing..." }); + } + ); + }); } -async function createVirtualenv(name: string, dirPath: string, dockerImage: string): Promise { - // this implemented in a script, should be a command in SDK. - // When SDK added this command, change to use it as wrapper. - Logger.info('Running virtualenv task') - const setupVenvScript = path.resolve(__dirname, '../Scripts/setup_venv.sh') - const cmd = `${setupVenvScript} ${dockerImage} ${name} ${dirPath} ` + "${command:python.interpreterPath}" - const task = new vscode.Task( - { type: 'virtualenv', name: 'Setup virtualenv' }, - vscode.TaskScope.Workspace, - 'virtualenv', - 'virtualenv', - new vscode.ShellExecution(cmd, { cwd: dirPath })); - return new Promise(resolve => { - vscode.window.withProgress({ - cancellable: false, - title: `Creating virtualenv in ${dirPath}`, - location: vscode.ProgressLocation.Notification - }, async (progress) => { - progress.report({ message: `Creating virtualenv please wait` }) - const execution = await vscode.tasks.executeTask(task); - const disposable = vscode.tasks.onDidEndTaskProcess(e => { - if (e.execution === execution) { - if (e.exitCode === 0) { - disposable.dispose() - resolve() - } - else { - vscode.window.showErrorMessage('Could not create virtualenv') - throw new Error('Could not create virtualenv') - } - } - }) - progress.report({ message: "Processing..." }); - }) - }) +async function createVirtualenv( + name: string, + dirPath: string, + dockerImage: string +): Promise { + // this implemented in a script, should be a command in SDK. + // When SDK added this command, change to use it as wrapper. + Logger.info("Running virtualenv task"); + const setupVenvScript = path.resolve(__dirname, "../Scripts/setup_venv.sh"); + const cmd = + `${setupVenvScript} ${dockerImage} ${name} ${dirPath} ` + + "${command:python.interpreterPath}"; + const task = new vscode.Task( + { type: "virtualenv", name: "Setup virtualenv" }, + vscode.TaskScope.Workspace, + "virtualenv", + "virtualenv", + new vscode.ShellExecution(cmd, { cwd: dirPath }) + ); + return new Promise((resolve) => { + vscode.window.withProgress( + { + cancellable: false, + title: `Creating virtualenv in ${dirPath}`, + location: vscode.ProgressLocation.Notification, + }, + async (progress) => { + progress.report({ message: `Creating virtualenv please wait` }); + const execution = await vscode.tasks.executeTask(task); + const disposable = vscode.tasks.onDidEndTaskProcess((e) => { + if (e.execution === execution) { + if (e.exitCode === 0) { + disposable.dispose(); + resolve(); + } else { + vscode.window.showErrorMessage("Could not create virtualenv"); + throw new Error("Could not create virtualenv"); + } + } + }); + progress.report({ message: "Processing..." }); + } + ); + }); } - - diff --git a/src/terminalManager.ts b/src/terminalManager.ts index dc0240c..f1addba 100644 --- a/src/terminalManager.ts +++ b/src/terminalManager.ts @@ -23,12 +23,8 @@ export class TerminalManager { options: ProcessEnvOptions ): Promise { const sdkPath = tools.getSDKPath() - let cmd = ''; - if (sdkPath) { - cmd = `${tools.getSDKPath()} ${command.join(' ')}` - } else { - cmd = `${tools.getPythonpath()} -m demisto_sdk ${command.join(' ')}` - } + const cmd = `${sdkPath} ${command.join(' ')}`; + Logger.info(`Executing command in background: \`${cmd}\``) exec(cmd, options, (error, stdout) => { if (error) { @@ -43,11 +39,10 @@ export class TerminalManager { public static async sendDemistoSdkCommandWithProgress(command: string[]): Promise { const sdkPath = tools.getSDKPath() - let cmd = "source $(dirname '${command:python.interpreterPath}')/activate || true && " - if (sdkPath) { - cmd += `${tools.getSDKPath()} ${command.join(' ')}` - } else { - cmd += `${tools.getPythonpath()} -m demisto_sdk ${command.join(' ')}` + let cmd = `${sdkPath} ${command.join(' ')}` + const contentPath = tools.getContentPath() + if (contentPath){ + cmd = `cd ${contentPath} && ${cmd}` } const task = new vscode.Task( { type: 'demisto-sdk', name: command[0] }, @@ -109,6 +104,7 @@ export class TerminalManager { newTerminal = false, timeout = 10000 ): Promise { + const contentPath = tools.getContentPath() if (!await tools.isDemistoSDKinstalled()){ vscode.window.showErrorMessage('Demisto-SDK is not available in your environment') return @@ -123,6 +119,9 @@ export class TerminalManager { terminal.hide() } terminal.sendText('') + if (contentPath) { + terminal.sendText(`cd ${contentPath}`) + } terminal.sendText(`${tools.getSDKPath()} ${command.join(' ')}`) await this.delay(timeout) } diff --git a/src/tools.ts b/src/tools.ts index 1e30c87..0daa7b8 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -4,6 +4,7 @@ import * as vscode from "vscode"; import { DiagnosticCollection } from "vscode"; import * as yaml from "yaml"; import { AutomationI, IntegrationI } from './contentObject'; +import * as fs from "fs-extra"; import { Logger } from './logger'; import { TerminalManager } from './terminalManager'; @@ -22,7 +23,7 @@ export function sendCommandExtraArgsWithUserInput(command: string[]): void { export function getContentPath(): string | undefined { const workspaces = vscode.workspace.workspaceFolders - if (!workspaces){ + if (!workspaces) { return } for (const workspace of workspaces) { @@ -46,31 +47,40 @@ export function getPythonpath(): string { } export function getSDKPath(): string { - const sdkPath = vscode.workspace.getConfiguration('xsoar').get('demisto-sdk.Path') - return sdkPath + const sdkPath = `${getContentPath()}/.venv/bin/demisto-sdk` + if (fs.existsSync(sdkPath)) { + return sdkPath + } + return 'demisto-sdk' } export async function installDemistoSDK(): Promise { - vscode.window.showQuickPick(['Global', 'Local'], { - title: 'Install Demisto SDK globally or locally?', - placeHolder: 'Global will install demisto-sdk with pipx. Local will install demisto-sdk with pip.' + vscode.window.showQuickPick(['Poetry', 'Pip'], { + title: 'Install Demisto SDK with Poetry or with Pip?', + placeHolder: 'Poetry is recommended' }).then(answer => { - if (answer === 'Global') { - installDemistoSDKGlobally() + if (answer === 'Poetry') { + installDemistoSDKPoetry() } else if (answer == 'Local') { - installDemistoSDKLocally() + installDemistoSDKPip() } }) } -export async function installDemistoSDKLocally(): Promise { +export async function installDemistoSDKPip(): Promise { TerminalManager.sendText(['pip', 'install', 'demisto-sdk', '--upgrade']); } -export async function installDemistoSDKGlobally(): Promise { - // if pipx is installed no need to install pipx with pip - TerminalManager.sendText('(pipx --version || pip install pipx) && pipx ensurepath --force && pipx install demisto-sdk --force && pipx upgrade demisto-sdk'); +export async function installDemistoSDKPoetry(): Promise { + const contentPath = getContentPath() + if (!contentPath) { + TerminalManager.sendText(['pip', 'install', 'demisto-sdk', '--upgrade']); + } + else { + TerminalManager.sendText(['cd', contentPath]) + TerminalManager.sendText(['poetry', 'install']) + } } export async function isDemistoSDKinstalled(): Promise { @@ -79,7 +89,7 @@ export async function isDemistoSDKinstalled(): Promise { return true } Logger.error('demisto-sdk is not installed') - await installDemistoSDK() + await installDemistoSDKPoetry() await new Promise(resolve => setTimeout(resolve, 15000)) return TerminalManager.sendDemistoSdkCommandWithProgress(['--version']) }