feds-cli
Version:
CLI for Front-end Dev Stack
188 lines (164 loc) • 5.58 kB
JavaScript
/* create commander component
* To use add require('../cmds/create.js')(program) to your commander.js based node executable before program.parse
*/
;
require('shelljs/global');
var inquirer = require('inquirer');
var Case = require('case');
var r = require('../utils/reporter');
var path = require('path')
var fse = require('fs-extra')
var set = require('lodash.set')
var each = require('lodash.foreach')
var get = require('lodash.get')
var assign = require('lodash.assign')
var keys = require('lodash.keys')
var template = require('lodash.template')
var chalk = require('chalk')
var readline = require('readline')
var EMAIL_PATTERN = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i
var REPO_PATTERN = /(?:git|ssh|https?|git@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+\.git(?:\/?|\#[\d\w\.\-_]+?)$/
var GA_PATTERN = /\bUA-\d{4,10}(-\d{1,4})?\b/
var SEMVER_PATTERN = /\bv?(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?\b/ig
var QUESTIONS = [
{
type: 'input',
name: 'name',
message: 'Project name',
default: process.cwd().replace(/\/([^\/]+\/)+/gi, ''),
filter: function(v) {
return Case.kebab(v)
}
}, {
type: 'input',
name: 'version',
message: 'Version',
default: '0.0.0',
validate: function(v) {
return SEMVER_PATTERN.test(v) || 'Invalid version format. Should be MAJOR.MINOR.PATH. See semver.org for more info.'
}
}, {
type: 'input',
name: 'description',
message: 'Project description'
}, {
type: 'input',
name: 'author.name',
message: 'Author name',
default: ''
}, {
type: 'input',
name: 'author.email',
message: 'Author email',
default: '',
validate: function(v) {
return v === '' || EMAIL_PATTERN.test(v) || 'Invalid email address'
}
}, {
type: 'input',
name: 'repository.url',
message: 'Repo URL',
default: '',
validate: function(v) {
return v === '' || REPO_PATTERN.test(v) || 'Invalid repo URL'
}
}, {
type: 'list',
name: 'createDir',
message: 'Create folder for project?',
choices: ['Yes', 'No'],
default: 'Yes',
filter: function(v) {
return v === 'Yes'
}
}
];
function installDeps(location, callback) {
exec('cd ' + location + ' && npm install', addCheckMark.bind(null, callback));
}
function addCheckMark(callback) {
process.stdout.write(chalk.green(' ✓'));
callback();
}
function animateProgress(message, amountOfDots) {
if (typeof amountOfDots !== 'number') {
amountOfDots = 3;
}
var i = 0;
return setInterval(function() {
readline.cursorTo(process.stdout, 0);
i = (i + 1) % (amountOfDots + 1);
var dots = new Array(i + 1)
.join('.');
process.stdout.write(message + dots);
}, 500);
}
module.exports = function(program) {
var interval;
program
.command('create')
.version('0.0.0')
.description('Create a new Front-end Dev Stack project')
.action(function() {
if (!which('git')) {
r.error('Sorry, this script requires git');
exit(1);
}
inquirer.prompt(QUESTIONS)
.then(function(answers) {
var PROJECT_ROOT = answers.createDir ? path.join(process.cwd(), answers.name) : process.cwd()
// create project dir
if (answers.createDir) {
mkdir('-p', PROJECT_ROOT)
r.success('Project folder created')
}
// check whether target folder is empty/exists
if (ls('-A', PROJECT_ROOT) != '') {
r.error('Project target folder is not empty.');
exit(1);
}
r.success('Target folder is available')
// clone universal boilerplate
if (exec('git clone https://git.siteone.cz/feds/universal-boilerplate.git ' + PROJECT_ROOT).code !== 0) {
r.error('Creating new project failed.');
exit(1);
}
r.success('Successfully cloned project boilerplate')
// update package meta
var oldPackage = fse.readJsonSync(path.join(PROJECT_ROOT, 'package.json'))
var newPackage = assign({}, oldPackage)
each(keys(answers), function(key) {
set(newPackage, key, get(answers, key))
})
// update package file
fse.writeJsonSync(path.join(PROJECT_ROOT, 'package.json'), newPackage)
r.success('Successfully composed project package.json')
// remove boilerplate readme
rm('-fr', path.join(PROJECT_ROOT, 'readme.md'))
// compose new readme
var templateReadme = template(fse.readFileSync(path.join(__dirname, '../templates/', 'readme._md')))
fse.writeFileSync(path.join(PROJECT_ROOT, 'README.md'), templateReadme(answers))
r.success('Successfully composed project README.md')
// remove universal boilerplate repository
rm('-fr', path.join(PROJECT_ROOT, '.git'))
// initialize a new repository
if (exec('cd ' + PROJECT_ROOT + ' && git init && git add . --all && git commit -qm "Initial commit"')
.code !== 0) {
r.error('Failed to initialize new repository');
exit(1)
}
r.success('Successfully initialized project repository')
setTimeout(function() {
readline.cursorTo(process.stdout, 0);
interval = animateProgress('Installing dependencies');
}, 500);
r.info('Installing project dependencies... (Will take a white)')
installDeps(PROJECT_ROOT, function(error) {
clearInterval(interval);
if (error) {
r.error(error);
}
})
})
})
}