@backstage/create-app 0.4.7 → 0.4.11

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,173 @@
1
1
  # @backstage/create-app
2
2
 
3
+ ## 0.4.11
4
+
5
+ ## 0.4.10
6
+
7
+ ### Patch Changes
8
+
9
+ - 79b342bd36: removed inline and internal CSS from index.html
10
+
11
+ To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file:
12
+
13
+ Remove internal style
14
+
15
+ ```diff
16
+ - <style>
17
+ - #root {
18
+ - min-height: 100%;
19
+ - }
20
+ - </style>
21
+ ```
22
+
23
+ Remove inline style from the body tag
24
+
25
+ ```diff
26
+ - <body style="margin: 0">
27
+ + <body>
28
+ ```
29
+
30
+ - d33b65dc52: Removed unused templating asset.
31
+ - 613ad12960: Add a comment to the default backend about the fallback 404 handler.
32
+ - 20af5a701f: The `<SearchType />` filter in the composed `SearchPage.tsx` was replaced with the `<SearchType.Accordion />` variant.
33
+
34
+ This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout:
35
+
36
+ ```diff
37
+ --- a/packages/app/src/components/search/SearchPage.tsx
38
+ +++ b/packages/app/src/components/search/SearchPage.tsx
39
+ @@ -11,7 +11,7 @@ import {
40
+ SearchType,
41
+ DefaultResultListItem,
42
+ } from '@backstage/plugin-search';
43
+ -import { Content, Header, Page } from '@backstage/core-components';
44
+ +import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components';
45
+
46
+ const useStyles = makeStyles((theme: Theme) => ({
47
+ bar: {
48
+ @@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({
49
+ },
50
+ filters: {
51
+ padding: theme.spacing(2),
52
+ + marginTop: theme.spacing(2),
53
+ },
54
+ filter: {
55
+ '& + &': {
56
+ @@ -41,12 +42,23 @@ const SearchPage = () => {
57
+ </Paper>
58
+ </Grid>
59
+ <Grid item xs={3}>
60
+ + <SearchType.Accordion
61
+ + name="Result Type"
62
+ + defaultValue="software-catalog"
63
+ + types={[
64
+ + {
65
+ + value: 'software-catalog',
66
+ + name: 'Software Catalog',
67
+ + icon: <CatalogIcon />,
68
+ + },
69
+ + {
70
+ + value: 'techdocs',
71
+ + name: 'Documentation',
72
+ + icon: <DocsIcon />,
73
+ + },
74
+ + ]}
75
+ + />
76
+ <Paper className={classes.filters}>
77
+ - <SearchType
78
+ - values={['techdocs', 'software-catalog']}
79
+ - name="type"
80
+ - defaultValue="software-catalog"
81
+ - />
82
+ <SearchFilter.Select
83
+ className={classes.filter}
84
+ name="kind"
85
+ ```
86
+
87
+ - 0dcd1dd64f: Add a `scheduler` to the plugin environment, which can schedule collaborative tasks across backends. To apply the same change in your backend, follow the steps below.
88
+
89
+ First install the package:
90
+
91
+ ```shell
92
+ # From the Backstage repository root
93
+ cd packages/backend
94
+ yarn add @backstage/backend-tasks
95
+ ```
96
+
97
+ Add the scheduler to your plugin environment type:
98
+
99
+ ```diff
100
+ // In packages/backend/src/types.ts
101
+ +import { PluginTaskScheduler } from '@backstage/backend-tasks';
102
+
103
+ export type PluginEnvironment = {
104
+ + scheduler: PluginTaskScheduler;
105
+ ```
106
+
107
+ And finally make sure to add such an instance to each plugin's environment:
108
+
109
+ ```diff
110
+ // In packages/backend/src/index.ts
111
+ +import { TaskScheduler } from '@backstage/backend-tasks';
112
+
113
+ function makeCreateEnv(config: Config) {
114
+ // ...
115
+ + const taskScheduler = TaskScheduler.fromConfig(config);
116
+
117
+ return (plugin: string): PluginEnvironment => {
118
+ // ...
119
+ + const scheduler = taskScheduler.forPlugin(plugin);
120
+ return {
121
+ + scheduler,
122
+ // ...
123
+ ```
124
+
125
+ ## 0.4.9
126
+
127
+ ### Patch Changes
128
+
129
+ - 49a696d720: debounceTime prop is removed from the SearchBar component in the SearchPage as the default is set to 200. The prop is safe to remove and makes it easier to stay up to date with any changes in the future.
130
+ - 5fdc8df0e8: The `index.html` template of the app has been updated to use the new `config` global provided by the Backstage CLI.
131
+
132
+ To apply this change to an existing app, make the following changes to `packages/app/public/index.html`:
133
+
134
+ ```diff
135
+ - <title><%= app.title %></title>
136
+ + <title><%= config.getString('app.title') %></title>
137
+ ```
138
+
139
+ ```diff
140
+ - <% if (app.googleAnalyticsTrackingId && typeof app.googleAnalyticsTrackingId === 'string') { %>
141
+ + <% if (config.has('app.googleAnalyticsTrackingId')) { %>
142
+ <script
143
+ async
144
+ - src="https://www.googletagmanager.com/gtag/js?id=<%= app.googleAnalyticsTrackingId %>"
145
+ + src="https://www.googletagmanager.com/gtag/js?id=<%= config.getString('app.googleAnalyticsTrackingId') %>"
146
+ ></script>
147
+ ```
148
+
149
+ ```diff
150
+ - gtag('config', '<%= app.googleAnalyticsTrackingId %>');
151
+ + gtag(
152
+ + 'config',
153
+ + '<%= config.getString("app.googleAnalyticsTrackingId") %>',
154
+ + );
155
+ ```
156
+
157
+ ## 0.4.8
158
+
159
+ ### Patch Changes
160
+
161
+ - 25dfc2d483: Updated the root `package.json` to include files with `.cjs` and `.mjs` extensions in the `"lint-staged"` configuration.
162
+
163
+ To make this change to an existing app, apply the following changes to the `package.json` file:
164
+
165
+ ```diff
166
+ "lint-staged": {
167
+ - "*.{js,jsx,ts,tsx}": [
168
+ + "*.{js,jsx,ts,tsx,mjs,cjs}": [
169
+ ```
170
+
3
171
  ## 0.4.7
