All files / src/deployTools ftp.js

14.02% Statements 15/107
0% Branches 0/49
0% Functions 0/31
11.83% Lines 11/93

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 1733x 3x 3x           3x 3x 3x   3x                                                                                                               3x                                                                   3x                                                                                                             3x                       3x      
import path from 'path';
import fs from 'fs';
import {
    logInfo,
    logComplete,
    logError,
    logTask,
} from '../common';
import { askQuestion, generateOptions, finishQuestion } from '../systemTools/prompt';
import { RENATIVE_CONFIG_NAME } from '../constants';
import { DEPLOY_TARGET_FTP } from './webTools';
 
const _deployToFtp = (c, platform) => new Promise((resolve, reject) => {
    logTask(`_deployToFtp:${platform}`);
    let promise;
    const envPath = path.resolve(c.paths.project.dir, '.env');
    if (!fs.existsSync(envPath)) {
        logInfo('.env file does not exist. Creating one for you');
        promise = _createEnvFtpConfig(envPath);
    } else {
        promise = new Promise((resolve, reject) => {
            fs.readFile(envPath, (err, data) => {
                if (err) return reject(err);
                resolve(data.toString());
            });
        });
    }
    promise.then((envContent) => {
        const envObj = {};
        let matches = 0;
        const targetMatches = 2;
        envContent.split('\n').map(line => line.split('=')).forEach(([key, val]) => {
            if (['RNV_DEPLOY_WEB_FTP_SERVER', 'RNV_DEPLOY_WEB_FTP_USER'].indexOf(key) > -1) {
                matches++;
            }
        });
        let envPromise;
        if (matches >= targetMatches) {
            envPromise = Promise.resolve();
        } else {
            logInfo('.env file does not contain all needed FTP config, helping you to set it up');
            envPromise = _createEnvFtpConfig(envPath, `${envContent}\n`);
        }
        return envPromise;
    })
        .then(() => {
            require('dotenv').config();
            const config = {
                user: process.env.RNV_DEPLOY_WEB_FTP_USER,
                password: process.env.RNV_DEPLOY_WEB_FTP_PASSWORD, // optional, prompted if none given
                host: process.env.RNV_DEPLOY_WEB_FTP_SERVER,
                port: process.env.RNV_DEPLOY_WEB_FTP_PORT || 21,
                localRoot: c.buildConfig.platforms[platform].deploy[DEPLOY_TARGET_FTP].localRoot,
                remoteRoot: c.buildConfig.platforms[platform].deploy[DEPLOY_TARGET_FTP].remoteRoot || '/',
                include: c.buildConfig.platforms[platform].deploy[DEPLOY_TARGET_FTP].include || ['*', '**/*'], // this would upload everything except dot files
                exclude: c.buildConfig.platforms[platform].deploy[DEPLOY_TARGET_FTP].exclude || [], // e.g. exclude sourcemaps - ** exclude: [] if nothing to exclude **
                deleteRemote: c.buildConfig.platforms[platform].deploy[DEPLOY_TARGET_FTP].exclude.deleteRemote || false, // delete ALL existing files at destination before uploading, if true
                forcePasv: true // Passive mode is forced (EPSV command is not sent)
            };
            return config;
        })
        .then((config) => {
            const FtpDeploy = require('ftp-deploy');
            const ftpDeploy = new FtpDeploy();
            return ftpDeploy.deploy(config);
        }).catch(reject);
});
 
