@backstage/create-app 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @backstage/create-app
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 4f1c30c176: Support optional path argument when generating a project using `create-app`
8
+ - Updated dependencies
9
+ - @backstage/cli-common@0.1.5
10
+
3
11
  ## 0.4.0
4
12
 
5
13
  ### Minor Changes
package/dist/index.cjs.js CHANGED
@@ -55,43 +55,43 @@ ${chalk__default['default'].red(`${error}`)}
55
55
  }
56
56
  }
57
57
 
58
- var version$z = "0.4.0";
58
+ var version$z = "0.4.1";
59
59
 
60
- var version$y = "0.9.7";
60
+ var version$y = "0.9.8";
61
61
 
62
62
  var version$x = "0.5.0";
63
63
 
64
- var version$w = "0.9.5";
64
+ var version$w = "0.9.6";
65
65
 
66
- var version$v = "0.8.0";
66
+ var version$v = "0.8.1";
67
67
 
68
- var version$u = "0.1.10";
68
+ var version$u = "0.1.11";
69
69
 
70
- var version$t = "0.1.18";
70
+ var version$t = "0.1.19";
71
71
 
72
- var version$s = "0.7.1";
72
+ var version$s = "0.7.2";
73
73
 
74
- var version$r = "0.1.11";
74
+ var version$r = "0.1.12";
75
75
 
76
- var version$q = "0.1.3";
76
+ var version$q = "0.1.4";
77
77
 
78
- var version$p = "0.1.12";
78
+ var version$p = "0.1.13";
79
79
 
80
- var version$o = "0.1.19";
80
+ var version$o = "0.1.20";
81
81
 
82
- var version$n = "0.2.11";
82
+ var version$n = "0.2.12";
83
83
 
84
84
  var version$m = "0.6.12";
85
85
 
86
- var version$l = "0.3.17";
86
+ var version$l = "0.3.18";
87
87
 
88
- var version$k = "0.4.5";
88
+ var version$k = "0.4.6";
89
89
 
90
90
  var version$j = "0.7.2";
91
91
 
92
- var version$i = "0.6.1";
92
+ var version$i = "0.6.2";
93
93
 
94
- var version$h = "0.17.1";
94
+ var version$h = "0.17.2";
95
95
 
96
96
  var version$g = "0.7.3";
97
97
 
@@ -109,21 +109,21 @@ var version$a = "0.2.13";
109
109
 
110
110
  var version$9 = "0.1.15";
111
111
 
112
- var version$8 = "0.11.8";
112
+ var version$8 = "0.11.9";
113
113
 
114
- var version$7 = "0.15.10";
114
+ var version$7 = "0.15.11";
115
115
 
116
- var version$6 = "0.4.15";
116
+ var version$6 = "0.4.16";
117
117
 
118
118
  var version$5 = "0.2.6";
119
119
 
120
- var version$4 = "0.4.2";
120
+ var version$4 = "0.4.3";
121
121
 
122
122
  var version$3 = "0.4.11";
123
123
 
124
- var version$2 = "0.12.3";
124
+ var version$2 = "0.12.4";
125
125
 
126
- var version$1 = "0.10.5";
126
+ var version$1 = "0.10.6";
127
127
 
128
128
  var version = "0.3.10";
129
129
 
@@ -240,7 +240,7 @@ async function templatingTask(templateDir, destinationDir, context) {
240
240
  }
241
241
 
242
242
  const exec = util.promisify(child_process.exec);