4
172
 
5
173
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -55,83 +55,86 @@ ${chalk__default["default"].red(`${error}`)}
55
55
  }
56
56
  }
57
57
 
58
- var version$A = "0.4.7";
58
+ var version$B = "0.4.11";
59
59
 
60
- var version$z = "0.1.2";
60
+ var version$A = "0.1.3";
61
61
 
62
- var version$y = "0.9.13";
62
+ var version$z = "0.10.2";
63
63
 
64
- var version$x = "0.5.2";
64
+ var version$y = "0.1.2";
65
65
 
66
- var version$w = "0.9.7";
66
+ var version$x = "0.5.3";
67
67
 
68
- var version$v = "0.10.1";
68
+ var version$w = "0.9.8";
69
+
70
+ var version$v = "0.10.5";
69
71
 
70
72
  var version$u = "0.1.11";
71
73
 
72
- var version$t = "0.2.0";
74
+ var version$t = "0.3.1";
73
75
 
74
- var version$s = "0.8.0";
76
+ var version$s = "0.8.3";
75
77
 
76
- var version$r = "0.3.0";
78
+ var version$r = "0.4.1";
77
79
 
78
80
  var version$q = "0.1.5";
79
81
 
80
- var version$p = "0.1.15";
82
+ var version$p = "0.1.17";
81
83
 
82
- var version$o = "0.1.24";
84
+ var version$o = "0.2.1";
83
85
 
84
86
  var version$n = "0.2.14";
85
87
 
86
- var version$m = "0.6.18";
88
+ var version$m = "0.6.21";
87
89
 
88
- var version$l = "0.3.19";
90
+ var version$l = "0.3.21";
89
91
 
90
- var version$k = "0.5.0";
92
+ var version$k = "0.6.1";
91
93
 
