Merge pull request #7439 from cmpadden/create-app-path-option
Support optional [path] argument in create-app command-line utility
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Support optional path argument when generating a project using `create-app`
|
||||
@@ -27,7 +27,7 @@ import { Task, templatingTask } from './lib/tasks';
|
||||
|
||||
const exec = promisify(execCb);
|
||||
|
||||
async function checkExists(rootDir: string, name: string) {
|
||||
async function checkAppExists(rootDir: string, name: string) {
|
||||
await Task.forItem('checking', name, async () => {
|
||||
const destination = resolvePath(rootDir, name);
|
||||
|
||||
@@ -40,6 +40,17 @@ async function checkExists(rootDir: string, name: string) {
|
||||
});
|
||||
}
|
||||
|
||||
async function checkPathExists(path: string) {
|
||||
await Task.forItem('checking', path, async () => {
|
||||
try {
|
||||
await fs.mkdirs(path);
|
||||
} catch (error) {
|
||||
// will fail if a file already exists at given `path`
|
||||
throw new Error(`Failed to create app directory: ${error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function createTemporaryAppFolder(tempDir: string) {
|
||||
await Task.forItem('creating', 'temporary directory', async () => {
|
||||
try {
|
||||
@@ -50,12 +61,6 @@ async function createTemporaryAppFolder(tempDir: string) {
|
||||
});
|
||||
}
|
||||
|
||||
async function cleanUp(tempDir: string) {
|
||||
await Task.forItem('remove', 'temporary directory', async () => {
|
||||
await fs.remove(tempDir);
|
||||
});
|
||||
}
|
||||
|
||||
async function buildApp(appDir: string) {
|
||||
const runCmd = async (cmd: string) => {
|
||||
await Task.forItem('executing', cmd, async () => {
|
||||
@@ -75,11 +80,17 @@ async function buildApp(appDir: string) {
|
||||
|
||||
async function moveApp(tempDir: string, destination: string, id: string) {
|
||||
await Task.forItem('moving', id, async () => {
|
||||
await fs.move(tempDir, destination).catch(error => {
|
||||
throw new Error(
|
||||
`Failed to move app from ${tempDir} to ${destination}: ${error.message}`,
|
||||
);
|
||||
});
|
||||
await fs
|
||||
.move(tempDir, destination)
|
||||
.catch(error => {
|
||||
throw new Error(
|
||||
`Failed to move app from ${tempDir} to ${destination}: ${error.message}`,
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
// remove temporary files on both success and failure
|
||||
fs.removeSync(tempDir);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -117,23 +128,40 @@ export default async (cmd: Command): Promise<void> => {
|
||||
|
||||
const templateDir = paths.resolveOwn('templates/default-app');
|
||||
const tempDir = resolvePath(os.tmpdir(), answers.name);
|
||||
const appDir = resolvePath(paths.targetDir, answers.name);
|
||||
|
||||
// Use `--path` argument as applicaiton directory when specified, otherwise
|
||||
// create a directory using `answers.name`
|
||||
const appDir = cmd.path
|
||||
? resolvePath(paths.targetDir, cmd.path)
|
||||
: resolvePath(paths.targetDir, answers.name);
|
||||
|
||||
Task.log();
|
||||
Task.log('Creating the app...');
|
||||
|
||||
try {
|
||||
Task.section('Checking if the directory is available');
|
||||
await checkExists(paths.targetDir, answers.name);
|
||||
if (cmd.path) {
|
||||
// Template directly to specified path
|
||||
|
||||
Task.section('Creating a temporary app directory');
|
||||
await createTemporaryAppFolder(tempDir);
|
||||
Task.section('Checking that supplied path exists');
|
||||
await checkPathExists(appDir);
|
||||
|
||||
Task.section('Preparing files');
|
||||
await templatingTask(templateDir, tempDir, answers);
|
||||
Task.section('Preparing files');
|
||||
await templatingTask(templateDir, cmd.path, answers);
|
||||
} else {
|
||||
// Template to temporary location, and then move files
|
||||
|
||||
Task.section('Moving to final location');
|
||||
await moveApp(tempDir, appDir, answers.name);
|
||||
Task.section('Checking if the directory is available');
|
||||
await checkAppExists(paths.targetDir, answers.name);
|
||||
|
||||
Task.section('Creating a temporary app directory');
|
||||
await createTemporaryAppFolder(tempDir);
|
||||
|
||||
Task.section('Preparing files');
|
||||
await templatingTask(templateDir, tempDir, answers);
|
||||
|
||||
Task.section('Moving to final location');
|
||||
await moveApp(tempDir, appDir, answers.name);
|
||||
}
|
||||
|
||||
if (!cmd.skipInstall) {
|
||||
Task.section('Building the app');
|
||||
@@ -157,10 +185,7 @@ export default async (cmd: Command): Promise<void> => {
|
||||
Task.error(String(error));
|
||||
|
||||
Task.log('It seems that something went wrong when creating the app 🤔');
|
||||
Task.log('We are going to clean up, and then you can try again.');
|
||||
|
||||
Task.section('Cleanup');
|
||||
await cleanUp(tempDir);
|
||||
Task.error('🔥 Failed to create app!');
|
||||
Task.exit(1);
|
||||
}
|
||||
|
||||
@@ -26,10 +26,14 @@ import { version } from '../package.json';
|
||||
import createApp from './createApp';
|
||||
|
||||
const main = (argv: string[]) => {
|
||||
program.name('backstage-create-app').version(version);
|
||||
|
||||
program
|
||||
.description('Creates a new app in a new directory')
|
||||
.name('backstage-create-app')
|
||||
.version(version)
|
||||
.description('Creates a new app in a new directory or specified path')
|
||||
.option(
|
||||
'--path [directory]',
|
||||
'Location to store the app defaulting to a new folder with the app name',
|
||||
)
|
||||
.option(
|
||||
'--skip-install',
|
||||
'Skip the install and builds steps after creating the app',
|
||||
|
||||
Reference in New Issue
Block a user