From c3ca11436b912831eb84c5f253fcc7a7b25df4fe Mon Sep 17 00:00:00 2001 From: monteri Date: Thu, 7 Sep 2023 17:23:19 +0300 Subject: [PATCH 1/4] feat: help command for Paragon CLI --- README.md | 10 ++++++++ bin/paragon-scripts.js | 54 ++++++++++++++++++++++++++++++++++----- lib/help.js | 57 ++++++++++++++++++++++++++++++++++++++++++ lib/install-theme.js | 25 ++++++++++++++++-- 4 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 lib/help.js diff --git a/README.md b/README.md index b3f5a12eea..647c1151ee 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,16 @@ Usage on with `@edx/brand`: Note that including fonts will affect performance. In some applications may choose not to load the custom font to keep it highly performant. +## Paragon CLI + +The Paragon CLI (Command Line Interface) is a tool that provides various utility commands to automate actions within the Open edX environment. + +### Available Commands + +- `paragon install-theme [theme]`: Installs the specific @edx/brand package. + +Use `paragon help` to see more information. + ## Getting Help Please reach out to the Paragon Working Group (PWG): diff --git a/bin/paragon-scripts.js b/bin/paragon-scripts.js index acf1252236..813a28d807 100755 --- a/bin/paragon-scripts.js +++ b/bin/paragon-scripts.js @@ -1,10 +1,49 @@ #!/usr/bin/env node +/* eslint-disable no-console */ const chalk = require('chalk'); const themeCommand = require('../lib/install-theme'); +const helpCommand = require('../lib/help'); -// command: executor function const COMMANDS = { - 'install-theme': themeCommand, + // 'command-name': { + // executor: executorFunc, + // + // ********** Block for help command start ********** + // description: 'Command description', + // parameters: [ + // { + // name: 'paramName', + // description: 'paramDescription', + // defaultValue: 'paramDefaultValue', + // required: true/false, + // }, + // ... + // ], + // options: [ + // { + // name: '--optionName', + // description: 'optionDescription', + // }, + // ... + // ], + // ********** Block for help command end ********** + // }, + 'install-theme': { + executor: themeCommand, + description: 'Installs the specific @edx/brand package.', + parameters: [ + { + name: 'theme', + description: 'The @edx/brand package to install.', + defaultValue: '@edx/brand-openedx@latest', + required: false, + }, + ], + }, + help: { + executor: helpCommand, + description: 'Displays help for available commands.', + }, }; (async () => { @@ -12,15 +51,18 @@ const COMMANDS = { const executor = COMMANDS[command]; if (!executor) { - // eslint-disable-next-line no-console - console.log(chalk.red.bold('Unknown command. Usage: paragon ')); + console.log(chalk.red.bold('Unknown command. Usage: paragon .')); + return; + } + + if (command === 'help') { + helpCommand(COMMANDS); return; } try { - await executor(); + await executor.executor(); } catch (error) { - // eslint-disable-next-line no-console console.error(chalk.red.bold('An error occurred:', error.message)); process.exit(1); } diff --git a/lib/help.js b/lib/help.js new file mode 100644 index 0000000000..721b8c583a --- /dev/null +++ b/lib/help.js @@ -0,0 +1,57 @@ +/* eslint-disable no-console */ +const chalk = require('chalk'); + +const DESCRIPTION_PAD = 20; + +/** + * Pads a description string to align with a specified offset string. + * + * @param {string} description - The description to pad. + * @param {string} offsetString - The offset string that the description should align with. + * @returns {string} - The padded description. + */ +function padLeft(description, offsetString) { + // Calculate the necessary padding based on the offsetString length + const padding = ' '.repeat(Math.max(0, DESCRIPTION_PAD - offsetString.length)); + return `${padding}${description}`; +} + +/** + * Displays a help message for available commands, including descriptions, parameters, and options. + * + * @param {Object} commands - An object containing information about available commands. + */ +function helpCommand(commands) { + console.log(chalk.yellow.bold('Paragon Help')); + console.log(); + console.log('Available commands:'); + console.log(); + + Object.keys(commands).forEach(command => { + console.log(` ${chalk.green.bold(command)}`); + if (commands[command].description) { + console.log(` ${commands[command].description}`); + } + + if (commands[command].parameters && commands[command].parameters.length > 0) { + console.log(` ${chalk.cyan('Parameters: ')}`); + commands[command].parameters.forEach(parameter => { + const requiredStatus = parameter.required ? 'Required' : 'Optional'; + const formattedDescription = padLeft(parameter.description, parameter.name); + console.log(` ${parameter.name}${formattedDescription} (${requiredStatus}, Default: ${parameter.defaultValue || 'None'})`); + }); + } + + if (commands[command].options && commands[command].options.length > 0) { + console.log(` ${chalk.cyan('Options: ')}`); + commands[command].options.forEach(option => { + const formattedDescription = padLeft(option.description, option.name); + console.log(` ${option.name}${formattedDescription}`); + }); + } + + console.log(); + }); +} + +module.exports = helpCommand; diff --git a/lib/install-theme.js b/lib/install-theme.js index edc3c09e00..0ff3032da6 100644 --- a/lib/install-theme.js +++ b/lib/install-theme.js @@ -1,6 +1,12 @@ +/* eslint-disable no-console */ const inquirer = require('inquirer'); const childProcess = require('child_process'); +/** + * Prompts the user to enter the @edx/brand package they want to install. + * + * @returns {Promise} - A Promise that resolves to an object containing the user's input. + */ function promptUserForTheme() { return inquirer.prompt([ { @@ -12,6 +18,11 @@ function promptUserForTheme() { ]); } +/** + * Installs a specified @edx/brand package. + * + * @param {string} theme - The @edx/brand package to install. + */ function installTheme(theme) { const version = theme ? `npm:${theme}` : ''; @@ -20,9 +31,19 @@ function installTheme(theme) { childProcess.execSync(installCommand, { stdio: 'inherit' }); } +/** + * Command handler for installing an @edx/brand package. + */ async function themeCommand() { - const answers = await promptUserForTheme(); - installTheme(answers.theme); + // Check if the user passed a theme parameter as a command-line argument + console.log('process.argv', process.argv); + if (process.argv.length === 4) { + const providedTheme = process.argv[3]; + installTheme(providedTheme); + } else { + const answers = await promptUserForTheme(); + installTheme(answers.theme); + } } module.exports = themeCommand; From c73c078afeb37ff26f9d9747a6ed060316c83a5f Mon Sep 17 00:00:00 2001 From: monteri Date: Thu, 7 Sep 2023 17:29:14 +0300 Subject: [PATCH 2/4] feat: remove console log --- lib/install-theme.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/install-theme.js b/lib/install-theme.js index 0ff3032da6..89156cadff 100644 --- a/lib/install-theme.js +++ b/lib/install-theme.js @@ -36,7 +36,6 @@ function installTheme(theme) { */ async function themeCommand() { // Check if the user passed a theme parameter as a command-line argument - console.log('process.argv', process.argv); if (process.argv.length === 4) { const providedTheme = process.argv[3]; installTheme(providedTheme); From 032e705db1892cf15ee90aa35ef73d7600f56234 Mon Sep 17 00:00:00 2001 From: monteri Date: Fri, 8 Sep 2023 17:53:21 +0300 Subject: [PATCH 3/4] feat: PR comments update --- bin/paragon-scripts.js | 55 +++++++++++++++++++++++------------------- lib/install-theme.js | 3 ++- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/bin/paragon-scripts.js b/bin/paragon-scripts.js index 813a28d807..47ef258f0b 100755 --- a/bin/paragon-scripts.js +++ b/bin/paragon-scripts.js @@ -1,33 +1,36 @@ #!/usr/bin/env node -/* eslint-disable no-console */ const chalk = require('chalk'); const themeCommand = require('../lib/install-theme'); const helpCommand = require('../lib/help'); +const HELP_COMMAND = 'help'; + const COMMANDS = { - // 'command-name': { - // executor: executorFunc, - // - // ********** Block for help command start ********** - // description: 'Command description', - // parameters: [ - // { - // name: 'paramName', - // description: 'paramDescription', - // defaultValue: 'paramDefaultValue', - // required: true/false, - // }, - // ... - // ], - // options: [ - // { - // name: '--optionName', - // description: 'optionDescription', - // }, - // ... - // ], - // ********** Block for help command end ********** - // }, + /** + *'command-name': { + * executor: executorFunc, + * + * ********** Block for help command start ********** + * description: 'Command description', + * parameters: [ + * { + * name: 'paramName', + * description: 'paramDescription', + * defaultValue: 'paramDefaultValue', + * required: true/false, + * }, + * ... + * ], + * options: [ + * { + * name: '--optionName', + * description: 'optionDescription', + * }, + * ... + * ], + * ********** Block for help command end ********** + *}, + */ 'install-theme': { executor: themeCommand, description: 'Installs the specific @edx/brand package.', @@ -51,11 +54,12 @@ const COMMANDS = { const executor = COMMANDS[command]; if (!executor) { + // eslint-disable-next-line no-console console.log(chalk.red.bold('Unknown command. Usage: paragon .')); return; } - if (command === 'help') { + if (command === HELP_COMMAND) { helpCommand(COMMANDS); return; } @@ -63,6 +67,7 @@ const COMMANDS = { try { await executor.executor(); } catch (error) { + // eslint-disable-next-line no-console console.error(chalk.red.bold('An error occurred:', error.message)); process.exit(1); } diff --git a/lib/install-theme.js b/lib/install-theme.js index 89156cadff..3eb03c54a2 100644 --- a/lib/install-theme.js +++ b/lib/install-theme.js @@ -36,7 +36,8 @@ function installTheme(theme) { */ async function themeCommand() { // Check if the user passed a theme parameter as a command-line argument - if (process.argv.length === 4) { + const userPassedThemeParameter = process.argv.length === 4; + if (userPassedThemeParameter) { const providedTheme = process.argv[3]; installTheme(providedTheme); } else { From 3d463de291dc4c954b77ba0d82f815ea48923fab Mon Sep 17 00:00:00 2001 From: monteri Date: Mon, 18 Sep 2023 15:07:49 +0300 Subject: [PATCH 4/4] feat: update commands code --- lib/help.js | 14 +++++++------- lib/install-theme.js | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/help.js b/lib/help.js index 721b8c583a..9491995a18 100644 --- a/lib/help.js +++ b/lib/help.js @@ -27,24 +27,24 @@ function helpCommand(commands) { console.log('Available commands:'); console.log(); - Object.keys(commands).forEach(command => { + Object.entries(commands).forEach(([command, { parameters, description, options }]) => { console.log(` ${chalk.green.bold(command)}`); - if (commands[command].description) { - console.log(` ${commands[command].description}`); + if (description) { + console.log(` ${description}`); } - if (commands[command].parameters && commands[command].parameters.length > 0) { + if (parameters && parameters.length > 0) { console.log(` ${chalk.cyan('Parameters: ')}`); - commands[command].parameters.forEach(parameter => { + parameters.forEach(parameter => { const requiredStatus = parameter.required ? 'Required' : 'Optional'; const formattedDescription = padLeft(parameter.description, parameter.name); console.log(` ${parameter.name}${formattedDescription} (${requiredStatus}, Default: ${parameter.defaultValue || 'None'})`); }); } - if (commands[command].options && commands[command].options.length > 0) { + if (options && options.length > 0) { console.log(` ${chalk.cyan('Options: ')}`); - commands[command].options.forEach(option => { + options.forEach(option => { const formattedDescription = padLeft(option.description, option.name); console.log(` ${option.name}${formattedDescription}`); }); diff --git a/lib/install-theme.js b/lib/install-theme.js index 3eb03c54a2..a7b408c24b 100644 --- a/lib/install-theme.js +++ b/lib/install-theme.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ const inquirer = require('inquirer'); const childProcess = require('child_process');