92
- var version$j = "0.7.4";
94
+ var version$j = "0.7.7";
93
95
 
94
- var version$i = "0.6.5";
96
+ var version$i = "0.6.10";
95
97
 
96
- var version$h = "0.19.1";
98
+ var version$h = "0.19.4";
97
99
 
98
- var version$g = "0.7.5";
100
+ var version$g = "0.7.8";
99
101
 
100
- var version$f = "0.2.31";
102
+ var version$f = "0.2.33";
101
103
 
102
- var version$e = "0.3.22";
104
+ var version$e = "0.3.24";
103
105
 
104
- var version$d = "0.4.26";
106
+ var version$d = "0.4.30";
105
107
 
106
- var version$c = "0.2.31";
108
+ var version$c = "0.2.33";
107
109
 
108
- var version$b = "0.3.30";
110
+ var version$b = "0.3.33";
109
111
 
110
- var version$a = "0.2.14";
112
+ var version$a = "0.2.15";
111
113
 
112
- var version$9 = "0.1.16";
114
+ var version$9 = "0.1.18";
113
115
 
114
- var version$8 = "0.11.14";
116
+ var version$8 = "0.11.17";
115
117
 
116
- var version$7 = "0.15.16";
118
+ var version$7 = "0.15.19";
117
119
 
118
- var version$6 = "0.5.1";
120
+ var version$6 = "0.5.4";
119
121
 
120
- var version$5 = "0.2.8";
122
+ var version$5 = "0.3.0";
121
123
 
122
124
  var version$4 = "0.4.3";
123
125
 
124
- var version$3 = "0.4.13";
126
+ var version$3 = "0.5.1";
125
127
 
126
- var version$2 = "0.12.9";
128
+ var version$2 = "0.12.13";
127
129
 
128
- var version$1 = "0.12.0";
130
+ var version$1 = "0.12.2";
129
131
 
130
- var version = "0.3.13";
132
+ var version = "0.3.15";
131
133
 
