From a5829d07daa47fb90838682521a22cbb170b967f Mon Sep 17 00:00:00 2001 From: Hazzard17 Date: Fri, 30 Aug 2019 14:24:37 +0200 Subject: [PATCH 1/6] Update some output messages --- src/commands/deploy.ts | 6 ++---- src/utils/ValidationsHandler.ts | 12 +++++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index b2af2fb4..11a4fb1f 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -223,10 +223,8 @@ export default class Deploy extends Command { await this.deploy(deployParams) return Promise.resolve(undefined) } else { - StdOutUtil.printError( - `Can't find previously saved deploy options from this directory, can't use --default.\nFalling back to asking questions...\n\n`, - false - ) + StdOutUtil.printError(`Can't find previously saved deploy options from this directory, can't use --default.\n`) + StdOutUtil.printMessage('Falling back to asking questions...\n') } } else if ( possibleApp && diff --git a/src/utils/ValidationsHandler.ts b/src/utils/ValidationsHandler.ts index 5b075f73..d0a2e0b1 100644 --- a/src/utils/ValidationsHandler.ts +++ b/src/utils/ValidationsHandler.ts @@ -11,13 +11,15 @@ const isWindows = process.platform === 'win32' export function validateIsGitRepository() { if (!fs.pathExistsSync('./.git')) { StdOutUtil.printError( - 'You are not in a git root directory: this command will only deploys the current directory.\n', + 'You are not in a git root directory: this command will only deploys the current directory.\n' + + 'Run "caprover deploy --help" to know more deployment options... (e.g. tar file or image name)\n', true ) } if (!commandExistsSync('git')) { StdOutUtil.printError( - '"git" command not found: CapRover needs "git" to create tar file from your branch source files...\n', + '"git" command not found: CapRover needs "git" to create tar file from your branch source files.\n' + + 'Run "caprover deploy --help" to know more deployment options... (e.g. tar file or image name)\n', true ) } @@ -156,10 +158,10 @@ export function getErrorForAppName( export function getErrorForBranchName(value: string): true | string { if (!value || !value.trim()) return 'Please enter branch name.' value = value.trim() - const cmd = isWindows - ? execSync(`git rev-parse ${value} > NUL`) - : execSync(`git rev-parse ${value} 2>/dev/null`) try { + const cmd = isWindows + ? execSync(`git rev-parse ${value} > NUL`) + : execSync(`git rev-parse ${value} 2>/dev/null`) if (cmd) return true } catch (e) {} return `Cannot find hash of last commit on branch "${value}".` From 7647ce8b6696799c2e475f7108a47c423069711c Mon Sep 17 00:00:00 2001 From: Hazzard17 Date: Mon, 2 Sep 2019 18:00:17 +0200 Subject: [PATCH 2/6] Ensure authentication during deployment with --default --- src/commands/Command.ts | 25 +++++++------- src/commands/api.ts | 4 ++- src/commands/deploy.ts | 70 +++++++++++++++++++++++++++++++------- src/utils/CliHelper.ts | 31 +++++++++-------- src/utils/StorageHelper.ts | 6 ++++ 5 files changed, 94 insertions(+), 42 deletions(-) diff --git a/src/commands/Command.ts b/src/commands/Command.ts index 691d52b4..98b3ad6a 100644 --- a/src/commands/Command.ts +++ b/src/commands/Command.ts @@ -29,6 +29,7 @@ export enum ParamType { CommandLine, Question, Env, + Default, } export interface IParam { @@ -148,19 +149,7 @@ export default abstract class Command { if (this.description) cmd.description(this.description) if (this.usage) cmd.usage(this.usage) - let options = this.getOptions().filter(opt => opt && opt.name) - const optionAliases: IOptionAliasWithDetails[] = options.reduce( - (acc, opt) => [ - ...acc, - { ...opt, aliasTo: opt.name }, - ...(opt.aliases || []) - .filter(alias => alias && alias.name) - .map(alias => ({ ...alias, aliasTo: opt.name })), - ], - [] - ) - - options = options.filter(opt => !opt.hide) + const options = this.getOptions().filter(opt => opt && opt.name && !opt.hide) const spaces = ' '.repeat( options.reduce( (max, opt) => @@ -204,7 +193,17 @@ export default abstract class Command { `Positional parameter not supported: ${allParams[0]}\n`, true ) + const cmdLineOptions = await this.preAction(allParams[0]) + const optionAliases: IOptionAliasWithDetails[] = this.getOptions() + .filter(opt => opt && opt.name) + .reduce((acc, opt) => [ + ...acc, + { ...opt, aliasTo: opt.name }, + ...(opt.aliases || []) + .filter(alias => alias && alias.name) + .map(alias => ({ ...alias, aliasTo: opt.name })), + ], []) if (cmdLineOptions) this.action(await this.getParams(cmdLineOptions, optionAliases)) diff --git a/src/commands/api.ts b/src/commands/api.ts index 87f1548d..835827a1 100644 --- a/src/commands/api.ts +++ b/src/commands/api.ts @@ -87,7 +87,9 @@ export default class Api extends Command { : undefined, }, CliHelper.get().getEnsureAuthenticationOption( - params, + () => this.paramValue(params, K.url), + () => this.paramValue(params, K.pwd), + () => this.paramValue(params, K.name), async (machine: IMachine) => { this.machine = machine try { diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index 11a4fb1f..97ebef97 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -69,7 +69,7 @@ export default class Deploy extends Command { 'use previously entered values for the current directory, no others options are considered', when: false, }, - this.getDefaultConfigFileOption(() => this.preQuestions(params!)), + this.getDefaultConfigFileOption(() => this.validateDeploySource(params!)), { name: K.url, char: 'u', @@ -110,7 +110,9 @@ export default class Deploy extends Command { : undefined, }, CliHelper.get().getEnsureAuthenticationOption( - params, + () => this.paramValue(params, K.url), + () => this.paramValue(params, K.pwd), + () => this.paramValue(params, K.name), async (machine: IMachine) => { this.machine = machine try { @@ -205,14 +207,7 @@ export default class Deploy extends Command { .find((dir: IDeployedDirectory) => dir.cwd === process.cwd()) if (cmdLineoptions[K.default]) { if (possibleApp && possibleApp.machineNameToDeploy) { - const deployParams: IDeployParams = { - captainMachine: StorageHelper.get().findMachine( - possibleApp.machineNameToDeploy - ), - deploySource: possibleApp.deploySource, - appName: possibleApp.appName, - } - if (!deployParams.captainMachine) { + if (!StorageHelper.get().findMachine(possibleApp.machineNameToDeploy)) { StdOutUtil.printError( `You have to first login to ${StdOutUtil.getColoredMachineName( possibleApp.machineNameToDeploy @@ -220,8 +215,57 @@ export default class Deploy extends Command { true ) } - await this.deploy(deployParams) - return Promise.resolve(undefined) + this.options = (params?: IParams) => [CliHelper.get().getEnsureAuthenticationOption( + undefined, + undefined, + possibleApp.machineNameToDeploy, + async (machine: IMachine) => { + this.machine = machine + try { + this.apps = + (await CliApiManager.get(machine).getAllApps()) + .appDefinitions || [] + } catch (e) { + StdOutUtil.printError( + `\nSomething bad happened during deployment to ${StdOutUtil.getColoredMachineName( + machine.name + )}.\n${e.message || e}`, + true + ) + } + + const appErr = getErrorForAppName(this.apps, possibleApp.appName) + if (appErr !== true) + StdOutUtil.printError( + `\n${appErr || 'Error!'}\n`, + true + ) + + if (params) { + params[K.app] = { + value: possibleApp.appName, + from: ParamType.Default + } + if (possibleApp.deploySource.branchToPush) + params[K.branch] = { + value: possibleApp.deploySource.branchToPush, + from: ParamType.Default + } + else if (possibleApp.deploySource.tarFilePath) + params[K.tar] = { + value: possibleApp.deploySource.tarFilePath, + from: ParamType.Default + } + else + params[K.img] = { + value: possibleApp.deploySource.imageName, + from: ParamType.Default + } + this.validateDeploySource(params) + } + } + )] + return Promise.resolve({}) } else { StdOutUtil.printError(`Can't find previously saved deploy options from this directory, can't use --default.\n`) StdOutUtil.printMessage('Falling back to asking questions...\n') @@ -242,7 +286,7 @@ export default class Deploy extends Command { return Promise.resolve(cmdLineoptions) } - protected preQuestions(params: IParams) { + protected validateDeploySource(params: IParams) { if ( (this.findParamValue(params, K.branch) ? 1 : 0) + (this.findParamValue(params, K.tar) ? 1 : 0) + diff --git a/src/utils/CliHelper.ts b/src/utils/CliHelper.ts index 177c0be9..6506f0b7 100644 --- a/src/utils/CliHelper.ts +++ b/src/utils/CliHelper.ts @@ -178,7 +178,9 @@ export default class CliHelper { } getEnsureAuthenticationOption( - params?: IParams, + url?: string | (() => string | undefined), + password?: string | (() => string | undefined), + name?: string | (() => string | undefined), done?: (machine: IMachine) => void ): IOption { let machine: IMachine @@ -189,27 +191,26 @@ export default class CliHelper { hide: true, when: async () => { StdOutUtil.printMessage('Ensuring authentication...') - const url: string | undefined = - params && params.caproverUrl && params.caproverUrl.value - const password: string | undefined = - params && - params.caproverPassword && - params.caproverPassword.value - const name: string | undefined = - params && params.caproverName && params.caproverName.value + + const getVal = (value?: string | (() => string | undefined)): string | undefined => + value && value instanceof Function ? value() : value + const _url = getVal(url) + const _password = getVal(password) + const _name = getVal(name) + try { machine = await CliHelper.get().ensureAuthentication( - url, - password, - name + _url, + _password, + _name ) return !machine.authToken } catch (e) { StdOutUtil.printError( `\nSomething bad happened during authentication to ${ - url - ? StdOutUtil.getColoredMachineUrl(url) - : StdOutUtil.getColoredMachineName(name || '') + _url + ? StdOutUtil.getColoredMachineUrl(_url) + : StdOutUtil.getColoredMachineName(_name || '') }.\n${e.message || e}`, true ) diff --git a/src/utils/StorageHelper.ts b/src/utils/StorageHelper.ts index 73ba7ec1..4b64ae42 100644 --- a/src/utils/StorageHelper.ts +++ b/src/utils/StorageHelper.ts @@ -69,6 +69,12 @@ export default class StorageHelper { } saveDeployedDirectory(directoryToSaveOrUpdate: IDeployedDirectory) { + if (!directoryToSaveOrUpdate || + !directoryToSaveOrUpdate.appName || + !directoryToSaveOrUpdate.cwd || + !directoryToSaveOrUpdate.machineNameToDeploy) + return; + const currDirs = this.getDeployedDirectories() let updatedDir = false for (let index = 0; index < currDirs.length; index++) { From ddb8dd93687fdcf7917d3deecfac86116eddded2 Mon Sep 17 00:00:00 2001 From: Hazzard17 Date: Mon, 2 Sep 2019 18:35:55 +0200 Subject: [PATCH 3/6] Add warning on setup with wrong IP --- src/commands/serversetup.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/commands/serversetup.ts b/src/commands/serversetup.ts index 1c61fe37..a0900880 100644 --- a/src/commands/serversetup.ts +++ b/src/commands/serversetup.ts @@ -211,6 +211,10 @@ export default class ServerSetup extends Command { StdOutUtil.printWarning( '\nYou may have already setup the server! Use caprover login to log into an existing server.' ) + } else { + StdOutUtil.printWarning( + '\nYou may have specified a wrong IP address or not already started CapRover container on your server!' + ) } StdOutUtil.errorHandler(e) return '' From f4112588b28b039b217a135ff24ce4f55642f9f5 Mon Sep 17 00:00:00 2001 From: Hazzard17 Date: Wed, 4 Sep 2019 14:17:44 +0200 Subject: [PATCH 4/6] Check fresh installation during serversetup --- src/commands/serversetup.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/commands/serversetup.ts b/src/commands/serversetup.ts index a0900880..41b14df4 100644 --- a/src/commands/serversetup.ts +++ b/src/commands/serversetup.ts @@ -116,6 +116,7 @@ export default class ServerSetup extends Command { aliases: [{ name: 'rootDomain', hide: true }], type: 'input', message: 'CapRover server root domain', + when: () => this.checkFreshInstallation(), // Server not already setupped filter: (domain: string) => Utils.cleanDomain(domain), validate: (domain: string) => domain @@ -221,6 +222,24 @@ export default class ServerSetup extends Command { } } + private async checkFreshInstallation(): Promise { + try { + const rootDomain: string = (await CliApiManager.get({ + authToken: this.machine.authToken, + baseUrl: `http://${this.ip}:${Constants.SETUP_PORT}`, + name: '', + }).getCaptainInfo()).rootDomain + if (rootDomain) + StdOutUtil.printWarning( + `\nYou may have already setup the server with root domain: ${rootDomain}! Use caprover login to log into an existing server.`, + true + ) + } catch (e) { + StdOutUtil.errorHandler(e) + } + return true + } + private async updateRootDomain(rootDomain: string) { const adminDomain = Utils.cleanAdminDomainUrl(rootDomain, false)! try { From b86f93a5ed6ea2a5dfc3389b4b5f229b0a710d5b Mon Sep 17 00:00:00 2001 From: Hazzard17 Date: Wed, 18 Sep 2019 17:34:28 +0200 Subject: [PATCH 5/6] Create admin-domain from root-domain during serversetup --- src/commands/serversetup.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/commands/serversetup.ts b/src/commands/serversetup.ts index 41b14df4..005fc46e 100644 --- a/src/commands/serversetup.ts +++ b/src/commands/serversetup.ts @@ -66,7 +66,7 @@ export default class ServerSetup extends Command { 'Start it by running the following line:' ) StdOutUtil.printMessage( - 'mkdir /captain && docker run -p 80:80 -p 443:443 -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock -v /captain:/captain caprover/caprover' + 'docker run -p 80:80 -p 443:443 -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock -v /captain:/captain caprover/caprover' ) StdOutUtil.printMessageAndExit( '\nPlease read tutorial on CapRover.com to learn how to install CapRover on a server.\n' @@ -241,14 +241,13 @@ export default class ServerSetup extends Command { } private async updateRootDomain(rootDomain: string) { - const adminDomain = Utils.cleanAdminDomainUrl(rootDomain, false)! try { await CliApiManager.get({ authToken: this.machine.authToken, baseUrl: `http://${this.ip}:${Constants.SETUP_PORT}`, name: '', }).updateRootDomain(rootDomain) - this.machine.baseUrl = adminDomain + this.machine.baseUrl = `http://${Constants.ADMIN_DOMAIN}.${rootDomain}` } catch (e) { if (e.captainStatus === ErrorFactory.VERIFICATION_FAILED) { StdOutUtil.printError( From 8326c7327595c9724cb177e2ddcb89f44f002659 Mon Sep 17 00:00:00 2001 From: Hazzard17 Date: Fri, 27 Sep 2019 16:37:43 +0200 Subject: [PATCH 6/6] Fix exit codes --- src/commands/serversetup.ts | 5 +++-- src/utils/StdOutUtil.ts | 26 +++++++++++--------------- src/utils/ValidationsHandler.ts | 5 +++-- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/commands/serversetup.ts b/src/commands/serversetup.ts index 005fc46e..8087b942 100644 --- a/src/commands/serversetup.ts +++ b/src/commands/serversetup.ts @@ -68,8 +68,9 @@ export default class ServerSetup extends Command { StdOutUtil.printMessage( 'docker run -p 80:80 -p 443:443 -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock -v /captain:/captain caprover/caprover' ) - StdOutUtil.printMessageAndExit( - '\nPlease read tutorial on CapRover.com to learn how to install CapRover on a server.\n' + StdOutUtil.printMessage( + '\nPlease read tutorial on CapRover.com to learn how to install CapRover on a server.\n', + true ) } }, diff --git a/src/utils/StdOutUtil.ts b/src/utils/StdOutUtil.ts index 211fa796..23f58bc4 100644 --- a/src/utils/StdOutUtil.ts +++ b/src/utils/StdOutUtil.ts @@ -2,38 +2,34 @@ import chalk from 'chalk' import { IMachine } from '../models/storage/StoredObjects' class StdOutUtils { - printMessage(message: string) { + printMessage(message: string, exit: boolean | number = false) { console.log(message) + if (exit !== false) process.exit(exit === true ? 0 : exit) } - printMessageAndExit(message: string) { - console.log(message) - process.exit(0) - } - - printGreenMessage(message: string, exit = false) { + printGreenMessage(message: string, exit: boolean | number = false) { console.log(`${chalk.green(message)}`) - exit && process.exit(0) + if (exit !== false) process.exit(exit === true ? 0 : exit) } - printMagentaMessage(message: string, exit = false) { + printMagentaMessage(message: string, exit: boolean | number = false) { console.log(`${chalk.magenta(message)}`) exit && process.exit(0) } - printError(error: string, exit = false) { + printError(error: string, exit: boolean | number = false) { console.log(`${chalk.bold.red(error)}`) - exit && process.exit(0) + if (exit !== false) process.exit(exit === true ? 1 : exit) } - printWarning(warning: string, exit = false) { + printWarning(warning: string, exit: boolean | number = false) { console.log(`${chalk.yellow(warning)}`) - exit && process.exit(0) + if (exit !== false) process.exit(exit === true ? 1 : exit) } - printTip(tip: string, exit = false) { + printTip(tip: string, exit: boolean | number = false) { console.log(`${chalk.bold.green(tip)}`) - exit && process.exit(0) + if (exit !== false) process.exit(exit === true ? 0 : exit) } errorHandler(error: any) { diff --git a/src/utils/ValidationsHandler.ts b/src/utils/ValidationsHandler.ts index d0a2e0b1..710d3955 100644 --- a/src/utils/ValidationsHandler.ts +++ b/src/utils/ValidationsHandler.ts @@ -175,10 +175,11 @@ export function getErrorForEmail(value: string): true | string { export function userCancelOperation(cancel: boolean, c?: boolean): boolean { if (cancel) - StdOutUtil.printMessageAndExit( + StdOutUtil.printMessage( (c ? '\n' : '') + '\nOperation cancelled by the user!' + - (!c ? '\n' : '') + (!c ? '\n' : ''), + true ) return false }