Files
caprover/app-cli/captainduckduck-deploy.js
T
2017-10-24 22:21:10 -07:00

283 lines
7.6 KiB
JavaScript

const program = require('commander');
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
const inquirer = require('inquirer');
const configstore = require('configstore');
const request = require('request');
const commandExistsSync = require('command-exists').sync;
const ProgressBar = require('progress');
const ora = require('ora');
const {exec} = require('child_process');
const packagejson = require('./package.json');
const configs = new configstore(packagejson.name, {
captainMachines: [],
apps: []
});
console.log(' ');
console.log(' ');
program
.description('Deploy current directory to a Captain machine.')
.parse(process.argv);
if (program.args.length) {
console.error(chalk.red('Unrecognized commands:'));
program.args.forEach(function (arg) {
console.log(chalk.red(arg));
});
console.error(chalk.red('Deploy does not require any options. '));
process.exit(1);
}
if (!fs.pathExistsSync('./.git')) {
console.log(chalk.bold.yellow('**** WARNING: You are not in a git root directory. This command will only deploys the current directory ****'));
console.log(' ');
console.log(' ');
}
let listOfMachines = [{
name: '-- CANCEL --',
value: '',
short: ''
}];
let machines = configs.get('captainMachines');
for (let i = 0; i < machines.length; i++) {
let m = machines[i];
listOfMachines.push({
name: m.name + ' at ' + m.baseUrl,
value: m.name,
short: m.name + ' at ' + m.baseUrl
})
}
function getAppForDirectory() {
let apps = configs.get('apps');
for (let i = 0; i < apps.length; i++) {
let app = apps[i];
if (app.cwd === process.cwd()) {
return app.appName;
}
}
return undefined;
}
function saveAppForDirectory(appName) {
let apps = configs.get('apps');
for (let i = 0; i < apps.length; i++) {
let app = apps[i];
if (app.cwd === process.cwd()) {
app.appName = appName;
return;
}
}
apps.push({
cwd: process.cwd(),
appName: appName
});
configs.set('apps', apps);
}
console.log('Preparing deployment to Captain...');
console.log(' ');
const questions = [
{
type: 'list',
name: 'captainNameToDeploy',
message: 'Select the Captain Machine you want to deploy to:',
choices: listOfMachines
},
{
type: 'input',
default: 'master',
name: 'branchToPush',
message: 'Enter the "git" branch you would like to deploy:',
when: function (answers) {
return !!answers.captainNameToDeploy;
}
},
{
type: 'input',
default: getAppForDirectory(),
name: 'appName',
message: 'Enter the Captain app name this directory will be deployed to:',
when: function (answers) {
return !!answers.captainNameToDeploy;
}
},
{
type: 'confirm',
name: 'confirmedToDeploy',
message: 'Are you sure you want to deploy to this Captain machine?',
default: true,
when: function (answers) {
return !!answers.captainNameToDeploy;
}
}
];
inquirer.prompt(questions).then(function (answers) {
console.log(' ');
console.log(' ');
if (!answers.confirmedToDeploy) {
console.log('Operation cancelled by the user...');
console.log(' ');
}
else {
let machines = configs.get('captainMachines');
let machineToDeploy = null;
for (let i = 0; i < machines.length; i++) {
if (machines[i].name === answers.captainNameToDeploy) {
console.log('Deploying to ' + answers.captainNameToDeploy);
machineToDeploy = machines[i];
break;
}
}
console.log(' ');
deployTo(machineToDeploy, answers.branchToPush, answers.appName);
}
});
function deployTo(machineToDeploy, branchToPush, appName) {
if (!commandExistsSync('git')) {
console.log(chalk.red('"git" command not found...'));
console.log(chalk.red('Captain needs "git" to create zip file of your source files...'));
console.log(' ');
process.exit(1);
}
let zipFileNameToDeploy = 'temporary-captain-to-deploy.zip';
let zipFileFullPath = path.join(process.cwd(), zipFileNameToDeploy);
console.log('Saving zip file to:');
console.log(zipFileFullPath);
console.log(' ');
exec('git archive --format tar --output ' + zipFileFullPath + ' ' + branchToPush, function (err, stdout, stderr) {
if (err) {
console.log(chalk.red('TAR file failed'));
console.log(chalk.red(err + ' '));
console.log(' ');
fs.removeSync(zipFileFullPath);
return;
}
exec('git rev-parse ' + branchToPush, function (err, stdout, stderr) {
const gitHash = (stdout || '').trim();
if (err || !(/^[a-f0-9]{40}$/.test(gitHash))) {
console.log(chalk.red('Cannot find hash of last commit on this branch: ' + branchToPush));
console.log(chalk.red(gitHash + ' '));
console.log(chalk.red(err + ' '));
console.log(' ');
return;
}
console.log('Pushing last commit on ' + branchToPush + ': ' + gitHash);
sendFileToCaptain(machineToDeploy, zipFileFullPath, appName, gitHash);
});
});
}
function sendFileToCaptain(machineToDeploy, zipFileFullPath, appName, gitHash) {
console.log('Uploading file to ' + machineToDeploy.baseUrl);
const fileSize = fs.statSync(zipFileFullPath).size;
const fileStream = fs.createReadStream(zipFileFullPath);
const barOpts = {
width: 20,
total: fileSize,
clear: true
};
const bar = new ProgressBar(' uploading [:bar] :percent (ETA :etas)', barOpts);
fileStream.on('data', function (chunk) {
bar.tick(chunk.length);
});
let spinner;
fileStream.on('end', function () {
console.log(' ');
console.log('This might take several minutes. PLEASE BE PATIENT...');
spinner = ora('Building your source code...').start();
spinner.color = 'yellow';
});
let options = {
url: machineToDeploy.baseUrl + '/api/v1/user/appData/' + appName,
headers: {
'x-namespace': 'captain',
'x-captain-auth': machineToDeploy.authToken
},
method: 'POST',
formData: {
sourceFile: fileStream,
gitHash: gitHash
}
};
function callback(error, response, body) {
spinner.stop();
fs.removeSync(zipFileFullPath);
try {
if (!error && response.statusCode === 200) {
let data = JSON.parse(body);
if (data.status !== 100) {
throw new Error(JSON.stringify(data, null, 2));
}
saveAppForDirectory(appName);
console.log(chalk.green('Deployed successful: ') + appName);
console.log(' ');
return;
}
if (error) {
throw new Error(error)
}
throw new Error(response ? JSON.stringify(response, null, 2) : 'Response NULL');
} catch (error) {
console.error(chalk.red('Something bad happened. Cannot deploy "' + appName + '"'));
let errorMessage = error.message ? error.message : error;
console.error(chalk.red(errorMessage));
console.log(' ');
}
}
request(options, callback);
}