132
134
  const packageVersions = {
133
- "@backstage/app-defaults": version$z,
134
- "@backstage/backend-common": version$y,
135
+ "@backstage/app-defaults": version$A,
136
+ "@backstage/backend-common": version$z,
137
+ "@backstage/backend-tasks": version$y,
135
138
  "@backstage/catalog-client": version$x,
136
139
  "@backstage/catalog-model": version$w,
137
140
  "@backstage/cli": version$v,
@@ -367,7 +370,7 @@ var createApp = async (cmd, version) => {
367
370
  };
368
371
 
369
372
  const main = (argv) => {
370
- program__default["default"].name("backstage-create-app").version(version$A).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((cmd) => createApp(cmd, version$A));
373
+ program__default["default"].name("backstage-create-app").version(version$B).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((cmd) => createApp(cmd, version$B));
371
374
  program__default["default"].parse(argv);
372
375
  };
373
376
  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 appDefaults } from '../../../app-defaults/package.json';\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/app-defaults': appDefaults,\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 { BACKSTAGE_JSON } from '@backstage/cli-common';\nimport chalk from 'chalk';\nimport fs from 'fs-extra';\nimport handlebars from 'handlebars';\nimport ora from 'ora';\nimport recursive from 'recursive-readdir';\nimport {\n basename,\n dirname,\n join,\n resolve as resolvePath,\n relative as relativePath,\n} from 'path';\nimport { exec as execCb } from 'child_process';\nimport { packageVersions } from './versions';\nimport { promisify } from 'util';\n\nconst TASK_NAME_MAX_LENGTH = 14;\nconst exec = promisify(execCb);\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\n/**\n * Generate a templated backstage project\n *\n * @param templateDir - location containing template files\n * @param destinationDir - location to save templated project\n * @param context - template parameters\n */\nexport async function templatingTask(\n templateDir: string,\n destinationDir: string,\n context: any,\n version: string,\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 = resolvePath(\n destinationDir,\n relativePath(templateDir, file),\n );\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 await Task.forItem('creating', BACKSTAGE_JSON, () =>\n fs.writeFile(\n join(destinationDir, BACKSTAGE_JSON),\n `{\\n \"version\": ${JSON.stringify(version)}\\n}\\n`,\n ),\n );\n}\n\n/**\n * Verify that application target does not already exist\n *\n * @param rootDir - The directory to create application folder `name`\n * @param name - The specified name of the application\n * @Throws Error - If directory with name of `destination` already exists\n */\nexport async function checkAppExistsTask(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\n/**\n * Verify that application `path` exists, otherwise create the directory\n *\n * @param {string} path - target to create directory\n * @throws {Error} if `path` is a file, or `fs.mkdir` fails\n */\nexport async function checkPathExistsTask(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\n/**\n * Create a folder to store templated files\n *\n * @param {string} tempDir - target temporary directory\n * @throws {Error} if `fs.mkdir` fails\n */\nexport async function createTemporaryAppFolderTask(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\n/**\n * Run `yarn install` and `run tsc` in application directory\n *\n * @param {string} appDir - location of application to build\n */\nexport async function buildAppTask(appDir: string) {\n const runCmd = async (cmd: string) => {\n await Task.forItem('executing', cmd, async () => {\n process.chdir(appDir);\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\n/**\n * Move temporary directory to destination application folder\n *\n * @param {string} tempDir source path to copy files from\n * @param {string} destination target path to copy files\n * @param {string} id\n * @throws {Error} if `fs.move` fails\n */\nexport async function moveAppTask(\n tempDir: string,\n destination: string,\n id: string,\n) {\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","/*\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 { Command } from 'commander';\nimport inquirer, { Answers, Question } from 'inquirer';\nimport { resolve as resolvePath } from 'path';\nimport { findPaths } from '@backstage/cli-common';\nimport os from 'os';\nimport {\n Task,\n buildAppTask,\n checkAppExistsTask,\n checkPathExistsTask,\n createTemporaryAppFolderTask,\n moveAppTask,\n templatingTask,\n} from './lib/tasks';\n\nexport default async (cmd: Command, version: string): 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 application 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 checkPathExistsTask(appDir);\n\n Task.section('Preparing files');\n await templatingTask(templateDir, cmd.path, answers, version);\n } else {\n // Template to temporary location, and then move files\n\n Task.section('Checking if the directory is available');\n await checkAppExistsTask(paths.targetDir, answers.name);\n\n Task.section('Creating a temporary app directory');\n await createTemporaryAppFolderTask(tempDir);\n\n Task.section('Preparing files');\n await templatingTask(templateDir, tempDir, answers, version);\n\n Task.section('Moving to final location');\n await moveAppTask(tempDir, appDir, answers.name);\n }\n\n if (!cmd.skipInstall) {\n Task.section('Building the app');\n await buildAppTask(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(cmd => createApp(cmd, version));\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","appDefaults","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","promisify","execCb","ora","recursive","resolvePath","relativePath","fs","dirname","basename","handlebars","BACKSTAGE_JSON","join","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 appDefaults } from '../../../app-defaults/package.json';\nimport { version as backendCommon } from '../../../backend-common/package.json';\nimport { version as backendTasks } from '../../../backend-tasks/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/app-defaults': appDefaults,\n '@backstage/backend-common': backendCommon,\n '@backstage/backend-tasks': backendTasks,\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 { BACKSTAGE_JSON } from '@backstage/cli-common';\nimport chalk from 'chalk';\nimport fs from 'fs-extra';\nimport handlebars from 'handlebars';\nimport ora from 'ora';\nimport recursive from 'recursive-readdir';\nimport {\n basename,\n dirname,\n join,\n resolve as resolvePath,\n relative as relativePath,\n} from 'path';\nimport { exec as execCb } from 'child_process';\nimport { packageVersions } from './versions';\nimport { promisify } from 'util';\n\nconst TASK_NAME_MAX_LENGTH = 14;\nconst exec = promisify(execCb);\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\n/**\n * Generate a templated backstage project\n *\n * @param templateDir - location containing template files\n * @param destinationDir - location to save templated project\n * @param context - template parameters\n */\nexport async function templatingTask(\n templateDir: string,\n destinationDir: string,\n context: any,\n version: string,\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 = resolvePath(\n destinationDir,\n relativePath(templateDir, file),\n );\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 await Task.forItem('creating', BACKSTAGE_JSON, () =>\n fs.writeFile(\n join(destinationDir, BACKSTAGE_JSON),\n `{\\n \"version\": ${JSON.stringify(version)}\\n}\\n`,\n ),\n );\n}\n\n/**\n * Verify that application target does not already exist\n *\n * @param rootDir - The directory to create application folder `name`\n * @param name - The specified name of the application\n * @Throws Error - If directory with name of `destination` already exists\n */\nexport async function checkAppExistsTask(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\n/**\n * Verify that application `path` exists, otherwise create the directory\n *\n * @param {string} path - target to create directory\n * @throws {Error} if `path` is a file, or `fs.mkdir` fails\n */\nexport async function checkPathExistsTask(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\n/**\n * Create a folder to store templated files\n *\n * @param {string} tempDir - target temporary directory\n * @throws {Error} if `fs.mkdir` fails\n */\nexport async function createTemporaryAppFolderTask(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\n/**\n * Run `yarn install` and `run tsc` in application directory\n *\n * @param {string} appDir - location of application to build\n */\nexport async function buildAppTask(appDir: string) {\n const runCmd = async (cmd: string) => {\n await Task.forItem('executing', cmd, async () => {\n process.chdir(appDir);\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\n/**\n * Move temporary directory to destination application folder\n *\n * @param {string} tempDir source path to copy files from\n * @param {string} destination target path to copy files\n * @param {string} id\n * @throws {Error} if `fs.move` fails\n */\nexport async function moveAppTask(\n tempDir: string,\n destination: string,\n id: string,\n) {\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","/*\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 { Command } from 'commander';\nimport inquirer, { Answers, Question } from 'inquirer';\nimport { resolve as resolvePath } from 'path';\nimport { findPaths } from '@backstage/cli-common';\nimport os from 'os';\nimport {\n Task,\n buildAppTask,\n checkAppExistsTask,\n checkPathExistsTask,\n createTemporaryAppFolderTask,\n moveAppTask,\n templatingTask,\n} from './lib/tasks';\n\nexport default async (cmd: Command, version: string): 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 application 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 checkPathExistsTask(appDir);\n\n Task.section('Preparing files');\n await templatingTask(templateDir, cmd.path, answers, version);\n } else {\n // Template to temporary location, and then move files\n\n Task.section('Checking if the directory is available');\n await checkAppExistsTask(paths.targetDir, answers.name);\n\n Task.section('Creating a temporary app directory');\n await createTemporaryAppFolderTask(tempDir);\n\n Task.section('Preparing files');\n await templatingTask(templateDir, tempDir, answers, version);\n\n Task.section('Moving to final location');\n await moveAppTask(tempDir, appDir, answers.name);\n }\n\n if (!cmd.skipInstall) {\n Task.section('Building the app');\n await buildAppTask(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(cmd => createApp(cmd, version));\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","appDefaults","backendCommon","backendTasks","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","promisify","execCb","ora","recursive","resolvePath","relativePath","fs","dirname","basename","handlebars","BACKSTAGE_JSON","join","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.7",
