UNPKG

@squiz/dxp-cli

Version:

The command line interface for dxp

205 lines (180 loc) • 6.41 kB
#!/usr/bin/env node /*! * @license * Copyright Squiz Australia Pty Ltd. All Rights Reserved. */ /* eslint-disable unicorn/no-abusive-eslint-disable */ /* eslint-disable */ const readline = require('readline'); const readlineInterface = readline.createInterface({ input: process.stdin, output: process.stdout, }); const { spawnSync } = require('child_process'); const { readdirSync, existsSync } = require('fs'); const homedir = require('os').homedir(); /** * The OS specific path to the config store folder. * @constant {string} */ const CONFIG_FOLDER_PATH = `${homedir}/.config`; /** * The OS specific path to the dxp config store folder. * @constant {string} */ const DXP_CONFIG_FOLDER_PATH = `${CONFIG_FOLDER_PATH}/dxp`; /** * The OS specific path to the dxp plugins config store folder. * @constant {string} */ const DXP_PLUGINS_FOLDER_PATH = `${DXP_CONFIG_FOLDER_PATH}/plugins`; /** * Asynchronously run forEach over array. * @param {array} - The array to iterate and call async function on it. * @param {callback} - Async callback to run on each element. * @return {void} */ async function asyncForEach(array, callback) { for (let index = 0; index < array.length; index++) { await callback(array[index], index, array); } } /** * Prompt the question text to the command line and get the input. * @param {string} questionText - The question text to prompt. * @return {Promise} */ function ask(questionText) { return new Promise((resolve, reject) => { readlineInterface.question(questionText, (input) => resolve(input)); }); } /** * Helper function to print text message in boxed format. * @param {string} message - The message to print in boxed format. * @return {void} */ function printHeader(message) { console.log(``); console.log(`-`.repeat(message.length)); console.log(message); console.log(`-`.repeat(message.length)); } /** * Executes CLI command. * @param {string} cmd - The raw command string to run. * @param {string} description - The optional description to to describe the command. * @return {object} * @throws {Error} - Thrown for non-zero exit code. */ async function runCmd(cmd, description = null) { printHeader(`${description === null ? 'Running' : description}: $ ${cmd}`); const options = { stdio: [process.stdin.fd, process.stdout.fd, process.stderr.fd] }; const cmdParts = cmd.split(` `); const command = cmdParts[0]; const args = cmdParts.length > 1 ? cmdParts.slice(1) : []; const result = await spawnSync(command, args, options); result.stdout = Buffer.isBuffer(result.stdout) ? result.stdout.toString() : ``; result.stderr = Buffer.isBuffer(result.stderr) ? result.stderr.toString() : ``; if (result.status !== 0) { throw new Error(result.stderr); } return result; } /** * Get the list of installed dxp plugins. * @returns {array} */ async function getDxpPlugins() { if (existsSync(DXP_PLUGINS_FOLDER_PATH) === false) { return []; } return (await readdirSync(`${DXP_PLUGINS_FOLDER_PATH}/node_modules/@squiz`)).filter( (pluginFolderName) => pluginFolderName !== `dxp-plugin-core` && pluginFolderName.indexOf(`dxp-plugin`) === 0, ); } /** * Perform DXP CLI upgrade. * @param {array} pluginNames - The list of plugin names to upgrade. * @param {string} version - Optional package version number. * @return {void} */ async function upgrade(pluginNames = [], version = null) { await runCmd(`npm uninstall -g @squiz/dxp-cli`, `Uninstall @squiz/dxp-cli package`); await runCmd(`rm -rf ${DXP_CONFIG_FOLDER_PATH}`, `Clean up DXP config folder`); // List of plugins that have been removed entirely. If the user already had them before, // exclude it from the list. const retiredPlugins = [ 'dxp-plugin-core-internal', 'dxp-plugin-datastore', 'dxp-plugin-datastore-internal', 'dxp-plugin-funnelback', 'dxp-plugin-funnelback-internal', 'dxp-plugin-ipaas', 'dxp-plugin-ipaas-internal', 'dxp-plugin-matrix', 'dxp-plugin-matrix-internal', 'dxp-plugin-sxp', 'dxp-plugin-sxp-internal', 'dxp-plugin-workplace', 'dxp-plugin-workplace-internal', ]; pluginNames = pluginNames.filter((pluginName) => retiredPlugins.includes(pluginName) === false); await runCmd( `npm install -g --silent @squiz/dxp-cli${version === null ? '' : '@' + version}`, `Install @squiz/dxp-cli package`, ); await asyncForEach(pluginNames, async (pluginName) => { await runCmd( `dxp plugin add @squiz/${pluginName}${version === null ? '' : '@' + version}`, `Installing ${pluginName} plugin`, ); }); await runCmd(`dxp --version`, `Show the updated DXP CLI version`); } async function main() { try { const plugins = await getDxpPlugins(); if (plugins.length > 0) { printHeader(`${plugins.length} dxp plugins found to upgrade:`); plugins.forEach((pluginName) => console.log(` - ${pluginName}`)); } // If any internal plugin exist, then confirm the NPM login.s if (plugins.filter((pluginName) => pluginName.indexOf(`-internal`) !== -1).length > 0) { try { await runCmd(`npm whoami`, `Checking NPM credential`); console.log(``); } catch (noNpmLoginErr) { console.error(``); console.error(`You must be login to NPM to install internal DXP plugins`); process.exit(1); } } let answer = await ask( `Do you want to upgrade all plugins to ` + (process.env.DXP_CLI_VERSION ? process.env.DXP_CLI_VERSION : `the latest stable`) + ` version? (y/N) `, ); answer = answer.trim(); if (answer.toLowerCase() === `y`) { await upgrade(plugins, process.env.DXP_CLI_VERSION ? process.env.DXP_CLI_VERSION : null); } else if (answer === `` || answer.toLowerCase() === `n`) { console.log(``); console.log(`Bye~`); process.exit(0); } else { console.error(`Unknown answer`); process.exit(1); } process.exit(0); } catch (err) { const docLink = `https://docs.squiz.systems/experience-cloud/latest/customer-success-admin-guide/administering-with-the-cli.html#upgrading-the-cli-tools-for-administrators`; console.error( `Error occurred during the upgrade. Please follow the Upgrading the CLI tools for administrators guide from ${docLink}`, ); process.exit(1); } } if (require.main === module) { main(); }