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", diff --git a/frontend/packages/cli/src/commands/createPlugin.ts b/frontend/packages/cli/src/commands/createPlugin.ts index 06d1e0c47e..e5808ec6ea 100644 --- a/frontend/packages/cli/src/commands/createPlugin.ts +++ b/frontend/packages/cli/src/commands/createPlugin.ts @@ -4,11 +4,21 @@ 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 => { + console.log(); + 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, ''), @@ -16,13 +26,15 @@ export const createPluginFolder = (rootDir: string, id: string): string => { ); } + process.stdout.write( + chalk.green(` creating\t${chalk.cyan(destination.replace(rootDir, ''))}`), + ); try { - console.log( - chalk.green(`Creating:\t${chalk.cyan(destination.replace(rootDir, ''))}`), - ); fs.mkdirSync(destination, { recursive: true }); + process.stdout.write(chalk.green(' ✓\n')); return destination; } catch (e) { + process.stdout.write(chalk.red(` ✗\n`)); throw new Error( `Failed to create plugin directory: ${destination}: ${e.message}`, ); @@ -41,11 +53,10 @@ export const createFileFromTemplate = ( ...answers, }); try { - console.log( - chalk.green(`Creating:\t${chalk.cyan(path.basename(destination))}`), - ); fs.writeFileSync(destination, contents); + process.stdout.write(chalk.green(` ✓\n`)); } catch (e) { + process.stdout.write(chalk.red(` ✗\n`)); throw new Error(`Failed to create file: ${destination}: ${e.message}`); } }; @@ -55,14 +66,28 @@ export const createFromTemplateDir = async ( destinationFolder: string, 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); + process.stdout.write( + chalk.green(`${chalk.cyan(`${files.length} files`)} ✓\n`), + ); } catch (e) { + 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) @@ -75,10 +100,11 @@ export const createFromTemplateDir = async ( answers, ); } else { - console.log(chalk.green(`Copying:\t${chalk.cyan(path.basename(file))}`)); try { fs.copyFileSync(file, file.replace(templateFolder, destinationFolder)); + process.stdout.write(chalk.green(` ✓\n`)); } catch (e) { + process.stdout.write(chalk.red(` ✗\n`)); throw new Error( `Failed to copy file: ${file.replace( templateFolder, @@ -98,7 +124,7 @@ 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 🤔\nDo you want to remove the following directory and all the files in it:\n${chalk.cyan( destination, )}`, ), @@ -107,18 +133,47 @@ 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(); + } + } +}; + +const buildPlugin = async (pluginFolder: string) => { + console.log(); + console.log(chalk.green(` Building the plugin:`)); + + const prom_exec = promisify(exec); + + // 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 }); + process.stdout.write(chalk.cyan(` ✓\n`)); + } catch (e) { + process.stdout.write(chalk.red(` ✗\n`)); + throw new Error( + `Could not execute command ${chalk.cyan(command)}: ${e.message}`, + ); } } }; @@ -148,29 +203,29 @@ 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); + await buildPlugin(destinationFolder); console.log(); console.log( chalk.green( - `Successfully created a Backstage Plugin in ${chalk.cyan( - path.join('packages', 'plugins', answers.id), + `🥇 Successfully created ${chalk.cyan( + `@spotify-backstage/plugin-${answers.id}`, )}`, ), ); - - console.log( - chalk.green( - `Run ${chalk.cyan('yarn start')} in the plugin directory to start it.`, - ), - ); console.log(); 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);