UNPKG

infopack-cli

Version:

Command line tool for managing infopacks

361 lines (340 loc) 15.1 kB
#!/usr/bin/env node var program = require('commander'); const fs = require('fs'); var path = require('path'); var inquirer = require('inquirer'); const { Table } = require("console-table-printer"); const _ = require('lodash'); const slugify = require('slugify'); var infopackOutputValidator = require('infopack-output-validator'); const { exit } = require('process'); var package = require('../package'); const unzipper = require('../lib/unzipper') const { readJson } = require('../lib/json') const MODULE_PATH = path.join(__dirname, '..'); const TEMPLATES = ['basic']; const urls = { basic: 'https://gitlab.com/infopack/infopack-example-basic/-/archive/master/infopack-example-basic-master.zip' }; program .version(package.version) .description(package.description); program .command('init [template]') .alias('i') .description('Creates a new information package from a template. The package will be created in the current directory with the name you choose.') .action((template, program) => { template = template || TEMPLATES[0]; if(TEMPLATES.indexOf(template) < 0) { console.log(`Invalid template name provided, valid values are: ${TEMPLATES.join(', ')}`); return; } console.log('Initializing...') Promise .resolve() .then(() => { return inquirer .prompt([{ type: "input", name: "title", message: "Package title (This will be the human readable name)", validate: function(answer, hash) { return (answer.length > 0); } }, { type: "input", name: "name", default: answers => slugify(answers.title, { lower: true }), message: "Package name (slug with alphanumeric characters)", validate: function(answer, hash) { if(answer.length < 1) return 'Name too short (min 1 char)' if(answer.length > 140) return 'Name too long (max 140 chars)' if(!/^[a-z0-9-_]*$/.test(answer)) return 'Please use small characters separated by - och _' return true } }, { type: "input", name: "namespace", message: "Namespace slug (slug with alphanumeric characters)", validate: function(answer, hash) { if(answer.length < 1) return 'Namespace name too short (min 1 char)' if(answer.length > 140) return 'Namespace name too long (max 140 chars)' if(!/^[a-z0-9-_]*$/.test(answer)) return 'Please use small characters separated by - och _' return true } }, { type: "input", name: "description", message: "Package description (describe what this will contain)", validate: function(answer, hash) { if(answer.length < 1) 'Description is too short (min 1 char)' return true } }, { type: "input", name: "version", default: "0.0.1", message: "Package version", validate: function(answer, hash) { return (answer.length > 0); } }, { type: "input", name: "author", message: "Package author", validate: function(answer, hash) { return (answer.length > 0); } }, { type: "input", name: "license", message: "Package license", validate: function(answer, hash) { return (answer.length > 0); } }]) }) .then(packageData => { console.log() console.log('Please confirm the following:') console.log(`A new folder will be created in: ${path.resolve(packageData.name)}`) console.log(`Please make sure that you are in control over the namespace: ${packageData.namespace}`) console.log('') return Promise.all([ packageData, inquirer .prompt([{ type: "confirm", name: "lastChange", message: "Are we OK?", }]) ]) }) .then(([packageData, { lastChange }]) => { if(!lastChange) throw new Error('user_aborted') console.log('=== Fetching template from: ' + urls[template]) console.log('=== Writing') return Promise.all([ packageData, unzipper(urls[template], packageData.name) ]) }) .then(([packageData, unzipperResult]) => { const packagePath = path.resolve(packageData.name, 'package.json') return Promise.all([ packageData, unzipperResult, readJson(packagePath), packagePath ]) }) .then(([packageData, unzipperResult, packageJson, packagePath]) => { // prep package.json packageJson.name = packageData.name; packageJson.description = packageData.description; packageJson.version = packageData.version; packageJson.author = packageData.author; packageJson.license = packageData.license; fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2)); // prep index.js var indexPath = path.resolve(packageData.name, 'index.js') let indexString = fs.readFileSync(indexPath).toString() indexString = indexString.replace('<PACKAGE_TITLE>', packageData.title) indexString = indexString.replace('<PACKAGE_NAMESPACE>', packageData.namespace) fs.writeFileSync(indexPath, indexString) return [packageData, unzipperResult] }) .then(([packageData, unzipperResult]) => { console.log('') console.log('Next steps (at the command line):') console.log('') console.log(`1. cd ${packageData.name}`) console.log('2. npm install') console.log('3. Delete the example data in input/ (rm -rf input/) and add your own') console.log('4. npm start (to build your package)') console.log('') }) .catch(err => { if (err.isTtyError) { // Prompt couldn't be rendered in the current environment } else if (err.message == 'user_aborted') { console.log('') console.log('ABORTING') } else { // Something else went wrong console.log(err) } }); }); program .command('create meta-input') .alias('ci') .description('Creates a meta input file.') .action((name, program) => { Promise .resolve() .then(() => { return inquirer .prompt([{ type: "list", name: "file", message: "Which file?", choices: fs.readdirSync(path.resolve()).filter(str => '.meta-input.json' !== str.substring(str.length - '.meta-input.json'.length)), validate: function(answer, hash) { return (answer.length > 0); } }, { type: "input", name: "title", message: "Title?", validate: function(answer, hash) { return (answer.length > 0); } }, { type: "input", name: "description", message: "Description?", validate: function(answer, hash) { return (answer.length > 0); } }, { type: "confirm", name: "_addLabels", message: "Want to add Labels?" }, { type: "input", name: "_labels", message: "Write key value pair(s) (eg. Key 1=Value one, Key2 = Value two)", when: hash => hash._addLabels, filter: (answer, hash) => answer.split(',').map(i => i.trim().split('=').map(i => i.trim())) }, { type: "confirm", name: "_addOrigin", message: "want to add an origin?" }, { type: "input", name: "origin", message: "Write path to origin (use comma separation for multiple values)", when: hash => hash._addOrigin, filter: (answer, hash) => answer.split(',').map(i => i.trim()) }], { $schema: 'http://schemas.infopack.io/infopack-meta-input.2.schema.json' }) }) .then(answers => { const { _labels, _addLabels, _addOrigin, file, ...metaInput } = answers if(_labels && _labels.length > 0) { metaInput.labels = {} _labels.forEach(l => metaInput.labels[l[0]] = l[1]) } fs.writeFileSync(path.resolve(file + '.meta-input.json'), JSON.stringify(metaInput, null, 2)); }) .catch((error) => { if (error.isTtyError) { // Prompt couldn't be rendered in the current environment } else { // Something else went wrong console.log(error) } }); }); program .command('test') .alias('t') .description('Tests a infopack release') .arguments('<testSuiteVersion>', 'Manifest version for package to test') .arguments('<path>', 'Path to infopack release to test') .option('-s, --suppressErrors', 'If provided test will exit with errorcode = 0') .option('-l, --generate-logfile', 'creates a log file in current folder') .action((testSuiteVersion, folderPath, option, program) => { var validator = new infopackOutputValidator.Validator(folderPath) validator .addTestSuite(testSuiteVersion) .run() .then(results => { if(validator.getErrorsCount() > 0) { const p = new Table({ title: "Error Summary", columns: [{ name: "test", alignment: "left", title: "Test name" }, { name: "folder", alignment: "right", title: "Folder", maxLen: 40 }, { name: "file", alignment: "right", title: "File", maxLen: 30 }, { name: "message", alignment: "left", title: "Error messages" }, { name: "numberOfMessages", alignment: "right", title: "Messages" }, { name: "level", alignment: "left", title: "Error level" }], }); _.forEach(validator.getErrors(), e => { let option = {} if(e.level === 'info') option.color = 'yellow' if(e.level === 'critical') option.color = 'red' const foldername = path.dirname(e.path).replace('/', ' / ') const filename = path.basename(e.path) p.addRow({ test: e.test, folder: foldername.length > 40 ? foldername.slice(0,40) + ' ' + foldername.slice(40) : foldername, file: filename.length > 30 ? filename.slice(0,30) + ' ' + filename.slice(30) : filename, message: e.message, numberOfMessages: e.numberOfMessages, level: e.level }, option) }) console.log() p.printTable() } if(!validator.isValid()) { if(option.suppressErrors === undefined) { process.exitCode = 1 } } else { console.log('') console.log('') console.log(' ____________________ ') console.log(' / \\') console.log(' | ALL OK! | ') console.log(' | You are awesome!! | ') console.log(' \\____________________/') console.log(' ! ! ') console.log(' ! ! ') console.log(' L_ ! ') console.log(' / _)! ') console.log(' / /__L ') console.log(' _____/ (____) ') console.log(' (____) ') console.log(' _____ (____) ') console.log(' \\_(____) ') console.log(' ! ! ') console.log(' ! ! ') console.log(' \\__/ ') console.log('') } if(option.generateLogfile) { fs.writeFileSync(process.cwd() + '/test-log.json', JSON.stringify(results, null, 2)) } }) }); program.parse(process.argv); // show help if no command was provided if(program.args.length === 0) { program.help(); } process.on('exit', (code) => { console.log('Exited with code: ', code) })