atlas-connect
Version:
CLI for the atlassian-connect-express library (helpers for building Atlassian Connect apps on top of Express)
174 lines (152 loc) • 6.48 kB
JavaScript
var AdmZip = require('adm-zip');
var chalk = require('chalk');
var json = require('comment-json');
var fs = require('fs');
var inquirer = require('inquirer');
var fetch = require('node-fetch');
var path = require('path');
var rimraf = require('rimraf');
var temp = require('temp');
var descriptorModules = require('./descriptor-modules.json');
var extractTemplate = function (projectName, product, buffer, callback) {
fs.exists(projectName, function (err) {
if (err) {
inquirer.prompt({
type: 'confirm',
name: 'overwrite',
message: 'Directory ' + projectName + ' already exists. Do you wish to remove and continue?',
default: false
}).then(function (answer) {
if (answer.overwrite) {
rimraf(projectName, function (err) {
if (!err) {
createScaffold(projectName, product, buffer, callback);
}
});
} else {
callback(new Error('Chose not to overwrite directory ' + projectName));
}
});
} else {
createScaffold(projectName, product, buffer, callback);
}
});
};
var logError = function (message) {
logMessage('error', message);
};
var logMessage = function (type, message) {
var prefix = '';
message = message || '';
if (type === 'error') {
prefix = chalk.red('ERR!');
}
message.split('\\n').forEach(function (m) {
console.log(prefix, m);
});
};
var createScaffold = function (projectName, product, buffer, callback) {
var writeJsonObjectToFile = function (jsonObject, filename) {
// We use 4 spaces as an indention
fs.writeFileSync(filename, json.stringify(jsonObject, null, 4));
};
var setProductInConfigFile = function(projectDir, product) {
var configFilename = path.join(projectDir, 'config.json');
var config = json.parse(fs.readFileSync(configFilename, { encoding: 'utf8' }));
config.product = product === 'jira-service-desk' ? 'jira' : product;
writeJsonObjectToFile(config, configFilename);
};
var setProductModulesInDescriptor = function(projectDir, product) {
var productModules = descriptorModules[product];
if (productModules) {
var descriptorFilename = path.join(projectDir, 'atlassian-connect.json');
var descriptor = json.parse(fs.readFileSync(descriptorFilename, { encoding: 'utf8' }));
descriptor.modules = productModules;
writeJsonObjectToFile(descriptor, descriptorFilename);
}
};
temp.mkdir(projectName, function (err, dirPath) {
var zip = new AdmZip(buffer);
var zipEntries = zip.getEntries();
// write the zip archive into the current directory
var outDir = process.cwd();
// The bitbucket archive includes the account, repository name and commit hash
// as the first directory in the archive, eg: "atlassian-atlassian-connect-express-template-564020eabcd4/"
// let's get this folder name and remove it from the extracted archive.
var zipFolderName = zipEntries[0].entryName.split(path.sep)[0];
zip.extractAllTo(outDir, true);
// Move all files in "outdir/zipFolderName" to "outdir/projectName"
fs.renameSync(path.join(outDir, zipFolderName), path.join(process.cwd(), projectName));
if (product) {
var projectDir = path.join(outDir, projectName);
setProductInConfigFile(projectDir, product);
setProductModulesInDescriptor(projectDir, product);
}
console.log('\nExtracting template:');
zipEntries.forEach(function (zipEntry) {
// Replace "zipFolderName" with "projectName"
var zipFilenameWithoutFirstDirectory = zipEntry.entryName.split(path.sep).slice(1).join(path.sep);
var fileName = [projectName, zipFilenameWithoutFirstDirectory].join(path.sep);
console.log(' ' + chalk.green(fileName));
});
callback(err);
});
};
var generateScaffold = function (projectName, template, callback) {
var templateUrl;
var product = template;
if (template.match(/^http/)) {
templateUrl = template;
product = null;
} else {
templateUrl = 'https://bitbucket.org/atlassian/atlassian-connect-express-template/get/';
switch (template) {
case 'jira':
case 'jira-service-desk':
case 'confluence':
templateUrl += 'master.zip';
break;
case 'bitbucket':
templateUrl += 'bitbucket.zip';
break;
default:
var msg = 'No template for type ' + template;
logError(msg);
return callback(new Error(msg));
break;
}
}
fetch(templateUrl).then(function (response) {
if (response.status === 404) {
logError('The Atlassian Connect app template ' + chalk.bold(template) + ' was not found.');
logError();
logError('Please check that you are connected to the internet and try again.');
} else if (!response.ok) {
logError('The Atlassian Connect app template ' + chalk.bold(template) + ' was unable to be downloaded.');
logError();
logError(chalk.bold('Status code: ') + response.status);
response.text().then(function (body) {
logError(body);
});
} else {
response.buffer().then(function (buffer) {
extractTemplate(projectName, product, buffer, callback);
});
}
});
};
module.exports = {
createTemplate: function (name, template) {
generateScaffold(name, template, function (err) {
if (!err) {
console.log();
console.log('A directory ' + chalk.bold.green(name) + ' has been created for your project with a Node.js');
console.log('application pre-configured. For information on what to do next, visit:');
console.log();
console.log(' http://go.atlassian.com/get-started-with-atlassian-connect-express');
console.log();
}
});
},
logError: logError
};