import Constants from '../utils/Constants' ; import Utils from '../utils/Utils' ; import StdOutUtil from '../utils/StdOutUtil' ; import StorageHelper from '../utils/StorageHelper' ; import CliHelper from '../utils/CliHelper' ; import DeployHelper from '../utils/DeployHelper' ; import CliApiManager from '../api/CliApiManager' ; import { validateIsGitRepository , validateDefinitionFile , getErrorForDomain , getErrorForPassword , getErrorForMachineName , userCancelOperation , getErrorForAppName , getErrorForBranchName } from '../utils/ValidationsHandler' ; import { IAppDef } from '../models/AppDef' ; import { IMachine , IDeployedDirectory , IDeployParams } from '../models/storage/StoredObjects' ; import Command , { IParams , IOption , ParamType , ICommandLineOptions , IParam } from './Command' ; const K = Utils . extendCommonKeys ( { default : 'default' , branch : 'branch' , tar : 'tarFile' , appToken : 'appToken' , img : 'imageName' } ) ; export default class Deploy extends Command { protected command = 'deploy' ; protected usage = '[options]\n' + '       deploy -d\n' + '       deploy -c file\n' + '       deploy [-c file] [-n name] [-a app] [-b branch | -t tarFile | -i image]\n' + '       deploy [-c file] -u url [-p password] [-n name] [-a app] [-b branch | -t tarFile | -i image]\n' + '  Use --caproverName to use an already logged in CapRover machine\n' + '  Use --caproverUrl and --caproverPassword to login on the fly to a CapRover machine, if also --caproverName is present, login credetials are stored locally\n' + '  Use one among --branch, --tarFile, --imageName' ; protected description = "Deploy your app to a specific CapRover machine. You'll be prompted for missing parameters." ; private machines = CliHelper . get ( ) . getMachinesAsOptions ( ) ; private apps : IAppDef [ ] = [ ] ; private machine : IMachine ; protected options = ( params ? ) : IOption [ ] => [ { name : K . default , char : 'd' , type : 'confirm' , message : 'use previously entered values for the current directory, no others options are considered' , when : false } , this . getDefaultConfigFileOption ( ( ) => this . validateDeploySource ( params ! ) ) , { name : K . url , char : 'u' , env : 'CAPROVER_URL' , aliases : [ { name : 'host' , char : 'h' } ] , type : 'input' , message : `CapRover machine URL address, it is "[http[s]://][${ Constants . ADMIN_DOMAIN }.]your-captain-root.domain"` , when : false , filter : ( url ) => Utils . cleanAdminDomainUrl ( url ) || url , validate : ( url ) => getErrorForDomain ( url , true ) } , { name : K . pwd , char : 'p' , env : 'CAPROVER_PASSWORD' , aliases : [ { name : 'pass' } ] , type : 'password' , message : 'CapRover machine password' , when : ! ! this . findParamValue ( params , K . url ) && ! this . findParamValue ( params , K . appToken ) , validate : ( password ) => getErrorForPassword ( password ) } , { name : K . name , char : 'n' , env : 'CAPROVER_NAME' , message : params ? 'select the CapRover machine name you want to deploy to' : 'CapRover machine name, to load/store credentials' , type : 'list' , choices : this . machines , when : ! this . findParamValue ( params , K . url ) , filter : ( name ) => ! this . findParamValue ( params , K . name ) ? userCancelOperation ( ! name , true ) || name : name . trim ( ) , validate : ! this . findParamValue ( params , K . url ) ? ( name ) => getErrorForMachineName ( name , true ) : undefined } , CliHelper . get ( ) . getEnsureAuthenticationOption ( this . paramValue ( params , K . appToken ) || '' , ( ) => this . paramValue ( params , K . url ) , ( ) => this . paramValue ( params , K . pwd ) , ( ) => this . paramValue ( params , K . name ) , async ( machine ) => { this . machine = machine ; try { if ( machine . appToken ) { this . apps = [ ] ; return ; } this . apps = ( await CliApiManager . get ( machine ) . getAllApps ( ) ) . appDefinitions || [ ] ; } catch ( e ) { StdOutUtil . printError ( `\nSomething bad happened during deployment to ${ StdOutUtil . getColoredMachineUrl ( machine . baseUrl ) }.\n${ e . message || e }` , true ) ; } } ) , { name : K . app , char : 'a' , env : 'CAPROVER_APP' , aliases : [ { name : 'appName' } ] , message : params ? 'select the app name you want to deploy to' : 'app name to deploy to' , type : 'list' , choices : ( ) => CliHelper . get ( ) . getAppsAsOptions ( this . apps ) , filter : ( app ) => ! this . findParamValue ( params , K . app ) ? userCancelOperation ( ! app , true ) || app : app . trim ( ) , validate : ( app ) => this . findParamValue ( params , K . appToken ) ? true : getErrorForAppName ( this . apps , app ) } , { name : K . branch , char : 'b' , env : 'CAPROVER_BRANCH' , message : 'git branch name to be deployed' + ( ! params ? ', current directory must be git root directory' : '' ) , type : 'input' , default : params && ( process . env . CAPROVER_DEFAULT_BRANCH || 'master' ) , when : ! this . findParamValue ( params , K . tar ) && ! this . findParamValue ( params , K . img ) , validate : ( branch ) => getErrorForBranchName ( branch ) } , { name : K . tar , char : 't' , env : 'CAPROVER_TAR_FILE' , message : 'tar file to be uploaded, must contain captain-definition file' , type : 'input' , when : false } , { name : K . img , char : 'i' , env : 'CAPROVER_IMAGE_NAME' , message : 'image name to be deployed, it should either exist on server, or it has to be public, or on a private repository that CapRover has access to' , type : 'input' , when : false } , { name : K . appToken , char : 't' , env : 'CAPROVER_APP_TOKEN' , message : 'app Token' , type : 'input' , when : false } , { name : 'confirmedToDeploy' , type : 'confirm' , message : ( ) => ( this . findParamValue ( params , K . branch ) ? 'note that uncommitted and gitignored files (if any) will not be pushed to server! A' : 'a' ) + 're you sure you want to deploy?' , default : true , hide : true , when : ( ) => this . paramFrom ( params , K . name ) === ParamType . Question || this . paramFrom ( params , K . app ) === ParamType . Question || this . paramFrom ( params , K . branch ) === ParamType . Question , preProcessParam : ( param ) => param && userCancelOperation ( ! param . value ) } ] ; protected async preAction ( cmdLineoptions ) { StdOutUtil . printMessage ( 'Preparing deployment to CapRover...\n' ) ; const possibleApp = StorageHelper . get ( ) . getDeployedDirectories ( ) . find ( ( dir ) => dir . cwd === process . cwd ( ) ) ; if ( cmdLineoptions [ K . default ] ) { if ( possibleApp && possibleApp . machineNameToDeploy ) { if ( ! StorageHelper . get ( ) . findMachine ( possibleApp . machineNameToDeploy ) ) { StdOutUtil . printError ( `You have to first login to ${ StdOutUtil . getColoredMachineName ( possibleApp . machineNameToDeploy ) } CapRover machine to use previously saved deploy options from this directory with --default.\n` , true ) ; } this . options = ( params ? ) => [ CliHelper . get ( ) . getEnsureAuthenticationOption ( '' , undefined , undefined , possibleApp . machineNameToDeploy , async ( machine ) => { 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' ) ; } } else if ( possibleApp && possibleApp . machineNameToDeploy && StorageHelper . get ( ) . findMachine ( possibleApp . machineNameToDeploy ) ) { StdOutUtil . printTip ( '**** Protip ****' ) ; StdOutUtil . printMessage ( `You seem to have deployed ${ StdOutUtil . getColoredMachineName ( possibleApp . appName ) } from this directory in the past, use --default flag to avoid having to re-enter the information.\n` ) ; } return Promise . resolve ( cmdLineoptions ) ; } protected validateDeploySource ( params ) { if ( ( this . findParamValue ( params , K . branch ) ? 1 : 0 ) + ( this . findParamValue ( params , K . tar ) ? 1 : 0 ) + ( this . findParamValue ( params , K . img ) ? 1 : 0 ) > 1 ) { StdOutUtil . printError ( 'Only one of branch, tarFile or imageName can be present in deploy.\n' , true ) ; } if ( ! this . findParamValue ( params , K . tar ) && ! this . findParamValue ( params , K . img ) ) { validateIsGitRepository ( ) ; validateDefinitionFile ( ) ; } } protected async action ( params ) { await this . deploy ( { captainMachine : this . machine , deploySource : { branchToPush : this . paramValue ( params , K . branch ) , tarFilePath : this . paramValue ( params , K . tar ) , imageName : this . paramValue ( params , K . img ) } , appName : this . paramValue ( params , K . app ) } , this . apps . find ( app => app . appName === this . paramValue ( params , K . app ) ) ) ; } private async deploy ( deployParams , app ? ) { try { if ( await new DeployHelper ( app && app . hasDefaultSubDomainSsl ) . startDeploy ( deployParams ) ) { StorageHelper . get ( ) . saveDeployedDirectory ( { appName : deployParams . appName || '' , cwd : process . cwd ( ) , deploySource : deployParams . deploySource , machineNameToDeploy : deployParams . captainMachine ? deployParams . captainMachine . name : '' } ) ; } } catch ( error ) { const errorMessage = error . message ? error . message : error ; StdOutUtil . printError ( `\nSomething bad happened: cannot deploy ${ StdOutUtil . getColoredAppName ( deployParams . appName || '' ) } at ${ StdOutUtil . getColoredMachineName ( deployParams . captainMachine ? deployParams . captainMachine . name || deployParams . captainMachine . baseUrl : '' ) }.\n${ errorMessage }\n` , true ) ; } } }