4
+ "version": "0.4.11",
5
5
  "private": false,
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/fs-extra": "^9.0.1",
44
- "@types/inquirer": "^7.3.1",
44
+ "@types/inquirer": "^8.1.3",
45
45
  "@types/node": "^14.14.32",
46
46
  "@types/recursive-readdir": "^2.2.0",
47
47
  "mock-fs": "^5.1.1",
@@ -57,5 +57,5 @@
57
57
  "dist",
58
58
  "templates"
59
59
  ],
60
- "gitHead": "562be0b43016294e27af3ad024191bb86b13b1c1"
60
+ "gitHead": "ffdb98aa2973366d48ff1774a7f892bc0c926e7e"
61
61
  }
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "prettier": "@spotify/prettier-config",
40
40
  "lint-staged": {
41
- "*.{js,jsx,ts,tsx}": [
41
+ "*.{js,jsx,ts,tsx,mjs,cjs}": [
42
42
  "eslint --fix",
43
43
  "prettier --write"
44
44
  ],
@@ -42,17 +42,11 @@
42
42
  href="<%= publicPath %>/safari-pinned-tab.svg"
43
43
  color="#5bbad5"
44
44
  />
45
- <style>
46
- #root {
47
- min-height: 100%;
48
- }
49
- </style>
50
- <title><%= app.title %></title>
51
- <% if (app.googleAnalyticsTrackingId && typeof app.googleAnalyticsTrackingId
52
- === 'string') { %>
45
+ <title><%= config.getString('app.title') %></title>
46
+ <% if (config.has('app.googleAnalyticsTrackingId')) { %>
53
47
  <script
54
48
  async
55
- src="https://www.googletagmanager.com/gtag/js?id=<%= app.googleAnalyticsTrackingId %>"
49
+ src="https://www.googletagmanager.com/gtag/js?id=<%= config.getString('app.googleAnalyticsTrackingId') %>"
56
50
  ></script>
57
51
  <script>
58
52
  window.dataLayer = window.dataLayer || [];
@@ -61,11 +55,14 @@
61
55
  }
62
56
  gtag('js', new Date());
63
57
 
64
- gtag('config', '<%= app.googleAnalyticsTrackingId %>');
58
+ gtag(
59
+ 'config',
60
+ '<%= config.getString("app.googleAnalyticsTrackingId") %>',
61
+ );
65
62
  </script>
66
63
  <% } %>
67
64
  </head>
68
- <body style="margin: 0">
65
+ <body>
69
66
  <noscript>You need to enable JavaScript to run this app.</noscript>
70
67
  <div id="root"></div>
71
68
  <!--
@@ -11,7 +11,13 @@ import {
11
11
  SearchType,
12
12
  DefaultResultListItem,
13
13
  } from '@backstage/plugin-search';
14
- import { Content, Header, Page } from '@backstage/core-components';
14
+ import {
15
+ CatalogIcon,
16
+ Content,
17
+ DocsIcon,
18
+ Header,
19
+ Page,
20
+ } from '@backstage/core-components';
15
21
 
16
22
  const useStyles = makeStyles((theme: Theme) => ({
17
23
  bar: {
@@ -19,6 +25,7 @@ const useStyles = makeStyles((theme: Theme) => ({
19
25
  },
20
26
  filters: {
21
27
  padding: theme.spacing(2),
28
+ marginTop: theme.spacing(2),
22
29
  },
23
30
  filter: {
24
31
  '& + &': {
@@ -37,16 +44,27 @@ const SearchPage = () => {
37
44
  <Grid container direction="row">
38
45
  <Grid item xs={12}>
39
46
  <Paper className={classes.bar}>
40
- <SearchBar debounceTime={100} />
47
+ <SearchBar />
41
48
  </Paper>
42
49
  </Grid>
43
50
  <Grid item xs={3}>
51
+ <SearchType.Accordion
52
+ name="Result Type"
53
+ defaultValue="software-catalog"
54
+ types={[
55
+ {
56
+ value: 'software-catalog',
57
+ name: 'Software Catalog',
58
+ icon: <CatalogIcon />,
59
+ },
60
+ {
61
+ value: 'techdocs',
62
+ name: 'Documentation',
63
+ icon: <DocsIcon />,
64
+ },
65
+ ]}
66
+ />
44
67
  <Paper className={classes.filters}>
45
- <SearchType
46
- values={['techdocs', 'software-catalog']}
47
- name="type"
48
- defaultValue="software-catalog"
49
- />
50
68
  <SearchFilter.Select
51
69
  className={classes.filter}
52
70
  name="kind"
@@ -16,6 +16,7 @@
16
16
  "dependencies": {
17
17
  "app": "0.0.0",
18
18
  "@backstage/backend-common": "^{{version '@backstage/backend-common'}}",
19
+ "@backstage/backend-tasks": "^{{version '@backstage/backend-tasks'}}",
19
20
  "@backstage/catalog-model": "^{{version '@backstage/catalog-model'}}",
20
21
  "@backstage/catalog-client": "^{{version '@backstage/catalog-client'}}",
21
22
  "@backstage/config": "^{{version '@backstage/config'}}",
@@ -19,6 +19,7 @@ import {
19
19
  UrlReaders,
20
20
  ServerTokenManager,
21
21
  } from '@backstage/backend-common';
22
+ import { TaskScheduler } from '@backstage/backend-tasks';
22
23
  import { Config } from '@backstage/config';
23
24
  import app from './plugins/app';
24
25
  import auth from './plugins/auth';
@@ -33,18 +34,28 @@ function makeCreateEnv(config: Config) {
33
34
  const root = getRootLogger();
34
35
  const reader = UrlReaders.default({ logger: root, config });
35
36
  const discovery = SingleHostDiscovery.fromConfig(config);
36
-
37
- root.info(`Created UrlReader ${reader}`);
38
-
39
37
  const cacheManager = CacheManager.fromConfig(config);
40
38
  const databaseManager = DatabaseManager.fromConfig(config);
41
39
  const tokenManager = ServerTokenManager.noop();
40
+ const taskScheduler = TaskScheduler.fromConfig(config);
41
+
42
+ root.info(`Created UrlReader ${reader}`);
42
43
 
43
44
  return (plugin: string): PluginEnvironment => {
44
45
  const logger = root.child({ type: 'plugin', plugin });
45
46
  const database = databaseManager.forPlugin(plugin);
46
47
  const cache = cacheManager.forPlugin(plugin);
47
- return { logger, database, cache, config, reader, discovery, tokenManager };
48
+ const scheduler = taskScheduler.forPlugin(plugin);
49
+ return {
50
+ logger,
51
+ database,
52
+ cache,
53
+ config,
54
+ reader,
55
+ discovery,
56
+ tokenManager,
57
+ scheduler,
58
+ };
48
59
  };
49
60
  }
50
61
 
@@ -70,6 +81,8 @@ async function main() {
70
81
  apiRouter.use('/techdocs', await techdocs(techdocsEnv));
71
82
  apiRouter.use('/proxy', await proxy(proxyEnv));
72
83
  apiRouter.use('/search', await search(searchEnv));
84
+
85
+ // Add backends ABOVE this line; this 404 handler is the catch-all fallback
73
86
  apiRouter.use(notFoundHandler());
74
87
 
75
88
  const service = createServiceBuilder(module)
@@ -7,6 +7,7 @@ import {
7
7
  TokenManager,
8
8
  UrlReader,
9
9
  } from '@backstage/backend-common';
10
+ import { PluginTaskScheduler } from '@backstage/backend-tasks';
10
11
 
11
12
  export type PluginEnvironment = {
12
13
  logger: Logger;
@@ -16,4 +17,5 @@ export type PluginEnvironment = {
16
17
  reader: UrlReader;
17
18
  discovery: PluginEndpointDiscovery;
18
19
  tokenManager: TokenManager;
20
+ scheduler: PluginTaskScheduler;
19
21
  };
@@ -1,27 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <meta name="theme-color" content="#000000" />
7
- <meta
8
- name="description"
9
- content="Backstage is an open platform for building developer portals"
10
- />
11
- <title>Backstage</title>
12
- </head>
13
- <body style="margin: 0">
14
- <noscript>You need to enable JavaScript to run this app.</noscript>
15
- <div id="root"></div>
16
- <!--
17
- This HTML file is a template.
18
- If you open it directly in the browser, you will see an empty page.
19
-
20
- You can add webfonts, meta tags, or analytics to this file.
21
- The build step will place the bundled scripts into the <body> tag.
22
-
23
- To begin the development, run `npm start` or `yarn start`.
24
- To create a production bundle, use `npm run build` or `yarn build`.
25
- -->
26
- </body>
27
- </html>