const _createEnvFtpConfig = (configFilePath, previousContent = '') => new Promise((resolve, reject) => {
    let envContent = previousContent || '';
    askQuestion('Type your FTP host').then((v) => {
        finishQuestion();
        if (v) {
            envContent += `RNV_DEPLOY_WEB_FTP_SERVER=${v}\n`;
        } else {
            return reject(new Error('NO FTP SERVER PROVIDED'));
        }
        askQuestion('Type your FTP user').then((v) => {
            finishQuestion();
            if (v) {
                envContent += `RNV_DEPLOY_WEB_FTP_USER=${v}\n`;
            } else {
                return reject(new Error('NO FTP USER PROVIDED'));
            }
            askQuestion('Type your FTP password (or press ENTER for prompting every time)').then((v) => {
                finishQuestion();
                if (v) {
                    envContent += `RNV_DEPLOY_WEB_FTP_PASSWORD=${v}\n`;
                }
                askQuestion('Type your FTP port (or enter for 21)').then((v) => {
                    finishQuestion();
                    const port = !v || isNaN(v) ? 21 : v;
                    envContent += `RNV_DEPLOY_WEB_FTP_PORT=${port}`;
                    fs.writeFileSync(configFilePath, envContent);
                    logInfo(`Writing .env config to ${configFilePath}`);
                    resolve();
                });
            });
        });
    });
});
 
const _createDeployConfig = (c, platform) => new Promise((resolve, reject) => {
    logTask(`_createDeployConfig:${platform}`);
 
    const deploy = c.buildConfig.platforms[platform].deploy || {};
 
    deploy[DEPLOY_TARGET_FTP] = {};
    deploy[DEPLOY_TARGET_FTP].type = DEPLOY_TARGET_FTP;
 
    const targetConfigPromise = new Promise((resolve, reject) => {
        deploy[DEPLOY_TARGET_FTP].localRoot = path.resolve(c.paths.project.builds.dir, `${c.runtime.appId}_${platform}`);
        askQuestion('Folder on the ftp to upload the project (default is \'/\')')
            .then((v) => {
                finishQuestion();
                deploy[DEPLOY_TARGET_FTP].remoteRoot = v || '/';
            })
            .then(() => askQuestion('Delete all contents of that folder when deploying versions y/N (default is \'N\')?')
                .then((v) => {
                    finishQuestion();
                    deploy[DEPLOY_TARGET_FTP].deleteRemote = ['yes', 'Y', 'y'].indexOf(v) > -1;
                }))
            .then(() => askQuestion('Included files pattern, comma separated (default \'*\',\'**/*\' = all except dot files)')
                .then((v) => {
                    finishQuestion();
                    deploy[DEPLOY_TARGET_FTP].include = v ? v.split(',') : ['*', '**/*'];
                }))
            .then(() => {
                deploy[DEPLOY_TARGET_FTP].exclude = [];
                return askQuestion('Excluded files pattern, comma separated (default [])')
                    .then((v) => {
                        finishQuestion();
                        deploy[DEPLOY_TARGET_FTP].exclude = v ? v.split(',') : [];
                    });
            })
            .then(() => askQuestion('Exclude sourcemaps? y/N (default = N)')
                .then((v) => {
                    finishQuestion();
                    deploy[DEPLOY_TARGET_FTP].exclude = deploy[DEPLOY_TARGET_FTP].exclude.concat(['yes', 'Y', 'y'].indexOf(v) > -1 ? ['**/*.map'] : []);
                }))
            .then(resolve);
    });
 
    targetConfigPromise
        .then(() => {
            logInfo(`Setting your appconfig for ${platform} to include deploy type: ${DEPLOY_TARGET_FTP}
                    on ${c.paths.appConfig.config}
                `);
 
            // TODO: Review this (where to put what props renative.*.json)
            c.files.appConfig.config.platforms[platform].deploy = deploy;
            writeObjectSync(c.paths.appConfig.config, c.files.appConfig.config);
            resolve();
        })
        .catch(reject);
});
 
const deployToFtp = (c, platform) => new Promise((resolve, reject) => {
    logTask(`checkDeployConfigTarget:${platform}`);
    const targetConfig = c.buildConfig.platforms[platform];
    if (targetConfig && targetConfig.deploy[DEPLOY_TARGET_FTP] && targetConfig.deploy[DEPLOY_TARGET_FTP].type) {
        _deployToFtp(c, platform).then(resolve).catch(reject);
    } else {
        _createDeployConfig(c, platform)
            .then(() => {
                _deployToFtp(c, platform).then(resolve).catch(reject);
            })
            .catch(reject);
    }
});
 
export { deployToFtp };