243
- async function checkExists(rootDir, name) {
243
+ async function checkAppExists(rootDir, name) {
244
244
  await Task.forItem("checking", name, async () => {
245
245
  const destination = path.resolve(rootDir, name);
246
246
  if (await fs__default['default'].pathExists(destination)) {
@@ -250,6 +250,15 @@ Please try again with a different app name`);
250
250
  }
251
251
  });
252
252
  }
253
+ async function checkPathExists(path) {
254
+ await Task.forItem("checking", path, async () => {
255
+ try {
256
+ await fs__default['default'].mkdirs(path);
257
+ } catch (error) {
258
+ throw new Error(`Failed to create app directory: ${error.message}`);
259
+ }
260
+ });
261
+ }
253
262
  async function createTemporaryAppFolder(tempDir) {
254
263
  await Task.forItem("creating", "temporary directory", async () => {
255
264
  try {
@@ -259,11 +268,6 @@ async function createTemporaryAppFolder(tempDir) {
259
268
  }
260
269
  });
261
270
  }
262
- async function cleanUp(tempDir) {
263
- await Task.forItem("remove", "temporary directory", async () => {
264
- await fs__default['default'].remove(tempDir);
265
- });
266
- }
267
271
  async function buildApp(appDir) {
268
272
  const runCmd = async (cmd) => {
269
273
  await Task.forItem("executing", cmd, async () => {
@@ -282,6 +286,8 @@ async function moveApp(tempDir, destination, id) {
282
286
  await Task.forItem("moving", id, async () => {
283
287
  await fs__default['default'].move(tempDir, destination).catch((error) => {
284
288
  throw new Error(`Failed to move app from ${tempDir} to ${destination}: ${error.message}`);
289
+ }).finally(() => {
290
+ fs__default['default'].removeSync(tempDir);
285
291
  });
286
292
  });
287
293
  }
@@ -313,18 +319,25 @@ var createApp = async (cmd) => {
313
319
  answers.dbTypeSqlite = answers.dbType === "SQLite";
314
320
  const templateDir = paths.resolveOwn("templates/default-app");
315
321
  const tempDir = path.resolve(os__default['default'].tmpdir(), answers.name);
316
- const appDir = path.resolve(paths.targetDir, answers.name);
322
+ const appDir = cmd.path ? path.resolve(paths.targetDir, cmd.path) : path.resolve(paths.targetDir, answers.name);
317
323
  Task.log();
318
324
  Task.log("Creating the app...");
319
325
  try {
320
- Task.section("Checking if the directory is available");
321
- await checkExists(paths.targetDir, answers.name);
322
- Task.section("Creating a temporary app directory");
323
- await createTemporaryAppFolder(tempDir);
324
- Task.section("Preparing files");
325
- await templatingTask(templateDir, tempDir, answers);
326
- Task.section("Moving to final location");
327
- await moveApp(tempDir, appDir, answers.name);
326
+ if (cmd.path) {
327
+ Task.section("Checking that supplied path exists");
328
+ await checkPathExists(appDir);
329
+ Task.section("Preparing files");
330
+ await templatingTask(templateDir, cmd.path, answers);
331
+ } else {
332
+ Task.section("Checking if the directory is available");
333
+ await checkAppExists(paths.targetDir, answers.name);
334
+ Task.section("Creating a temporary app directory");
335
+ await createTemporaryAppFolder(tempDir);
336
+ Task.section("Preparing files");
337
+ await templatingTask(templateDir, tempDir, answers);
338
+ Task.section("Moving to final location");
339
+ await moveApp(tempDir, appDir, answers.name);
340
+ }
328
341
  if (!cmd.skipInstall) {
329
342
  Task.section("Building the app");
330
343
  await buildApp(appDir);
@@ -341,17 +354,13 @@ var createApp = async (cmd) => {
341
354
  } catch (error) {
342
355
  Task.error(String(error));
343
356
  Task.log("It seems that something went wrong when creating the app \u{1F914}");
344
- Task.log("We are going to clean up, and then you can try again.");
345
- Task.section("Cleanup");
346
- await cleanUp(tempDir);
347
357
  Task.error("\u{1F525} Failed to create app!");
348
358
  Task.exit(1);
349
359
  }
350
360
  };
351
361
 
352
362
  const main = (argv) => {
353
- program__default['default'].name("backstage-create-app").version(version$z);
354
- program__default['default'].description("Creates a new app in a new directory").option("--skip-install", "Skip the install and builds steps after creating the app").action(createApp);
363
+ program__default['default'].name("backstage-create-app").version(version$z).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").action(createApp);
355
364
  program__default['default'].parse(argv);
356
365
  };
357
366
  process.on("unhandledRejection", (rejection) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/lib/errors.ts","../src/lib/versions.ts","../src/lib/tasks.ts","../src/createApp.ts","../src/index.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport chalk from 'chalk';\n\nexport class CustomError extends Error {\n get name(): string {\n return this.constructor.name;\n }\n}\n\nexport class ExitCodeError extends CustomError {\n readonly code: number;\n\n constructor(code: number, command?: string) {\n if (command) {\n super(`Command '${command}' exited with code ${code}`);\n } else {\n super(`Child exited with code ${code}`);\n }\n this.code = code;\n }\n}\n\nexport function exitWithError(error: Error): never {\n if (error instanceof ExitCodeError) {\n process.stderr.write(`\\n${chalk.red(error.message)}\\n\\n`);\n process.exit(error.code);\n } else {\n process.stderr.write(`\\n${chalk.red(`${error}`)}\\n\\n`);\n process.exit(1);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* eslint-disable monorepo/no-relative-import */\n\n/*\nThis is a list of all packages used by the template. If dependencies are added or removed,\nthis list should be updated as well.\n\nThe list, and the accompanying peerDependencies entries, are here to ensure correct versioning\nand bumping of this package. Without this list the version would not be bumped unless we\nmanually trigger a release.\n\nThis does not create an actual dependency on these packages and does not bring in any code.\nRelative imports are used rather than package imports to make sure the packages aren't externalized.\nRollup will extract the value of the version field in each package at build time without\nleaving any imports in place.\n*/\n\nimport { version as backendCommon } from '../../../backend-common/package.json';\nimport { version as catalogClient } from '../../../catalog-client/package.json';\nimport { version as catalogModel } from '../../../catalog-model/package.json';\nimport { version as cli } from '../../../cli/package.json';\nimport { version as config } from '../../../config/package.json';\nimport { version as coreAppApi } from '../../../core-app-api/package.json';\nimport { version as coreComponents } from '../../../core-components/package.json';\nimport { version as corePluginApi } from '../../../core-plugin-api/package.json';\nimport { version as errors } from '../../../errors/package.json';\nimport { version as integrationReact } from '../../../integration-react/package.json';\nimport { version as testUtils } from '../../../test-utils/package.json';\nimport { version as theme } from '../../../theme/package.json';\n\nimport { version as pluginApiDocs } from '../../../../plugins/api-docs/package.json';\nimport { version as pluginAppBackend } from '../../../../plugins/app-backend/package.json';\nimport { version as pluginAuthBackend } from '../../../../plugins/auth-backend/package.json';\nimport { version as pluginCatalog } from '../../../../plugins/catalog/package.json';\nimport { version as pluginCatalogReact } from '../../../../plugins/catalog-react/package.json';\nimport { version as pluginCatalogBackend } from '../../../../plugins/catalog-backend/package.json';\nimport { version as pluginCatalogImport } from '../../../../plugins/catalog-import/package.json';\nimport { version as pluginCircleci } from '../../../../plugins/circleci/package.json';\nimport { version as pluginExplore } from '../../../../plugins/explore/package.json';\nimport { version as pluginGithubActions } from '../../../../plugins/github-actions/package.json';\nimport { version as pluginLighthouse } from '../../../../plugins/lighthouse/package.json';\nimport { version as pluginOrg } from '../../../../plugins/org/package.json';\nimport { version as pluginProxyBackend } from '../../../../plugins/proxy-backend/package.json';\nimport { version as pluginRollbarBackend } from '../../../../plugins/rollbar-backend/package.json';\nimport { version as pluginScaffolder } from '../../../../plugins/scaffolder/package.json';\nimport { version as pluginScaffolderBackend } from '../../../../plugins/scaffolder-backend/package.json';\nimport { version as pluginSearch } from '../../../../plugins/search/package.json';\nimport { version as pluginSearchBackend } from '../../../../plugins/search-backend/package.json';\nimport { version as pluginSearchBackendNode } from '../../../../plugins/search-backend-node/package.json';\nimport { version as pluginTechRadar } from '../../../../plugins/tech-radar/package.json';\nimport { version as pluginTechdocs } from '../../../../plugins/techdocs/package.json';\nimport { version as pluginTechdocsBackend } from '../../../../plugins/techdocs-backend/package.json';\nimport { version as pluginUserSettings } from '../../../../plugins/user-settings/package.json';\n\nexport const packageVersions = {\n '@backstage/backend-common': backendCommon,\n '@backstage/catalog-client': catalogClient,\n '@backstage/catalog-model': catalogModel,\n '@backstage/cli': cli,\n '@backstage/config': config,\n '@backstage/core-app-api': coreAppApi,\n '@backstage/core-components': coreComponents,\n '@backstage/core-plugin-api': corePluginApi,\n '@backstage/errors': errors,\n '@backstage/integration-react': integrationReact,\n '@backstage/plugin-api-docs': pluginApiDocs,\n '@backstage/plugin-app-backend': pluginAppBackend,\n '@backstage/plugin-auth-backend': pluginAuthBackend,\n '@backstage/plugin-catalog': pluginCatalog,\n '@backstage/plugin-catalog-react': pluginCatalogReact,\n '@backstage/plugin-catalog-backend': pluginCatalogBackend,\n '@backstage/plugin-catalog-import': pluginCatalogImport,\n '@backstage/plugin-circleci': pluginCircleci,\n '@backstage/plugin-explore': pluginExplore,\n '@backstage/plugin-github-actions': pluginGithubActions,\n '@backstage/plugin-lighthouse': pluginLighthouse,\n '@backstage/plugin-org': pluginOrg,\n '@backstage/plugin-proxy-backend': pluginProxyBackend,\n '@backstage/plugin-rollbar-backend': pluginRollbarBackend,\n '@backstage/plugin-scaffolder': pluginScaffolder,\n '@backstage/plugin-scaffolder-backend': pluginScaffolderBackend,\n '@backstage/plugin-search': pluginSearch,\n '@backstage/plugin-search-backend': pluginSearchBackend,\n '@backstage/plugin-search-backend-node': pluginSearchBackendNode,\n '@backstage/plugin-tech-radar': pluginTechRadar,\n '@backstage/plugin-techdocs': pluginTechdocs,\n '@backstage/plugin-techdocs-backend': pluginTechdocsBackend,\n '@backstage/plugin-user-settings': pluginUserSettings,\n '@backstage/test-utils': testUtils,\n '@backstage/theme': theme,\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport chalk from 'chalk';\nimport fs from 'fs-extra';\nimport handlebars from 'handlebars';\nimport ora from 'ora';\nimport { basename, dirname } from 'path';\nimport recursive from 'recursive-readdir';\nimport { packageVersions } from './versions';\n\nconst TASK_NAME_MAX_LENGTH = 14;\n\nexport class Task {\n static log(name: string = '') {\n process.stdout.write(`${chalk.green(name)}\\n`);\n }\n\n static error(message: string = '') {\n process.stdout.write(`\\n${chalk.red(message)}\\n\\n`);\n }\n\n static section(name: string) {\n const title = chalk.green(`${name}:`);\n process.stdout.write(`\\n ${title}\\n`);\n }\n\n static exit(code: number = 0) {\n process.exit(code);\n }\n\n static async forItem(\n task: string,\n item: string,\n taskFunc: () => Promise<void>,\n ): Promise<void> {\n const paddedTask = chalk.green(task.padEnd(TASK_NAME_MAX_LENGTH));\n\n const spinner = ora({\n prefixText: chalk.green(` ${paddedTask}${chalk.cyan(item)}`),\n spinner: 'arc',\n color: 'green',\n }).start();\n\n try {\n await taskFunc();\n spinner.succeed();\n } catch (error) {\n spinner.fail();\n throw error;\n }\n }\n}\n\nexport async function templatingTask(\n templateDir: string,\n destinationDir: string,\n context: any,\n) {\n const files = await recursive(templateDir).catch(error => {\n throw new Error(`Failed to read template directory: ${error.message}`);\n });\n\n for (const file of files) {\n const destinationFile = file.replace(templateDir, destinationDir);\n await fs.ensureDir(dirname(destinationFile));\n\n if (file.endsWith('.hbs')) {\n await Task.forItem('templating', basename(file), async () => {\n const destination = destinationFile.replace(/\\.hbs$/, '');\n\n const template = await fs.readFile(file);\n const compiled = handlebars.compile(template.toString());\n const contents = compiled(\n { name: basename(destination), ...context },\n {\n helpers: {\n version(name: keyof typeof packageVersions) {\n if (name in packageVersions) {\n return packageVersions[name];\n }\n throw new Error(`No version available for package ${name}`);\n },\n },\n },\n );\n\n await fs.writeFile(destination, contents).catch(error => {\n throw new Error(\n `Failed to create file: ${destination}: ${error.message}`,\n );\n });\n });\n } else {\n await Task.forItem('copying', basename(file), async () => {\n await fs.copyFile(file, destinationFile).catch(error => {\n const destination = destinationFile;\n throw new Error(\n `Failed to copy file to ${destination} : ${error.message}`,\n );\n });\n });\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { promisify } from 'util';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport inquirer, { Answers, Question } from 'inquirer';\nimport { exec as execCb } from 'child_process';\nimport { resolve as resolvePath } from 'path';\nimport { findPaths } from '@backstage/cli-common';\nimport os from 'os';\nimport { Task, templatingTask } from './lib/tasks';\n\nconst exec = promisify(execCb);\n\nasync function checkExists(rootDir: string, name: string) {\n await Task.forItem('checking', name, async () => {\n const destination = resolvePath(rootDir, name);\n\n if (await fs.pathExists(destination)) {\n const existing = chalk.cyan(destination.replace(`${rootDir}/`, ''));\n throw new Error(\n `A directory with the same name already exists: ${existing}\\nPlease try again with a different app name`,\n );\n }\n });\n}\n\nasync function createTemporaryAppFolder(tempDir: string) {\n await Task.forItem('creating', 'temporary directory', async () => {\n try {\n await fs.mkdir(tempDir);\n } catch (error) {\n throw new Error(`Failed to create temporary app directory, ${error}`);\n }\n });\n}\n\nasync function cleanUp(tempDir: string) {\n await Task.forItem('remove', 'temporary directory', async () => {\n await fs.remove(tempDir);\n });\n}\n\nasync function buildApp(appDir: string) {\n const runCmd = async (cmd: string) => {\n await Task.forItem('executing', cmd, async () => {\n process.chdir(appDir);\n\n await exec(cmd).catch(error => {\n process.stdout.write(error.stderr);\n process.stdout.write(error.stdout);\n throw new Error(`Could not execute command ${chalk.cyan(cmd)}`);\n });\n });\n };\n\n await runCmd('yarn install');\n await runCmd('yarn tsc');\n}\n\nasync function moveApp(tempDir: string, destination: string, id: string) {\n await Task.forItem('moving', id, async () => {\n await fs.move(tempDir, destination).catch(error => {\n throw new Error(\n `Failed to move app from ${tempDir} to ${destination}: ${error.message}`,\n );\n });\n });\n}\n\nexport default async (cmd: Command): Promise<void> => {\n /* eslint-disable-next-line no-restricted-syntax */\n const paths = findPaths(__dirname);\n\n const questions: Question[] = [\n {\n type: 'input',\n name: 'name',\n message: chalk.blue('Enter a name for the app [required]'),\n validate: (value: any) => {\n if (!value) {\n return chalk.red('Please enter a name for the app');\n } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {\n return chalk.red(\n 'App name must be lowercase and contain only letters, digits, and dashes.',\n );\n }\n return true;\n },\n },\n {\n type: 'list',\n name: 'dbType',\n message: chalk.blue('Select database for the backend [required]'),\n // @ts-ignore\n choices: ['SQLite', 'PostgreSQL'],\n },\n ];\n const answers: Answers = await inquirer.prompt(questions);\n answers.dbTypePG = answers.dbType === 'PostgreSQL';\n answers.dbTypeSqlite = answers.dbType === 'SQLite';\n\n const templateDir = paths.resolveOwn('templates/default-app');\n const tempDir = resolvePath(os.tmpdir(), answers.name);\n const appDir = resolvePath(paths.targetDir, answers.name);\n\n Task.log();\n Task.log('Creating the app...');\n\n try {\n Task.section('Checking if the directory is available');\n await checkExists(paths.targetDir, answers.name);\n\n Task.section('Creating a temporary app directory');\n await createTemporaryAppFolder(tempDir);\n\n Task.section('Preparing files');\n await templatingTask(templateDir, tempDir, answers);\n\n Task.section('Moving to final location');\n await moveApp(tempDir, appDir, answers.name);\n\n if (!cmd.skipInstall) {\n Task.section('Building the app');\n await buildApp(appDir);\n }\n\n Task.log();\n Task.log(\n chalk.green(`🥇 Successfully created ${chalk.cyan(answers.name)}`),\n );\n Task.log();\n Task.section('All set! Now you might want to');\n Task.log(` Run the app: ${chalk.cyan(`cd ${answers.name} && yarn dev`)}`);\n Task.log(\n ' Set up the software catalog: https://backstage.io/docs/features/software-catalog/configuration',\n );\n Task.log(' Add authentication: https://backstage.io/docs/auth/');\n Task.log();\n Task.exit();\n } catch (error) {\n Task.error(String(error));\n\n Task.log('It seems that something went wrong when creating the app 🤔');\n Task.log('We are going to clean up, and then you can try again.');\n\n Task.section('Cleanup');\n await cleanUp(tempDir);\n Task.error('🔥 Failed to create app!');\n Task.exit(1);\n }\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A CLI that helps you create your own Backstage app\n *\n * @packageDocumentation\n */\n\nimport program from 'commander';\nimport { exitWithError } from './lib/errors';\nimport { version } from '../package.json';\nimport createApp from './createApp';\n\nconst main = (argv: string[]) => {\n program.name('backstage-create-app').version(version);\n\n program\n .description('Creates a new app in a new directory')\n .option(\n '--skip-install',\n 'Skip the install and builds steps after creating the app',\n )\n .action(createApp);\n\n program.parse(argv);\n};\n\nprocess.on('unhandledRejection', rejection => {\n if (rejection instanceof Error) {\n exitWithError(rejection);\n } else {\n exitWithError(new Error(`Unknown rejection: '${rejection}'`));\n }\n});\n\nmain(process.argv);\n"],"names":["chalk","backendCommon","catalogClient","catalogModel","cli","config","coreAppApi","coreComponents","corePluginApi","errors","integrationReact","pluginApiDocs","pluginAppBackend","pluginAuthBackend","pluginCatalog","pluginCatalogReact","pluginCatalogBackend","pluginCatalogImport","pluginCircleci","pluginExplore","pluginGithubActions","pluginLighthouse","pluginOrg","pluginProxyBackend","pluginRollbarBackend","pluginScaffolder","pluginScaffolderBackend","pluginSearch","pluginSearchBackend","pluginSearchBackendNode","pluginTechRadar","pluginTechdocs","pluginTechdocsBackend","pluginUserSettings","testUtils","theme","ora","recursive","fs","dirname","basename","handlebars","promisify","execCb","resolvePath","findPaths","inquirer","os","version"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/lib/errors.ts","../src/lib/versions.ts","../src/lib/tasks.ts","../src/createApp.ts","../src/index.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport chalk from 'chalk';\n\nexport class CustomError extends Error {\n get name(): string {\n return this.constructor.name;\n }\n}\n\nexport class ExitCodeError extends CustomError {\n readonly code: number;\n\n constructor(code: number, command?: string) {\n if (command) {\n super(`Command '${command}' exited with code ${code}`);\n } else {\n super(`Child exited with code ${code}`);\n }\n this.code = code;\n }\n}\n\nexport function exitWithError(error: Error): never {\n if (error instanceof ExitCodeError) {\n process.stderr.write(`\\n${chalk.red(error.message)}\\n\\n`);\n process.exit(error.code);\n } else {\n process.stderr.write(`\\n${chalk.red(`${error}`)}\\n\\n`);\n process.exit(1);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* eslint-disable monorepo/no-relative-import */\n\n/*\nThis is a list of all packages used by the template. If dependencies are added or removed,\nthis list should be updated as well.\n\nThe list, and the accompanying peerDependencies entries, are here to ensure correct versioning\nand bumping of this package. Without this list the version would not be bumped unless we\nmanually trigger a release.\n\nThis does not create an actual dependency on these packages and does not bring in any code.\nRelative imports are used rather than package imports to make sure the packages aren't externalized.\nRollup will extract the value of the version field in each package at build time without\nleaving any imports in place.\n*/\n\nimport { version as backendCommon } from '../../../backend-common/package.json';\nimport { version as catalogClient } from '../../../catalog-client/package.json';\nimport { version as catalogModel } from '../../../catalog-model/package.json';\nimport { version as cli } from '../../../cli/package.json';\nimport { version as config } from '../../../config/package.json';\nimport { version as coreAppApi } from '../../../core-app-api/package.json';\nimport { version as coreComponents } from '../../../core-components/package.json';\nimport { version as corePluginApi } from '../../../core-plugin-api/package.json';\nimport { version as errors } from '../../../errors/package.json';\nimport { version as integrationReact } from '../../../integration-react/package.json';\nimport { version as testUtils } from '../../../test-utils/package.json';\nimport { version as theme } from '../../../theme/package.json';\n\nimport { version as pluginApiDocs } from '../../../../plugins/api-docs/package.json';\nimport { version as pluginAppBackend } from '../../../../plugins/app-backend/package.json';\nimport { version as pluginAuthBackend } from '../../../../plugins/auth-backend/package.json';\nimport { version as pluginCatalog } from '../../../../plugins/catalog/package.json';\nimport { version as pluginCatalogReact } from '../../../../plugins/catalog-react/package.json';\nimport { version as pluginCatalogBackend } from '../../../../plugins/catalog-backend/package.json';\nimport { version as pluginCatalogImport } from '../../../../plugins/catalog-import/package.json';\nimport { version as pluginCircleci } from '../../../../plugins/circleci/package.json';\nimport { version as pluginExplore } from '../../../../plugins/explore/package.json';\nimport { version as pluginGithubActions } from '../../../../plugins/github-actions/package.json';\nimport { version as pluginLighthouse } from '../../../../plugins/lighthouse/package.json';\nimport { version as pluginOrg } from '../../../../plugins/org/package.json';\nimport { version as pluginProxyBackend } from '../../../../plugins/proxy-backend/package.json';\nimport { version as pluginRollbarBackend } from '../../../../plugins/rollbar-backend/package.json';\nimport { version as pluginScaffolder } from '../../../../plugins/scaffolder/package.json';\nimport { version as pluginScaffolderBackend } from '../../../../plugins/scaffolder-backend/package.json';\nimport { version as pluginSearch } from '../../../../plugins/search/package.json';\nimport { version as pluginSearchBackend } from '../../../../plugins/search-backend/package.json';\nimport { version as pluginSearchBackendNode } from '../../../../plugins/search-backend-node/package.json';\nimport { version as pluginTechRadar } from '../../../../plugins/tech-radar/package.json';\nimport { version as pluginTechdocs } from '../../../../plugins/techdocs/package.json';\nimport { version as pluginTechdocsBackend } from '../../../../plugins/techdocs-backend/package.json';\nimport { version as pluginUserSettings } from '../../../../plugins/user-settings/package.json';\n\nexport const packageVersions = {\n '@backstage/backend-common': backendCommon,\n '@backstage/catalog-client': catalogClient,\n '@backstage/catalog-model': catalogModel,\n '@backstage/cli': cli,\n '@backstage/config': config,\n '@backstage/core-app-api': coreAppApi,\n '@backstage/core-components': coreComponents,\n '@backstage/core-plugin-api': corePluginApi,\n '@backstage/errors': errors,\n '@backstage/integration-react': integrationReact,\n '@backstage/plugin-api-docs': pluginApiDocs,\n '@backstage/plugin-app-backend': pluginAppBackend,\n '@backstage/plugin-auth-backend': pluginAuthBackend,\n '@backstage/plugin-catalog': pluginCatalog,\n '@backstage/plugin-catalog-react': pluginCatalogReact,\n '@backstage/plugin-catalog-backend': pluginCatalogBackend,\n '@backstage/plugin-catalog-import': pluginCatalogImport,\n '@backstage/plugin-circleci': pluginCircleci,\n '@backstage/plugin-explore': pluginExplore,\n '@backstage/plugin-github-actions': pluginGithubActions,\n '@backstage/plugin-lighthouse': pluginLighthouse,\n '@backstage/plugin-org': pluginOrg,\n '@backstage/plugin-proxy-backend': pluginProxyBackend,\n '@backstage/plugin-rollbar-backend': pluginRollbarBackend,\n '@backstage/plugin-scaffolder': pluginScaffolder,\n '@backstage/plugin-scaffolder-backend': pluginScaffolderBackend,\n '@backstage/plugin-search': pluginSearch,\n '@backstage/plugin-search-backend': pluginSearchBackend,\n '@backstage/plugin-search-backend-node': pluginSearchBackendNode,\n '@backstage/plugin-tech-radar': pluginTechRadar,\n '@backstage/plugin-techdocs': pluginTechdocs,\n '@backstage/plugin-techdocs-backend': pluginTechdocsBackend,\n '@backstage/plugin-user-settings': pluginUserSettings,\n '@backstage/test-utils': testUtils,\n '@backstage/theme': theme,\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport chalk from 'chalk';\nimport fs from 'fs-extra';\nimport handlebars from 'handlebars';\nimport ora from 'ora';\nimport { basename, dirname } from 'path';\nimport recursive from 'recursive-readdir';\nimport { packageVersions } from './versions';\n\nconst TASK_NAME_MAX_LENGTH = 14;\n\nexport class Task {\n static log(name: string = '') {\n process.stdout.write(`${chalk.green(name)}\\n`);\n }\n\n static error(message: string = '') {\n process.stdout.write(`\\n${chalk.red(message)}\\n\\n`);\n }\n\n static section(name: string) {\n const title = chalk.green(`${name}:`);\n process.stdout.write(`\\n ${title}\\n`);\n }\n\n static exit(code: number = 0) {\n process.exit(code);\n }\n\n static async forItem(\n task: string,\n item: string,\n taskFunc: () => Promise<void>,\n ): Promise<void> {\n const paddedTask = chalk.green(task.padEnd(TASK_NAME_MAX_LENGTH));\n\n const spinner = ora({\n prefixText: chalk.green(` ${paddedTask}${chalk.cyan(item)}`),\n spinner: 'arc',\n color: 'green',\n }).start();\n\n try {\n await taskFunc();\n spinner.succeed();\n } catch (error) {\n spinner.fail();\n throw error;\n }\n }\n}\n\nexport async function templatingTask(\n templateDir: string,\n destinationDir: string,\n context: any,\n) {\n const files = await recursive(templateDir).catch(error => {\n throw new Error(`Failed to read template directory: ${error.message}`);\n });\n\n for (const file of files) {\n const destinationFile = file.replace(templateDir, destinationDir);\n await fs.ensureDir(dirname(destinationFile));\n\n if (file.endsWith('.hbs')) {\n await Task.forItem('templating', basename(file), async () => {\n const destination = destinationFile.replace(/\\.hbs$/, '');\n\n const template = await fs.readFile(file);\n const compiled = handlebars.compile(template.toString());\n const contents = compiled(\n { name: basename(destination), ...context },\n {\n helpers: {\n version(name: keyof typeof packageVersions) {\n if (name in packageVersions) {\n return packageVersions[name];\n }\n throw new Error(`No version available for package ${name}`);\n },\n },\n },\n );\n\n await fs.writeFile(destination, contents).catch(error => {\n throw new Error(\n `Failed to create file: ${destination}: ${error.message}`,\n );\n });\n });\n } else {\n await Task.forItem('copying', basename(file), async () => {\n await fs.copyFile(file, destinationFile).catch(error => {\n const destination = destinationFile;\n throw new Error(\n `Failed to copy file to ${destination} : ${error.message}`,\n );\n });\n });\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { promisify } from 'util';\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport inquirer, { Answers, Question } from 'inquirer';\nimport { exec as execCb } from 'child_process';\nimport { resolve as resolvePath } from 'path';\nimport { findPaths } from '@backstage/cli-common';\nimport os from 'os';\nimport { Task, templatingTask } from './lib/tasks';\n\nconst exec = promisify(execCb);\n\nasync function checkAppExists(rootDir: string, name: string) {\n await Task.forItem('checking', name, async () => {\n const destination = resolvePath(rootDir, name);\n\n if (await fs.pathExists(destination)) {\n const existing = chalk.cyan(destination.replace(`${rootDir}/`, ''));\n throw new Error(\n `A directory with the same name already exists: ${existing}\\nPlease try again with a different app name`,\n );\n }\n });\n}\n\nasync function checkPathExists(path: string) {\n await Task.forItem('checking', path, async () => {\n try {\n await fs.mkdirs(path);\n } catch (error) {\n // will fail if a file already exists at given `path`\n throw new Error(`Failed to create app directory: ${error.message}`);\n }\n });\n}\n\nasync function createTemporaryAppFolder(tempDir: string) {\n await Task.forItem('creating', 'temporary directory', async () => {\n try {\n await fs.mkdir(tempDir);\n } catch (error) {\n throw new Error(`Failed to create temporary app directory, ${error}`);\n }\n });\n}\n\nasync function buildApp(appDir: string) {\n const runCmd = async (cmd: string) => {\n await Task.forItem('executing', cmd, async () => {\n process.chdir(appDir);\n\n await exec(cmd).catch(error => {\n process.stdout.write(error.stderr);\n process.stdout.write(error.stdout);\n throw new Error(`Could not execute command ${chalk.cyan(cmd)}`);\n });\n });\n };\n\n await runCmd('yarn install');\n await runCmd('yarn tsc');\n}\n\nasync function moveApp(tempDir: string, destination: string, id: string) {\n await Task.forItem('moving', id, async () => {\n await fs\n .move(tempDir, destination)\n .catch(error => {\n throw new Error(\n `Failed to move app from ${tempDir} to ${destination}: ${error.message}`,\n );\n })\n .finally(() => {\n // remove temporary files on both success and failure\n fs.removeSync(tempDir);\n });\n });\n}\n\nexport default async (cmd: Command): Promise<void> => {\n /* eslint-disable-next-line no-restricted-syntax */\n const paths = findPaths(__dirname);\n\n const questions: Question[] = [\n {\n type: 'input',\n name: 'name',\n message: chalk.blue('Enter a name for the app [required]'),\n validate: (value: any) => {\n if (!value) {\n return chalk.red('Please enter a name for the app');\n } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {\n return chalk.red(\n 'App name must be lowercase and contain only letters, digits, and dashes.',\n );\n }\n return true;\n },\n },\n {\n type: 'list',\n name: 'dbType',\n message: chalk.blue('Select database for the backend [required]'),\n // @ts-ignore\n choices: ['SQLite', 'PostgreSQL'],\n },\n ];\n const answers: Answers = await inquirer.prompt(questions);\n answers.dbTypePG = answers.dbType === 'PostgreSQL';\n answers.dbTypeSqlite = answers.dbType === 'SQLite';\n\n const templateDir = paths.resolveOwn('templates/default-app');\n const tempDir = resolvePath(os.tmpdir(), answers.name);\n\n // Use `--path` argument as applicaiton directory when specified, otherwise\n // create a directory using `answers.name`\n const appDir = cmd.path\n ? resolvePath(paths.targetDir, cmd.path)\n : resolvePath(paths.targetDir, answers.name);\n\n Task.log();\n Task.log('Creating the app...');\n\n try {\n if (cmd.path) {\n // Template directly to specified path\n\n Task.section('Checking that supplied path exists');\n await checkPathExists(appDir);\n\n Task.section('Preparing files');\n await templatingTask(templateDir, cmd.path, answers);\n } else {\n // Template to temporary location, and then move files\n\n Task.section('Checking if the directory is available');\n await checkAppExists(paths.targetDir, answers.name);\n\n Task.section('Creating a temporary app directory');\n await createTemporaryAppFolder(tempDir);\n\n Task.section('Preparing files');\n await templatingTask(templateDir, tempDir, answers);\n\n Task.section('Moving to final location');\n await moveApp(tempDir, appDir, answers.name);\n }\n\n if (!cmd.skipInstall) {\n Task.section('Building the app');\n await buildApp(appDir);\n }\n\n Task.log();\n Task.log(\n chalk.green(`🥇 Successfully created ${chalk.cyan(answers.name)}`),\n );\n Task.log();\n Task.section('All set! Now you might want to');\n Task.log(` Run the app: ${chalk.cyan(`cd ${answers.name} && yarn dev`)}`);\n Task.log(\n ' Set up the software catalog: https://backstage.io/docs/features/software-catalog/configuration',\n );\n Task.log(' Add authentication: https://backstage.io/docs/auth/');\n Task.log();\n Task.exit();\n } catch (error) {\n Task.error(String(error));\n\n Task.log('It seems that something went wrong when creating the app 🤔');\n\n Task.error('🔥 Failed to create app!');\n Task.exit(1);\n }\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A CLI that helps you create your own Backstage app\n *\n * @packageDocumentation\n */\n\nimport program from 'commander';\nimport { exitWithError } from './lib/errors';\nimport { version } from '../package.json';\nimport createApp from './createApp';\n\nconst main = (argv: string[]) => {\n program\n .name('backstage-create-app')\n .version(version)\n .description('Creates a new app in a new directory or specified path')\n .option(\n '--path [directory]',\n 'Location to store the app defaulting to a new folder with the app name',\n )\n .option(\n '--skip-install',\n 'Skip the install and builds steps after creating the app',\n )\n .action(createApp);\n\n program.parse(argv);\n};\n\nprocess.on('unhandledRejection', rejection => {\n if (rejection instanceof Error) {\n exitWithError(rejection);\n } else {\n exitWithError(new Error(`Unknown rejection: '${rejection}'`));\n }\n});\n\nmain(process.argv);\n"],"names":["chalk","backendCommon","catalogClient","catalogModel","cli","config","coreAppApi","coreComponents","corePluginApi","errors","integrationReact","pluginApiDocs","pluginAppBackend","pluginAuthBackend","pluginCatalog","pluginCatalogReact","pluginCatalogBackend","pluginCatalogImport","pluginCircleci","pluginExplore","pluginGithubActions","pluginLighthouse","pluginOrg","pluginProxyBackend","pluginRollbarBackend","pluginScaffolder","pluginScaffolderBackend","pluginSearch","pluginSearchBackend","pluginSearchBackendNode","pluginTechRadar","pluginTechdocs","pluginTechdocsBackend","pluginUserSettings","testUtils","theme","ora","recursive","fs","dirname","basename","handlebars","promisify","execCb","resolvePath","findPaths","inquirer","os","version"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/create-app",
3
3
  "description": "A CLI that helps you create your own Backstage app",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "private": false,
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -27,7 +27,7 @@
27
27
  "start": "nodemon --"
28
28
  },
29
29
  "dependencies": {
30
- "@backstage/cli-common": "^0.1.4",
30
+ "@backstage/cli-common": "^0.1.5",
31
31
  "chalk": "^4.0.0",
32
32
  "commander": "^6.1.0",
33
33
  "fs-extra": "9.1.0",
@@ -86,5 +86,5 @@
86
86
  "dist",
87
87
  "templates"
88
88
  ],
89
- "gitHead": "017a47e585642733ac3b4b294cd00fc517d3ba08"
89
+ "gitHead": "3db0cb3683d3000666802af90a465ba4fb0d1e8d"
90
90
  }