Merge pull request #143 from spotify/eide/cli-feedback

[cli] Add more user feedback
This commit is contained in:
marcuseide
2020-03-03 15:07:52 +01:00
committed by GitHub
4 changed files with 106 additions and 22 deletions
+1
View File
@@ -6,6 +6,7 @@
"license": "Apache-2.0",
"private": false,
"scripts": {
"exec": "npx ts-node ./src",
"build": "web-scripts build",
"lint": "web-scripts lint",
"test": "web-scripts test",
@@ -1,6 +1,7 @@
import fs from 'fs-extra';
import path from 'path';
import handlebars from 'handlebars';
import chalk from 'chalk';
import inquirer, { Answers, Question } from 'inquirer';
import recursive from 'recursive-readdir';
@@ -9,11 +10,16 @@ export const createPluginFolder = (rootDir: string, id: string): string => {
if (fs.existsSync(destination)) {
throw new Error(
`A plugin with the same name already exists: ${destination}`,
`A plugin with the same name already exists: ${chalk.cyan(
destination.replace(rootDir, ''),
)}\nPlease try again with a different Plugin ID`,
);
}
try {
console.log(
chalk.green(`Creating:\t${chalk.cyan(destination.replace(rootDir, ''))}`),
);
fs.mkdirSync(destination, { recursive: true });
return destination;
} catch (e) {
@@ -35,6 +41,9 @@ export const createFileFromTemplate = (
...answers,
});
try {
console.log(
chalk.green(`Creating:\t${chalk.cyan(path.basename(destination))}`),
);
fs.writeFileSync(destination, contents);
} catch (e) {
throw new Error(`Failed to create file: ${destination}: ${e.message}`);
@@ -66,27 +75,68 @@ export const createFromTemplateDir = async (
answers,
);
} else {
fs.copyFileSync(file, file.replace(templateFolder, destinationFolder));
console.log(chalk.green(`Copying:\t${chalk.cyan(path.basename(file))}`));
try {
fs.copyFileSync(file, file.replace(templateFolder, destinationFolder));
} catch (e) {
throw new Error(
`Failed to copy file: ${file.replace(
templateFolder,
destinationFolder,
)}: ${e.message}`,
);
}
}
});
};
const cleanUp = async (rootDir: string, id: string) => {
const destination = path.join(rootDir, 'packages', 'plugins', id);
const questions: Question[] = [
{
type: 'confirm',
name: 'cleanup',
message: chalk.yellow(
`Do you want to remove the created directory and all the files in it?\ndir: ${chalk.cyan(
destination,
)}`,
),
},
];
const answers: Answers = await inquirer.prompt(questions);
if (answers.cleanup) {
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, ''))}`),
);
console.log();
} catch (e) {
console.log();
console.log(chalk.red(`Failed to cleanup: ${e.message}`));
console.log();
}
}
};
const createPlugin = async (): Promise<any> => {
const currentDir = process.argv[1];
const questions: Question[] = [
{
type: 'input',
name: 'id',
message: 'Enter an ID for the plugin [required]',
message: chalk.blue('Enter an ID for the plugin [required]'),
validate: (value: any) =>
value ? true : 'Please enter an ID for the plugin',
value ? true : chalk.red('Please enter an ID for the plugin'),
},
];
const answers: Answers = await inquirer.prompt(questions);
const destinationFolder = createPluginFolder(
path.join(currentDir, '..', '..', '..'),
answers.id,
);
const currentDir = process.argv[1];
const rootDir = path.join(currentDir, '..', '..', '..');
const templateFolder = path.join(
currentDir,
'..',
@@ -97,15 +147,34 @@ const createPlugin = async (): Promise<any> => {
'default-plugin',
);
await createFromTemplateDir(templateFolder, destinationFolder, answers);
try {
const destinationFolder = createPluginFolder(rootDir, answers.id);
await createFromTemplateDir(templateFolder, destinationFolder, answers);
console.log(
`✨ You have created a Backstage Plugin packages/plugins/${answers.id}`,
);
console.log('');
console.log('Run yarn start in the plugin directory to start it');
console.log();
console.log(
chalk.green(
`Successfully created a Backstage Plugin in ${chalk.cyan(
path.join('packages', 'plugins', answers.id),
)}`,
),
);
return destinationFolder;
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();
await cleanUp(rootDir, answers.id);
}
};
export default createPlugin;
+16 -5
View File
@@ -1,4 +1,6 @@
import program from 'commander';
import chalk from 'chalk';
import fs from 'fs';
import createPluginCommand from './commands/createPlugin';
import watch from './commands/watch-deps';
import serve from './commands/serve';
@@ -8,6 +10,10 @@ process.on('unhandledRejection', err => {
});
const main = (argv: string[]) => {
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
program.name('backstage-cli').version(packageJson.version ?? '0.0.0');
program
.command('create-plugin')
.description('Creates a new plugin in the current repository')
@@ -24,16 +30,21 @@ const main = (argv: string[]) => {
.action(watch);
program.on('command:*', () => {
// eslint-disable-next-line no-console
console.error(
'Invalid command: %s\nSee --help for a list of available commands.',
program.args.join(' '),
console.log();
console.log(
chalk.red(`Invalid command: ${chalk.cyan(program.args.join(' '))}`),
);
console.log(chalk.red('See --help for a list of available commands.'));
console.log();
process.exit(1);
});
if (!process.argv.slice(2).length) {
program.outputHelp(chalk.yellow);
}
program.parse(argv);
};
main(process.argv);
// main([process.argv[0], process.argv[1], 'create-plugin']);
// main([process.argv[0], process.argv[1], '--version']);
@@ -11,6 +11,9 @@ const useStyles = makeStyles<Theme>(theme => ({
pageBody: {
padding: theme.spacing(3),
},
title: {
padding: theme.spacing(1,0,2,0),
},
}));
const ExampleComponent: FC<{}> = () => {
@@ -23,7 +26,7 @@ const ExampleComponent: FC<{}> = () => {
subtitle="Optional subtitle"
></Header>
<div className={classes.pageBody}>
<Typography variant="h3" style={{ padding: '8px 0 16px 0' }}>
<Typography variant="h3" className={classes.title}>
Plugin page title
</Typography>
<InfoCard title="Information card" maxWidth>