From dd8d4113c5b9e8dd9ccffa1831dcee83cbc209e2 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Tue, 3 Mar 2020 15:30:55 +0100 Subject: [PATCH 1/5] Run yarn on a newly created plugin as part of the creation process --- .../packages/cli/src/commands/createPlugin.ts | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/frontend/packages/cli/src/commands/createPlugin.ts b/frontend/packages/cli/src/commands/createPlugin.ts index 06d1e0c47e..bb7b10d482 100644 --- a/frontend/packages/cli/src/commands/createPlugin.ts +++ b/frontend/packages/cli/src/commands/createPlugin.ts @@ -4,6 +4,8 @@ import handlebars from 'handlebars'; import chalk from 'chalk'; import inquirer, { Answers, Question } from 'inquirer'; import recursive from 'recursive-readdir'; +import { promisify } from 'util'; +import { exec } from 'child_process'; export const createPluginFolder = (rootDir: string, id: string): string => { const destination = path.join(rootDir, 'packages', 'plugins', id); @@ -18,7 +20,9 @@ export const createPluginFolder = (rootDir: string, id: string): string => { try { console.log( - chalk.green(`Creating:\t${chalk.cyan(destination.replace(rootDir, ''))}`), + chalk.green( + ` creating:\t${chalk.cyan(destination.replace(rootDir, ''))}`, + ), ); fs.mkdirSync(destination, { recursive: true }); return destination; @@ -42,7 +46,7 @@ export const createFileFromTemplate = ( }); try { console.log( - chalk.green(`Creating:\t${chalk.cyan(path.basename(destination))}`), + chalk.green(` creating:\t${chalk.cyan(path.basename(destination))}`), ); fs.writeFileSync(destination, contents); } catch (e) { @@ -75,7 +79,7 @@ export const createFromTemplateDir = async ( answers, ); } else { - console.log(chalk.green(`Copying:\t${chalk.cyan(path.basename(file))}`)); + console.log(chalk.green(` copying:\t${chalk.cyan(path.basename(file))}`)); try { fs.copyFileSync(file, file.replace(templateFolder, destinationFolder)); } catch (e) { @@ -98,9 +102,9 @@ const cleanUp = async (rootDir: string, id: string) => { type: 'confirm', name: 'cleanup', message: chalk.yellow( - `Do you want to remove the created directory and all the files in it?\ndir: ${chalk.cyan( + `It seems that something went wrong when creating the plugin ๐Ÿค” Do you want to remove the directory and all the files in it?\nRemove: ${chalk.cyan( destination, - )}`, + )}?`, ), }, ]; @@ -123,6 +127,24 @@ const cleanUp = async (rootDir: string, id: string) => { } }; +const buildPlugin = async (pluginFolder: string) => { + const prom_exec = promisify(exec); + + // const commands = ['yarn', 'yarn build']; + const commands = ['yarn']; + for (const command of commands) { + try { + console.log(chalk.green(` executing:\t${chalk.cyan(command)}`)); + process.chdir(pluginFolder); + await prom_exec(command, { timeout: 60000 }); + } catch (e) { + throw new Error( + `Could not execute command ${chalk.cyan(command)}: ${e.message}`, + ); + } + } +}; + const createPlugin = async (): Promise => { const questions: Question[] = [ { @@ -148,21 +170,21 @@ const createPlugin = async (): Promise => { ); try { + console.log(); + console.log(chalk.green('Creating the plugin...')); const destinationFolder = createPluginFolder(rootDir, answers.id); await createFromTemplateDir(templateFolder, destinationFolder, answers); console.log(); - console.log( - chalk.green( - `Successfully created a Backstage Plugin in ${chalk.cyan( - path.join('packages', 'plugins', answers.id), - )}`, - ), - ); + console.log(chalk.green(`Building the plugin...`)); + await buildPlugin(destinationFolder); + console.log(); console.log( chalk.green( - `Run ${chalk.cyan('yarn start')} in the plugin directory to start it.`, + `Successfully created ${chalk.cyan( + `@spotify-backstage/plugin-${answers.id}`, + )}`, ), ); console.log(); From 4a123d8acc8514abc3bed1a34443b931f41c8356 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Tue, 3 Mar 2020 16:13:58 +0100 Subject: [PATCH 2/5] Re-arrange some console.logs --- .../packages/cli/src/commands/createPlugin.ts | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/packages/cli/src/commands/createPlugin.ts b/frontend/packages/cli/src/commands/createPlugin.ts index bb7b10d482..f1e0e2837d 100644 --- a/frontend/packages/cli/src/commands/createPlugin.ts +++ b/frontend/packages/cli/src/commands/createPlugin.ts @@ -8,6 +8,9 @@ import { promisify } from 'util'; import { exec } from 'child_process'; export const createPluginFolder = (rootDir: string, id: string): string => { + console.log(); + console.log(chalk.green(' Create the plugin directory:')); + const destination = path.join(rootDir, 'packages', 'plugins', id); if (fs.existsSync(destination)) { @@ -21,7 +24,7 @@ export const createPluginFolder = (rootDir: string, id: string): string => { try { console.log( chalk.green( - ` creating:\t${chalk.cyan(destination.replace(rootDir, ''))}`, + ` created:\t${chalk.cyan(destination.replace(rootDir, ''))}`, ), ); fs.mkdirSync(destination, { recursive: true }); @@ -46,7 +49,7 @@ export const createFileFromTemplate = ( }); try { console.log( - chalk.green(` creating:\t${chalk.cyan(path.basename(destination))}`), + chalk.green(` created:\t${chalk.cyan(path.basename(destination))}`), ); fs.writeFileSync(destination, contents); } catch (e) { @@ -59,6 +62,9 @@ export const createFromTemplateDir = async ( destinationFolder: string, answers: Answers, ) => { + console.log(); + console.log(chalk.green(' Set up the plugin files:')); + let files = []; try { files = await recursive(templateFolder); @@ -79,8 +85,10 @@ export const createFromTemplateDir = async ( answers, ); } else { - console.log(chalk.green(` copying:\t${chalk.cyan(path.basename(file))}`)); try { + console.log( + chalk.green(` copied:\t${chalk.cyan(path.basename(file))}`), + ); fs.copyFileSync(file, file.replace(templateFolder, destinationFolder)); } catch (e) { throw new Error( @@ -128,13 +136,16 @@ const cleanUp = async (rootDir: string, id: string) => { }; const buildPlugin = async (pluginFolder: string) => { + console.log(); + console.log(chalk.green(` Build the plugin:`)); + const prom_exec = promisify(exec); // const commands = ['yarn', 'yarn build']; const commands = ['yarn']; for (const command of commands) { try { - console.log(chalk.green(` executing:\t${chalk.cyan(command)}`)); + console.log(chalk.green(` executing:\t${chalk.cyan(command)}`)); process.chdir(pluginFolder); await prom_exec(command, { timeout: 60000 }); } catch (e) { @@ -172,11 +183,9 @@ const createPlugin = async (): Promise => { try { console.log(); console.log(chalk.green('Creating the plugin...')); + const destinationFolder = createPluginFolder(rootDir, answers.id); await createFromTemplateDir(templateFolder, destinationFolder, answers); - - console.log(); - console.log(chalk.green(`Building the plugin...`)); await buildPlugin(destinationFolder); console.log(); From fe5e505e908a1f7456f6e6a0dd7fb73dbc164d54 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Wed, 4 Mar 2020 08:34:10 +0100 Subject: [PATCH 3/5] Now with emojis --- .../packages/cli/src/commands/createPlugin.ts | 65 ++++++++++++++----- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/frontend/packages/cli/src/commands/createPlugin.ts b/frontend/packages/cli/src/commands/createPlugin.ts index f1e0e2837d..4825e7a093 100644 --- a/frontend/packages/cli/src/commands/createPlugin.ts +++ b/frontend/packages/cli/src/commands/createPlugin.ts @@ -9,11 +9,16 @@ import { exec } from 'child_process'; export const createPluginFolder = (rootDir: string, id: string): string => { console.log(); - console.log(chalk.green(' Create the plugin directory:')); + console.log(chalk.green(' Creating the plugin directory:')); const destination = path.join(rootDir, 'packages', 'plugins', id); if (fs.existsSync(destination)) { + console.log( + chalk.red( + ` failed:\t โœ— ${chalk.cyan(destination.replace(rootDir, ''))}`, + ), + ); throw new Error( `A plugin with the same name already exists: ${chalk.cyan( destination.replace(rootDir, ''), @@ -22,14 +27,19 @@ export const createPluginFolder = (rootDir: string, id: string): string => { } try { + fs.mkdirSync(destination, { recursive: true }); console.log( chalk.green( - ` created:\t${chalk.cyan(destination.replace(rootDir, ''))}`, + ` created:\t โœ“ ${chalk.cyan(destination.replace(rootDir, ''))}`, ), ); - fs.mkdirSync(destination, { recursive: true }); return destination; } catch (e) { + console.log( + chalk.red( + ` failed:\t โœ— ${chalk.cyan(destination.replace(rootDir, ''))}`, + ), + ); throw new Error( `Failed to create plugin directory: ${destination}: ${e.message}`, ); @@ -48,11 +58,14 @@ export const createFileFromTemplate = ( ...answers, }); try { - console.log( - chalk.green(` created:\t${chalk.cyan(path.basename(destination))}`), - ); fs.writeFileSync(destination, contents); + console.log( + chalk.green(` created:\t โœ“ ${chalk.cyan(path.basename(destination))}`), + ); } catch (e) { + console.log( + chalk.red(` failed:\t โœ— ${chalk.cyan(path.basename(destination))}`), + ); throw new Error(`Failed to create file: ${destination}: ${e.message}`); } }; @@ -63,15 +76,23 @@ export const createFromTemplateDir = async ( answers: Answers, ) => { console.log(); - console.log(chalk.green(' Set up the plugin files:')); + + console.log(chalk.green(' Reading template files:')); let files = []; + try { files = await recursive(templateFolder); + console.log( + chalk.green(` read:\t\t โœ“ ${chalk.cyan(`${files.length} files`)}`), + ); } catch (e) { + console.log(chalk.red(` failed:\t โœ— 0 files`)); throw new Error(`Failed to read files in template directory: ${e.message}`); } + console.log(); + console.log(chalk.green(' Setting up the plugin files:')); files.forEach(file => { fs.ensureDirSync( file @@ -86,11 +107,14 @@ export const createFromTemplateDir = async ( ); } else { try { - console.log( - chalk.green(` copied:\t${chalk.cyan(path.basename(file))}`), - ); fs.copyFileSync(file, file.replace(templateFolder, destinationFolder)); + console.log( + chalk.green(` copied:\t โœ“ ${chalk.cyan(path.basename(file))}`), + ); } catch (e) { + console.log( + chalk.red(` failed:\t โœ— ${chalk.cyan(path.basename(file))}`), + ); throw new Error( `Failed to copy file: ${file.replace( templateFolder, @@ -110,9 +134,9 @@ const cleanUp = async (rootDir: string, id: string) => { type: 'confirm', name: 'cleanup', message: chalk.yellow( - `It seems that something went wrong when creating the plugin ๐Ÿค” Do you want to remove the directory and all the files in it?\nRemove: ${chalk.cyan( + `It seems that something went wrong when creating the plugin ๐Ÿค”\nDo you want to remove the following directory and all the files in it:\n${chalk.cyan( destination, - )}?`, + )}`, ), }, ]; @@ -124,7 +148,9 @@ const cleanUp = async (rootDir: string, id: string) => { fs.rmdirSync(destination); console.log(); console.log( - chalk.green(`Removing ${chalk.cyan(destination.replace(rootDir, ''))}`), + chalk.green( + `๐Ÿงน Removing ${chalk.cyan(destination.replace(rootDir, ''))}`, + ), ); console.log(); } catch (e) { @@ -137,7 +163,7 @@ const cleanUp = async (rootDir: string, id: string) => { const buildPlugin = async (pluginFolder: string) => { console.log(); - console.log(chalk.green(` Build the plugin:`)); + console.log(chalk.green(` Building the plugin:`)); const prom_exec = promisify(exec); @@ -145,10 +171,11 @@ const buildPlugin = async (pluginFolder: string) => { const commands = ['yarn']; for (const command of commands) { try { - console.log(chalk.green(` executing:\t${chalk.cyan(command)}`)); process.chdir(pluginFolder); await prom_exec(command, { timeout: 60000 }); + console.log(chalk.green(` executed:\t โœ“ ${chalk.cyan(command)}`)); } catch (e) { + console.log(chalk.red(` failed:\t โœ— ${chalk.cyan(command)}`)); throw new Error( `Could not execute command ${chalk.cyan(command)}: ${e.message}`, ); @@ -182,7 +209,7 @@ const createPlugin = async (): Promise => { try { console.log(); - console.log(chalk.green('Creating the plugin...')); + console.log(chalk.green('๐Ÿงฉ Creating the plugin...')); const destinationFolder = createPluginFolder(rootDir, answers.id); await createFromTemplateDir(templateFolder, destinationFolder, answers); @@ -191,7 +218,7 @@ const createPlugin = async (): Promise => { console.log(); console.log( chalk.green( - `Successfully created ${chalk.cyan( + `๐Ÿฅ‡ Successfully created ${chalk.cyan( `@spotify-backstage/plugin-${answers.id}`, )}`, ), @@ -201,7 +228,9 @@ const createPlugin = async (): Promise => { return destinationFolder; } catch (e) { console.log(); - console.log(chalk.red(e.message)); + console.log(`${chalk.red(e.message)}`); + console.log(); + console.log(`๐Ÿ”ฅ ${chalk.red('Failed to create plugin!')}`); console.log(); await cleanUp(rootDir, answers.id); From 57576f267854ea651dee8dc5759ac906da719afe Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Wed, 4 Mar 2020 09:20:36 +0100 Subject: [PATCH 4/5] Using process.stdout.write where needed for better output control --- .../packages/cli/src/commands/createPlugin.ts | 65 +++++++++---------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/frontend/packages/cli/src/commands/createPlugin.ts b/frontend/packages/cli/src/commands/createPlugin.ts index 4825e7a093..e5808ec6ea 100644 --- a/frontend/packages/cli/src/commands/createPlugin.ts +++ b/frontend/packages/cli/src/commands/createPlugin.ts @@ -26,20 +26,15 @@ export const createPluginFolder = (rootDir: string, id: string): string => { ); } + process.stdout.write( + chalk.green(` creating\t${chalk.cyan(destination.replace(rootDir, ''))}`), + ); try { fs.mkdirSync(destination, { recursive: true }); - console.log( - chalk.green( - ` created:\t โœ“ ${chalk.cyan(destination.replace(rootDir, ''))}`, - ), - ); + process.stdout.write(chalk.green(' โœ“\n')); return destination; } catch (e) { - console.log( - chalk.red( - ` failed:\t โœ— ${chalk.cyan(destination.replace(rootDir, ''))}`, - ), - ); + process.stdout.write(chalk.red(` โœ—\n`)); throw new Error( `Failed to create plugin directory: ${destination}: ${e.message}`, ); @@ -59,13 +54,9 @@ export const createFileFromTemplate = ( }); try { fs.writeFileSync(destination, contents); - console.log( - chalk.green(` created:\t โœ“ ${chalk.cyan(path.basename(destination))}`), - ); + process.stdout.write(chalk.green(` โœ“\n`)); } catch (e) { - console.log( - chalk.red(` failed:\t โœ— ${chalk.cyan(path.basename(destination))}`), - ); + process.stdout.write(chalk.red(` โœ—\n`)); throw new Error(`Failed to create file: ${destination}: ${e.message}`); } }; @@ -76,24 +67,27 @@ export const createFromTemplateDir = async ( answers: Answers, ) => { console.log(); - console.log(chalk.green(' Reading template files:')); let files = []; + process.stdout.write(chalk.green(` reading\t`)); try { files = await recursive(templateFolder); - console.log( - chalk.green(` read:\t\t โœ“ ${chalk.cyan(`${files.length} files`)}`), + process.stdout.write( + chalk.green(`${chalk.cyan(`${files.length} files`)} โœ“\n`), ); } catch (e) { - console.log(chalk.red(` failed:\t โœ— 0 files`)); + console.log(chalk.red(` โœ— 0 files\n`)); throw new Error(`Failed to read files in template directory: ${e.message}`); } console.log(); console.log(chalk.green(' Setting up the plugin files:')); files.forEach(file => { + process.stdout.write( + chalk.green(` processing\t${chalk.cyan(path.basename(file))}`), + ); fs.ensureDirSync( file .replace(templateFolder, destinationFolder) @@ -108,13 +102,9 @@ export const createFromTemplateDir = async ( } else { try { fs.copyFileSync(file, file.replace(templateFolder, destinationFolder)); - console.log( - chalk.green(` copied:\t โœ“ ${chalk.cyan(path.basename(file))}`), - ); + process.stdout.write(chalk.green(` โœ“\n`)); } catch (e) { - console.log( - chalk.red(` failed:\t โœ— ${chalk.cyan(path.basename(file))}`), - ); + process.stdout.write(chalk.red(` โœ—\n`)); throw new Error( `Failed to copy file: ${file.replace( templateFolder, @@ -143,20 +133,24 @@ const cleanUp = async (rootDir: string, id: string) => { const answers: Answers = await inquirer.prompt(questions); if (answers.cleanup) { + console.log(); + console.log(chalk.green(`๐Ÿงน Cleaning up...`)); + console.log(); + console.log(chalk.green(` Removing plugin:`)); + process.stdout.write( + chalk.green( + ` deleting\t${chalk.cyan(destination.replace(rootDir, ''))}`, + ), + ); try { // Not using recursion here, so only empty directories can be removed fs.rmdirSync(destination); - console.log(); - console.log( - chalk.green( - `๐Ÿงน Removing ${chalk.cyan(destination.replace(rootDir, ''))}`, - ), - ); + process.stdout.write(chalk.green(` โœ“\n`)); console.log(); } catch (e) { + process.stdout.write(chalk.red(` โœ—\n`)); console.log(); console.log(chalk.red(`Failed to cleanup: ${e.message}`)); - console.log(); } } }; @@ -170,12 +164,13 @@ const buildPlugin = async (pluginFolder: string) => { // const commands = ['yarn', 'yarn build']; const commands = ['yarn']; for (const command of commands) { + process.stdout.write(chalk.green(` executing\t${chalk.cyan(command)}`)); try { process.chdir(pluginFolder); await prom_exec(command, { timeout: 60000 }); - console.log(chalk.green(` executed:\t โœ“ ${chalk.cyan(command)}`)); + process.stdout.write(chalk.cyan(` โœ“\n`)); } catch (e) { - console.log(chalk.red(` failed:\t โœ— ${chalk.cyan(command)}`)); + process.stdout.write(chalk.red(` โœ—\n`)); throw new Error( `Could not execute command ${chalk.cyan(command)}: ${e.message}`, ); From 7a651ff06d9483c5e8f7dc19e433fcc03a1782af Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Wed, 4 Mar 2020 10:17:31 +0100 Subject: [PATCH 5/5] Bump version --- frontend/packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/packages/cli/package.json b/frontend/packages/cli/package.json index e2a24a6214..49b50e2664 100644 --- a/frontend/packages/cli/package.json +++ b/frontend/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@spotify-backstage/cli", - "version": "1.2.0", + "version": "1.3.0", "main": "src/index.ts", "main:src": "src/index.ts", "license": "Apache-2.0",