/**
* @overview
* @author James Feigel {@link https://github.com/jfeigel|@jfeigel}
* @description
* Custom Git script to compile JSDoc / ngdoc and deploy to gh-pages
*
* @requires {@link https://github.com/petkaantonov/bluebird|bluebird}
* @requires {@link https://github.com/chalk/chalk|chalk}
* @requires {@link https://github.com/SBoudrias/Inquirer.js|Inquirer}
*/
"use strict";
const Promise = require("bluebird");
const chalk = require("chalk");
const inquirer = require("inquirer");
const execSync = require("child_process").execSync;
const fs = require("fs");
const config = require("./config")();
const seperatorLine = "==============================";
const seperator = `\n${seperatorLine}\n`
const squelch = "> /dev/null 2>&1";
let packageJSONExists = null;
// Object to easily access the runner setup functions
let runnerSetup = {
"grunt": {
"install": installGrunt,
"configure": configureGrunt
},
"gulp": {
"install": installGulp,
"configure": configureGulp
}
};
console.log(`\n${seperatorLine}`);
console.log(chalk.gray.bgCyan(' JS-PAGES '));
console.log(`${seperatorLine}\n`);
// Initial question set and kick-off point
inquirer.prompt([
{
"type": "list",
"name": "runner",
"message": "Which task runner will you use?",
"choices": [
{
"name": "Grunt",
"value": "grunt",
"short": "Grunt"
},
{
"name": "Gulp",
"value": "gulp",
"short": "Gulp"
}
]
},
{
"type": "list",
"name": "docs",
"message": "Which documentation generator will you use?",
"choices": ["ngdocs", "jsdoc"]
},
{
"type": "input",
"name": "command_name",
"message": "Name of custom Git command",
"default": "pushdoc",
"validate": function(value) {
var pass = value.match(/^[A-Z]{1}([A-Z0-9-]+)?$/i);
if (pass) {
try {
execSync(`git config -l --local | grep 'alias.${value}'`);
if (overwriteAliasCommand === null || overwriteAliasCommand !== value) {
overwriteAliasCommand = value;
return "Alias already exists. Enter the same alias again to overwrite the current alias.";
} else {
execSync(`git config --local --unset-all alias.${answers.command_name}`);
return true;
}
} catch (err) {
return true;
}
} else {
return "Please enter a valid command name";
}
}
},
{
"type": "list",
"name": "sudo",
"message": "Are your npm packages installed with 'sudo'?",
"choices": [
{
"name": "No",
"value": false,
"short": "No"
},
{
"name": "Yes",
"value": true,
"short": "Yes"
}
]
}
], init);
/**
* @function
* @name init
* @description
* Start setup after questions have been answered
*
* @param {Object} answers - Answer values from the setup questions
*/
function init(answers) {
console.log(seperator);
console.log(chalk.gray(`Setting up selected task runner: ${chalk.reset(answers.runner)}`));
// Check if package.json exists
try {
fs.statSync(`./package.json`);
packageJSONExists = true;
console.log(chalk.green('package.json exists'));
console.log(chalk.gray('Running npm install...'));
// If package.json exists make sure all listed packages are installed
execSync(`npm install ${squelch}`);
} catch (err) {
packageJSONExists = false;
console.log(chalk.yellow('package.json does not exist'));
console.log(chalk.gray('Creating package.json with default options...'));
// If package.json does not exist then create a new, default one
execSync(`npm init --force ${squelch}`);
}
// Install documentation packages
configureDocumentation(answers);
// Initialize the selected task runner
runnerSetup[answers.runner].install(answers);
// Compile the runner's template files
runnerSetup[answers.runner].configure(answers.docs, config['gh-pages'].name);
// Configure the custom git script
configureGitAlias(answers, config['gh-pages'].name);
}
////////////
/**
* @function
* @name checkInstall
* @description
* Check whether or not the given package is installed
*
* @param {String} packageToCheck - Name of the package to check
* @param {boolean} isGlobal - Is the package supposed to be installed globally?
*
* @returns {boolean} Whether or not the package is installed
*/
function checkInstall(packageToCheck, isGlobal) {
let command = 'npm list';
if (isGlobal === true) {
command = `${command} -g`;
}
command = `${command} --depth 0 ${packageToCheck} ${squelch}`
try {
execSync(command);
console.log(chalk.green(`${packageToCheck} is installed.`));
return true;
} catch (err) {
console.log(chalk.yellow(`${packageToCheck} is not installed.`));
return false;
}
}
/**
* @function
* @name installPackage
* @description
* Install the given package
*
* @param {String} packageToInstall - Name of the package to install
* @param {boolean} isGlobal - Should the package be installed globally?
* @param {boolean} isSudo - Should the package be installed using `sudo`?
* @param {String} doSave - Should the package be saved in `package.json`? ```['save', 'save-dev']```
*/
function installPackage(packageToInstall, isGlobal, isSudo, doSave) {
let command = 'npm install';
if (isSudo === true) {
command = `sudo ${command}`;
}
if (isGlobal === true) {
command = `${command} -g`;
}
if (packageToInstall !== null) {
command = `${command} ${packageToInstall}`;
}
if (doSave) {
command = `${command} --${doSave}`;
}
execSync(command);
return true;
}
/**
* @function
* @name configureDocumentation
* @description
* Configure the documentation packages and gh-pages
*
* @param {Object} answers - Answer values from the setup questions
*/
function configureDocumentation(answers) {
let docPackage = config.dependencies[answers.runner][answers.docs];
let ghpagesPackage = config.dependencies[answers.runner]['gh-pages'];
console.log(chalk.gray(`Installing ${docPackage}...`));
installPackage(docPackage, false, answers.sudo, 'save-dev');
console.log(chalk.gray(`Installing ${ghpagesPackage}...`));
installPackage(ghpagesPackage, false, answers.sudo, 'save-dev');
if (answers.docs === 'jsdoc') {
let jsdocConfFile = `${config.path.templates}/${[answers.runner]}/${config.jsdoc.conf}`;
execSync(`cp ${jsdocConfFile} ./`);
}
// Create empty `docs` folder
execSync('mkdir docs');
}
/**
* @function
* @name installGrunt
* @description
* Install grunt as the task-runner
*
* @param {Object} answers - Answer values from the setup questions
*/
function installGrunt(answers) {
console.log(chalk.gray("Installing 'grunt-cli' globally..."));
installPackage('grunt-cli', true, answers.sudo);
console.log(chalk.gray("Installing 'grunt' locally..."));
installPackage('grunt', false, answers.sudo, 'save-dev');
}
/**
* @function
* @name configureGrunt
* @description
* Configure grunt templates
*
* @param {String} runner - Selected task-runner
* @param {String} docs - Selected documentation generator
* @param {String} ghpages - Selected gh-pages script
*/
function configureGrunt(docs, ghpages) {
console.log(chalk.gray("Compiling the grunt template file..."));
let templateFilePath = `${config.path.templates}/grunt`;
let gruntfileName = 'Gruntfile.js';
let gruntfileFiles = [
`"${templateFilePath}/Gruntfile_header.js"`,
`"${templateFilePath}/Gruntfile_${ghpages}.js"`,
`"${templateFilePath}/Gruntfile_${docs}.js"`,
`"${templateFilePath}/Gruntfile_middle.js"`,
`"${templateFilePath}/Gruntfile_${ghpages}_npm.js"`,
`"${templateFilePath}/Gruntfile_${docs}_npm.js"`,
`"${templateFilePath}/Gruntfile_footer.js"`
];
let gruntfileExists = fs.readdirSync('./').some((file, index, array) => {
return file.toLowerCase() == gruntfileName.toLowerCase();
});
if (gruntfileExists === true) {
console.log(chalk.yellow("Gruntfile.js already exists. Creating a temporary file instead..."));
gruntfileName = `${gruntfileName}.tmp`;
}
execSync(`cat ${gruntfileFiles.join(' ')} > ${gruntfileName}`);
}
/**
* @function
* @name installGulp
* @description
* Install gulp as the task-runner
*
* @param {Object} answers - Answer values from the setup questions
*/
function installGulp(answers) {
console.log(chalk.gray("Installing 'gulp'..."));
installPackage('gulp', false, answers.sudo, 'save-dev');
}
/**
* @function
* @name configureGulp
* @description
* Configure gulp templates
*
* @param {String} runner - Selected task-runner
* @param {String} docs - Selected documentation generator
* @param {String} ghpages - Selected gh-pages script
*/
function configureGulp(docs, ghpages) {
console.log(chalk.gray("Compiling the gulp template files..."));
let templateFilePath = `${config.path.templates}/gulp`;
// gulp.config.js set up
let gulpconfigName = 'gulp.config.js';
let gulpconfigFiles = [
`"${templateFilePath}/gulp.config_header.js"`,
`"${templateFilePath}/gulp.config_${ghpages}.js"`,
`"${templateFilePath}/gulp.config_${docs}.js"`,
`"${templateFilePath}/gulp.config_footer.js"`
];
let gulpconfigExists = fs.readdirSync('./').some((file, index, array) => {
return file.toLowerCase() == gulpconfigName.toLowerCase();
});
if (gulpconfigExists === true) {
console.log(chalk.yellow("gulp.config.js already exists. Creating a temporary file instead..."));
gulpconfigName = `${gulpconfigName}.tmp`;
}
execSync(`cat ${gulpconfigFiles.join(' ')} > ${gulpconfigName}`);
// gulpfile.js set up
let gulpfileName = 'gulpfile.js';
let gulpfileFiles = [
`"${templateFilePath}/gulpfile_header.js"`,
`"${templateFilePath}/gulpfile_${ghpages}.js"`,
`"${templateFilePath}/gulpfile_${docs}.js"`,
`"${templateFilePath}/gulpfile_footer.js"`
];
let gulpfileExists = fs.readdirSync('./').some((file, index, array) => {
return file.toLowerCase() == gulpfileName.toLowerCase();
});
if (gulpfileExists === true) {
console.log(chalk.yellow("gulpfile.js already exists. Creating a temporary file instead..."));
gulpfileName = `${gulpfileName}.tmp`;
}
execSync(`cat ${gulpfileFiles.join(' ')} > ${gulpfileName}`);
}
/**
* @function
* @name configureGitAlias
* @description
* Configure the custom git script
*
* @param {String} runner - Selected task-runner
* @param {String} docs - Selected documentation generator
* @param {String} ghpages - Selected gh-pages script
*
* @returns {Promise} Promise object that is resolved after Inquirer
* and custom script creation completes
*/
function configureGitAlias(answers, ghpages) {
try {
console.log(chalk.gray('Verifying git has been initialized...'));
execSync(`git status ${squelch}`);
} catch (e) {
console.log(chalk.yellow('Git has not been initialized'));
console.log(chalk.gray('Initializing git...'));
execSync(`git init ${squelch}`);
}
// Create the custom git script
let gitFilePath = `./git-${answers.command_name}`;
let stream = fs.createWriteStream(gitFilePath);
stream.once('open', function(fd) {
stream.write("#!/bin/sh\n\n");
stream.write("git push \"$@\"\n");
stream.write(`test $? -eq 0 && ${answers.runner} ${answers.docs} && ${answers.runner} ${ghpages}`)
stream.end();
});
// Make the script executable
fs.chmodSync(gitFilePath, "0755");
execSync(`git config --local --add alias.${answers.command_name} '!sh -c "./git-${answers.command_name}"'`);
}