@backstage/create-app 0.4.4 → 0.4.8
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 +150 -0
- package/README.md +1 -1
- package/dist/index.cjs.js +66 -66
- package/dist/index.cjs.js.map +1 -1
- package/package.json +6 -37
- package/templates/default-app/app-config.production.yaml +3 -3
- package/templates/default-app/app-config.yaml.hbs +11 -6
- package/templates/default-app/package.json.hbs +2 -2
- package/templates/default-app/packages/app/package.json.hbs +3 -3
- package/templates/default-app/packages/app/src/App.test.tsx +2 -2
- package/templates/default-app/packages/app/src/components/Root/Root.tsx +7 -2
- package/templates/default-app/packages/app/src/components/search/SearchPage.tsx +15 -0
- package/templates/default-app/packages/backend/README.md +1 -1
- package/templates/default-app/packages/backend/package.json.hbs +1 -1
- package/templates/default-app/packages/backend/src/index.ts +3 -1
- package/templates/default-app/packages/backend/src/plugins/search.ts +17 -2
- package/templates/default-app/packages/backend/src/plugins/techdocs.ts +2 -0
- package/templates/default-app/packages/backend/src/types.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,155 @@
|
|
|
1
1
|
# @backstage/create-app
|
|
2
2
|
|
|
3
|
+
## 0.4.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 25dfc2d483: Updated the root `package.json` to include files with `.cjs` and `.mjs` extensions in the `"lint-staged"` configuration.
|
|
8
|
+
|
|
9
|
+
To make this change to an existing app, apply the following changes to the `package.json` file:
|
|
10
|
+
|
|
11
|
+
```diff
|
|
12
|
+
"lint-staged": {
|
|
13
|
+
- "*.{js,jsx,ts,tsx}": [
|
|
14
|
+
+ "*.{js,jsx,ts,tsx,mjs,cjs}": [
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 0.4.7
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 9603827bb5: Addressed some peer dependency warnings
|
|
22
|
+
- 1bada775a9: TechDocs Backend may now (optionally) leverage a cache store to improve
|
|
23
|
+
performance when reading content from a cloud storage provider.
|
|
24
|
+
|
|
25
|
+
To apply this change to an existing app, pass the cache manager from the plugin
|
|
26
|
+
environment to the `createRouter` function in your backend:
|
|
27
|
+
|
|
28
|
+
```diff
|
|
29
|
+
// packages/backend/src/plugins/techdocs.ts
|
|
30
|
+
|
|
31
|
+
export default async function createPlugin({
|
|
32
|
+
logger,
|
|
33
|
+
config,
|
|
34
|
+
discovery,
|
|
35
|
+
reader,
|
|
36
|
+
+ cache,
|
|
37
|
+
}: PluginEnvironment): Promise<Router> {
|
|
38
|
+
|
|
39
|
+
// ...
|
|
40
|
+
|
|
41
|
+
return await createRouter({
|
|
42
|
+
preparers,
|
|
43
|
+
generators,
|
|
44
|
+
publisher,
|
|
45
|
+
logger,
|
|
46
|
+
config,
|
|
47
|
+
discovery,
|
|
48
|
+
+ cache,
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If your `PluginEnvironment` does not include a cache manager, be sure you've
|
|
53
|
+
applied [the cache management change][cm-change] to your backend as well.
|
|
54
|
+
|
|
55
|
+
[Additional configuration][td-rec-arch] is required if you wish to enable
|
|
56
|
+
caching in TechDocs.
|
|
57
|
+
|
|
58
|
+
[cm-change]: https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md#patch-changes-6
|
|
59
|
+
[td-rec-arch]: https://backstage.io/docs/features/techdocs/architecture#recommended-deployment
|
|
60
|
+
|
|
61
|
+
- 4862fbc64f: Bump @spotify/prettier-config
|
|
62
|
+
- 36bb4fb2e9: Removed the `scaffolder.github.visibility` configuration that is no longer used from the default app template.
|
|
63
|
+
|
|
64
|
+
## 0.4.6
|
|
65
|
+
|
|
66
|
+
### Patch Changes
|
|
67
|
+
|
|
68
|
+
- 24d2ce03f3: Search Modal now relies on the Search Context to access state and state setter. If you use the SidebarSearchModal as described in the [getting started documentation](https://backstage.io/docs/features/search/getting-started#using-the-search-modal), make sure to update your code with the SearchContextProvider.
|
|
69
|
+
|
|
70
|
+
```diff
|
|
71
|
+
export const Root = ({ children }: PropsWithChildren<{}>) => (
|
|
72
|
+
<SidebarPage>
|
|
73
|
+
<Sidebar>
|
|
74
|
+
<SidebarLogo />
|
|
75
|
+
- <SidebarSearchModal />
|
|
76
|
+
+ <SearchContextProvider>
|
|
77
|
+
+ <SidebarSearchModal />
|
|
78
|
+
+ </SearchContextProvider>
|
|
79
|
+
<SidebarDivider />
|
|
80
|
+
...
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- 905dd952ac: Incorporate usage of the tokenManager into the backend created using `create-app`.
|
|
84
|
+
|
|
85
|
+
In existing backends, update the `PluginEnvironment` to include a `tokenManager`:
|
|
86
|
+
|
|
87
|
+
```diff
|
|
88
|
+
// packages/backend/src/types.ts
|
|
89
|
+
|
|
90
|
+
...
|
|
91
|
+
import {
|
|
92
|
+
...
|
|
93
|
+
+ TokenManager,
|
|
94
|
+
} from '@backstage/backend-common';
|
|
95
|
+
|
|
96
|
+
export type PluginEnvironment = {
|
|
97
|
+
...
|
|
98
|
+
+ tokenManager: TokenManager;
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Then, create a `ServerTokenManager`. This can either be a `noop` that requires no secret and validates all requests by default, or one that uses a secret from your `app-config.yaml` to generate and validate tokens.
|
|
103
|
+
|
|
104
|
+
```diff
|
|
105
|
+
// packages/backend/src/index.ts
|
|
106
|
+
|
|
107
|
+
...
|
|
108
|
+
import {
|
|
109
|
+
...
|
|
110
|
+
+ ServerTokenManager,
|
|
111
|
+
} from '@backstage/backend-common';
|
|
112
|
+
...
|
|
113
|
+
|
|
114
|
+
function makeCreateEnv(config: Config) {
|
|
115
|
+
...
|
|
116
|
+
// CHOOSE ONE
|
|
117
|
+
// TokenManager not requiring a secret
|
|
118
|
+
+ const tokenManager = ServerTokenManager.noop();
|
|
119
|
+
// OR TokenManager requiring a secret
|
|
120
|
+
+ const tokenManager = ServerTokenManager.fromConfig(config);
|
|
121
|
+
|
|
122
|
+
...
|
|
123
|
+
return (plugin: string): PluginEnvironment => {
|
|
124
|
+
...
|
|
125
|
+
- return { logger, cache, database, config, reader, discovery };
|
|
126
|
+
+ return { logger, cache, database, config, reader, discovery, tokenManager };
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 0.4.5
|
|
132
|
+
|
|
133
|
+
### Patch Changes
|
|
134
|
+
|
|
135
|
+
- dcaeaac174: Cleaned out the `peerDependencies` in the published version of the package, making it much quicker to run `npx @backstage/create-app` as it no longer needs to install a long list of unnecessary.
|
|
136
|
+
- a5a5d7e1f1: DefaultTechDocsCollator is now included in the search backend, and the Search Page updated with the SearchType component that includes the techdocs type
|
|
137
|
+
- bab752e2b3: Change default port of backend from 7000 to 7007.
|
|
138
|
+
|
|
139
|
+
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
|
|
140
|
+
|
|
141
|
+
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
backend:
|
|
145
|
+
listen: 0.0.0.0:7123
|
|
146
|
+
baseUrl: http://localhost:7123
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
More information can be found here: https://backstage.io/docs/conf/writing
|
|
150
|
+
|
|
151
|
+
- 42ebbc18c0: Bump gitbeaker to the latest version
|
|
152
|
+
|
|
3
153
|
## 0.4.4
|
|
4
154
|
|
|
5
155
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -22,4 +22,4 @@ yarn backstage-create-app
|
|
|
22
22
|
## Documentation
|
|
23
23
|
|
|
24
24
|
- [Backstage Readme](https://github.com/backstage/backstage/blob/master/README.md)
|
|
25
|
-
- [Backstage Documentation](https://
|
|
25
|
+
- [Backstage Documentation](https://backstage.io/docs/)
|
package/dist/index.cjs.js
CHANGED
|
@@ -42,92 +42,92 @@ class ExitCodeError extends CustomError {
|
|
|
42
42
|
function exitWithError(error) {
|
|
43
43
|
if (error instanceof ExitCodeError) {
|
|
44
44
|
process.stderr.write(`
|
|
45
|
-
${chalk__default[
|
|
45
|
+
${chalk__default["default"].red(error.message)}
|
|
46
46
|
|
|
47
47
|
`);
|
|
48
48
|
process.exit(error.code);
|
|
49
49
|
} else {
|
|
50
50
|
process.stderr.write(`
|
|
51
|
-
${chalk__default[
|
|
51
|
+
${chalk__default["default"].red(`${error}`)}
|
|
52
52
|
|
|
53
53
|
`);
|
|
54
54
|
process.exit(1);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
var version$A = "0.4.
|
|
58
|
+
var version$A = "0.4.8";
|
|
59
59
|
|
|
60
|
-
var version$z = "0.1.
|
|
60
|
+
var version$z = "0.1.2";
|
|
61
61
|
|
|
62
|
-
var version$y = "0.9.
|
|
62
|
+
var version$y = "0.9.14";
|
|
63
63
|
|
|
64
64
|
var version$x = "0.5.2";
|
|
65
65
|
|
|
66
|
-
var version$w = "0.9.
|
|
66
|
+
var version$w = "0.9.8";
|
|
67
67
|
|
|
68
|
-
var version$v = "0.
|
|
68
|
+
var version$v = "0.10.2";
|
|
69
69
|
|
|
70
70
|
var version$u = "0.1.11";
|
|
71
71
|
|
|
72
|
-
var version$t = "0.1
|
|
72
|
+
var version$t = "0.2.1";
|
|
73
73
|
|
|
74
|
-
var version$s = "0.
|
|
74
|
+
var version$s = "0.8.1";
|
|
75
75
|
|
|
76
|
-
var version$r = "0.
|
|
76
|
+
var version$r = "0.3.1";
|
|
77
77
|
|
|
78
|
-
var version$q = "0.1.
|
|
78
|
+
var version$q = "0.1.5";
|
|
79
79
|
|
|
80
|
-
var version$p = "0.1.
|
|
80
|
+
var version$p = "0.1.15";
|
|
81
81
|
|
|
82
|
-
var version$o = "0.1.
|
|
82
|
+
var version$o = "0.1.24";
|
|
83
83
|
|
|
84
|
-
var version$n = "0.2.
|
|
84
|
+
var version$n = "0.2.14";
|
|
85
85
|
|
|
86
|
-
var version$m = "0.6.
|
|
86
|
+
var version$m = "0.6.18";
|
|
87
87
|
|
|
88
88
|
var version$l = "0.3.19";
|
|
89
89
|
|
|
90
|
-
var version$k = "0.
|
|
90
|
+
var version$k = "0.5.1";
|
|
91
91
|
|
|
92
|
-
var version$j = "0.7.
|
|
92
|
+
var version$j = "0.7.4";
|
|
93
93
|
|
|
94
|
-
var version$i = "0.6.
|
|
94
|
+
var version$i = "0.6.7";
|
|
95
95
|
|
|
96
|
-
var version$h = "0.
|
|
96
|
+
var version$h = "0.19.2";
|
|
97
97
|
|
|
98
|
-
var version$g = "0.7.
|
|
98
|
+
var version$g = "0.7.5";
|
|
99
99
|
|
|
100
|
-
var version$f = "0.2.
|
|
100
|
+
var version$f = "0.2.31";
|
|
101
101
|
|
|
102
|
-
var version$e = "0.3.
|
|
102
|
+
var version$e = "0.3.22";
|
|
103
103
|
|
|
104
|
-
var version$d = "0.4.
|
|
104
|
+
var version$d = "0.4.27";
|
|
105
105
|
|
|
106
|
-
var version$c = "0.2.
|
|
106
|
+
var version$c = "0.2.31";
|
|
107
107
|
|
|
108
|
-
var version$b = "0.3.
|
|
108
|
+
var version$b = "0.3.31";
|
|
109
109
|
|
|
110
|
-
var version$a = "0.2.
|
|
110
|
+
var version$a = "0.2.14";
|
|
111
111
|
|
|
112
|
-
var version$9 = "0.1.
|
|
112
|
+
var version$9 = "0.1.16";
|
|
113
113
|
|
|
114
|
-
var version$8 = "0.11.
|
|
114
|
+
var version$8 = "0.11.14";
|
|
115
115
|
|
|
116
|
-
var version$7 = "0.15.
|
|
116
|
+
var version$7 = "0.15.17";
|
|
117
117
|
|
|
118
|
-
var version$6 = "0.
|
|
118
|
+
var version$6 = "0.5.1";
|
|
119
119
|
|
|
120
|
-
var version$5 = "0.2.
|
|
120
|
+
var version$5 = "0.2.8";
|
|
121
121
|
|
|
122
122
|
var version$4 = "0.4.3";
|
|
123
123
|
|
|
124
|
-
var version$3 = "0.4.
|
|
124
|
+
var version$3 = "0.4.13";
|
|
125
125
|
|
|
126
|
-
var version$2 = "0.12.
|
|
126
|
+
var version$2 = "0.12.10";
|
|
127
127
|
|
|
128
|
-
var version$1 = "0.
|
|
128
|
+
var version$1 = "0.12.0";
|
|
129
129
|
|
|
130
|
-
var version = "0.3.
|
|
130
|
+
var version = "0.3.13";
|
|
131
131
|
|
|
132
132
|
const packageVersions = {
|
|
133
133
|
"@backstage/app-defaults": version$z,
|
|
@@ -172,17 +172,17 @@ const TASK_NAME_MAX_LENGTH = 14;
|
|
|
172
172
|
const exec = util.promisify(child_process.exec);
|
|
173
173
|
class Task {
|
|
174
174
|
static log(name = "") {
|
|
175
|
-
process.stdout.write(`${chalk__default[
|
|
175
|
+
process.stdout.write(`${chalk__default["default"].green(name)}
|
|
176
176
|
`);
|
|
177
177
|
}
|
|
178
178
|
static error(message = "") {
|
|
179
179
|
process.stdout.write(`
|
|
180
|
-
${chalk__default[
|
|
180
|
+
${chalk__default["default"].red(message)}
|
|
181
181
|
|
|
182
182
|
`);
|
|
183
183
|
}
|
|
184
184
|
static section(name) {
|
|
185
|
-
const title = chalk__default[
|
|
185
|
+
const title = chalk__default["default"].green(`${name}:`);
|
|
186
186
|
process.stdout.write(`
|
|
187
187
|
${title}
|
|
188
188
|
`);
|
|
@@ -191,9 +191,9 @@ ${chalk__default['default'].red(message)}
|
|
|
191
191
|
process.exit(code);
|
|
192
192
|
}
|
|
193
193
|
static async forItem(task, item, taskFunc) {
|
|
194
|
-
const paddedTask = chalk__default[
|
|
195
|
-
const spinner = ora__default[
|
|
196
|
-
prefixText: chalk__default[
|
|
194
|
+
const paddedTask = chalk__default["default"].green(task.padEnd(TASK_NAME_MAX_LENGTH));
|
|
195
|
+
const spinner = ora__default["default"]({
|
|
196
|
+
prefixText: chalk__default["default"].green(` ${paddedTask}${chalk__default["default"].cyan(item)}`),
|
|
197
197
|
spinner: "arc",
|
|
198
198
|
color: "green"
|
|
199
199
|
}).start();
|
|
@@ -207,18 +207,18 @@ ${chalk__default['default'].red(message)}
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
async function templatingTask(templateDir, destinationDir, context, version) {
|
|
210
|
-
const files = await recursive__default[
|
|
210
|
+
const files = await recursive__default["default"](templateDir).catch((error) => {
|
|
211
211
|
throw new Error(`Failed to read template directory: ${error.message}`);
|
|
212
212
|
});
|
|
213
213
|
for (const file of files) {
|
|
214
214
|
const destinationFile = path.resolve(destinationDir, path.relative(templateDir, file));
|
|
215
|
-
await fs__default[
|
|
215
|
+
await fs__default["default"].ensureDir(path.dirname(destinationFile));
|
|
216
216
|
if (file.endsWith(".hbs")) {
|
|
217
217
|
await Task.forItem("templating", path.basename(file), async () => {
|
|
218
218
|
const destination = destinationFile.replace(/\.hbs$/, "");
|
|
219
|
-
const template = await fs__default[
|
|
220
|
-
const compiled = handlebars__default[
|
|
221
|
-
const contents = compiled({name: path.basename(destination), ...context}, {
|
|
219
|
+
const template = await fs__default["default"].readFile(file);
|
|
220
|
+
const compiled = handlebars__default["default"].compile(template.toString());
|
|
221
|
+
const contents = compiled({ name: path.basename(destination), ...context }, {
|
|
222
222
|
helpers: {
|
|
223
223
|
version(name) {
|
|
224
224
|
if (name in packageVersions) {
|
|
@@ -228,20 +228,20 @@ async function templatingTask(templateDir, destinationDir, context, version) {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
});
|
|
231
|
-
await fs__default[
|
|
231
|
+
await fs__default["default"].writeFile(destination, contents).catch((error) => {
|
|
232
232
|
throw new Error(`Failed to create file: ${destination}: ${error.message}`);
|
|
233
233
|
});
|
|
234
234
|
});
|
|
235
235
|
} else {
|
|
236
236
|
await Task.forItem("copying", path.basename(file), async () => {
|
|
237
|
-
await fs__default[
|
|
237
|
+
await fs__default["default"].copyFile(file, destinationFile).catch((error) => {
|
|
238
238
|
const destination = destinationFile;
|
|
239
239
|
throw new Error(`Failed to copy file to ${destination} : ${error.message}`);
|
|
240
240
|
});
|
|
241
241
|
});
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
|
-
await Task.forItem("creating", cliCommon.BACKSTAGE_JSON, () => fs__default[
|
|
244
|
+
await Task.forItem("creating", cliCommon.BACKSTAGE_JSON, () => fs__default["default"].writeFile(path.join(destinationDir, cliCommon.BACKSTAGE_JSON), `{
|
|
245
245
|
"version": ${JSON.stringify(version)}
|
|
246
246
|
}
|
|
247
247
|
`));
|
|
@@ -249,8 +249,8 @@ async function templatingTask(templateDir, destinationDir, context, version) {
|
|
|
249
249
|
async function checkAppExistsTask(rootDir, name) {
|
|
250
250
|
await Task.forItem("checking", name, async () => {
|
|
251
251
|
const destination = path.resolve(rootDir, name);
|
|
252
|
-
if (await fs__default[
|
|
253
|
-
const existing = chalk__default[
|
|
252
|
+
if (await fs__default["default"].pathExists(destination)) {
|
|
253
|
+
const existing = chalk__default["default"].cyan(destination.replace(`${rootDir}/`, ""));
|
|
254
254
|
throw new Error(`A directory with the same name already exists: ${existing}
|
|
255
255
|
Please try again with a different app name`);
|
|
256
256
|
}
|
|
@@ -259,7 +259,7 @@ Please try again with a different app name`);
|
|
|
259
259
|
async function checkPathExistsTask(path) {
|
|
260
260
|
await Task.forItem("checking", path, async () => {
|
|
261
261
|
try {
|
|
262
|
-
await fs__default[
|
|
262
|
+
await fs__default["default"].mkdirs(path);
|
|
263
263
|
} catch (error) {
|
|
264
264
|
throw new Error(`Failed to create app directory: ${error.message}`);
|
|
265
265
|
}
|
|
@@ -268,7 +268,7 @@ async function checkPathExistsTask(path) {
|
|
|
268
268
|
async function createTemporaryAppFolderTask(tempDir) {
|
|
269
269
|
await Task.forItem("creating", "temporary directory", async () => {
|
|
270
270
|
try {
|
|
271
|
-
await fs__default[
|
|
271
|
+
await fs__default["default"].mkdir(tempDir);
|
|
272
272
|
} catch (error) {
|
|
273
273
|
throw new Error(`Failed to create temporary app directory, ${error}`);
|
|
274
274
|
}
|
|
@@ -281,7 +281,7 @@ async function buildAppTask(appDir) {
|
|
|
281
281
|
await exec(cmd).catch((error) => {
|
|
282
282
|
process.stdout.write(error.stderr);
|
|
283
283
|
process.stdout.write(error.stdout);
|
|
284
|
-
throw new Error(`Could not execute command ${chalk__default[
|
|
284
|
+
throw new Error(`Could not execute command ${chalk__default["default"].cyan(cmd)}`);
|
|
285
285
|
});
|
|
286
286
|
});
|
|
287
287
|
};
|
|
@@ -290,10 +290,10 @@ async function buildAppTask(appDir) {
|
|
|
290
290
|
}
|
|
291
291
|
async function moveAppTask(tempDir, destination, id) {
|
|
292
292
|
await Task.forItem("moving", id, async () => {
|
|
293
|
-
await fs__default[
|
|
293
|
+
await fs__default["default"].move(tempDir, destination).catch((error) => {
|
|
294
294
|
throw new Error(`Failed to move app from ${tempDir} to ${destination}: ${error.message}`);
|
|
295
295
|
}).finally(() => {
|
|
296
|
-
fs__default[
|
|
296
|
+
fs__default["default"].removeSync(tempDir);
|
|
297
297
|
});
|
|
298
298
|
});
|
|
299
299
|
}
|
|
@@ -304,12 +304,12 @@ var createApp = async (cmd, version) => {
|
|
|
304
304
|
{
|
|
305
305
|
type: "input",
|
|
306
306
|
name: "name",
|
|
307
|
-
message: chalk__default[
|
|
307
|
+
message: chalk__default["default"].blue("Enter a name for the app [required]"),
|
|
308
308
|
validate: (value) => {
|
|
309
309
|
if (!value) {
|
|
310
|
-
return chalk__default[
|
|
310
|
+
return chalk__default["default"].red("Please enter a name for the app");
|
|
311
311
|
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
|
312
|
-
return chalk__default[
|
|
312
|
+
return chalk__default["default"].red("App name must be lowercase and contain only letters, digits, and dashes.");
|
|
313
313
|
}
|
|
314
314
|
return true;
|
|
315
315
|
}
|
|
@@ -317,15 +317,15 @@ var createApp = async (cmd, version) => {
|
|
|
317
317
|
{
|
|
318
318
|
type: "list",
|
|
319
319
|
name: "dbType",
|
|
320
|
-
message: chalk__default[
|
|
320
|
+
message: chalk__default["default"].blue("Select database for the backend [required]"),
|
|
321
321
|
choices: ["SQLite", "PostgreSQL"]
|
|
322
322
|
}
|
|
323
323
|
];
|
|
324
|
-
const answers = await inquirer__default[
|
|
324
|
+
const answers = await inquirer__default["default"].prompt(questions);
|
|
325
325
|
answers.dbTypePG = answers.dbType === "PostgreSQL";
|
|
326
326
|
answers.dbTypeSqlite = answers.dbType === "SQLite";
|
|
327
327
|
const templateDir = paths.resolveOwn("templates/default-app");
|
|
328
|
-
const tempDir = path.resolve(os__default[
|
|
328
|
+
const tempDir = path.resolve(os__default["default"].tmpdir(), answers.name);
|
|
329
329
|
const appDir = cmd.path ? path.resolve(paths.targetDir, cmd.path) : path.resolve(paths.targetDir, answers.name);
|
|
330
330
|
Task.log();
|
|
331
331
|
Task.log("Creating the app...");
|
|
@@ -350,10 +350,10 @@ var createApp = async (cmd, version) => {
|
|
|
350
350
|
await buildAppTask(appDir);
|
|
351
351
|
}
|
|
352
352
|
Task.log();
|
|
353
|
-
Task.log(chalk__default[
|
|
353
|
+
Task.log(chalk__default["default"].green(`\u{1F947} Successfully created ${chalk__default["default"].cyan(answers.name)}`));
|
|
354
354
|
Task.log();
|
|
355
355
|
Task.section("All set! Now you might want to");
|
|
356
|
-
Task.log(` Run the app: ${chalk__default[
|
|
356
|
+
Task.log(` Run the app: ${chalk__default["default"].cyan(`cd ${answers.name} && yarn dev`)}`);
|
|
357
357
|
Task.log(" Set up the software catalog: https://backstage.io/docs/features/software-catalog/configuration");
|
|
358
358
|
Task.log(" Add authentication: https://backstage.io/docs/auth/");
|
|
359
359
|
Task.log();
|
|
@@ -367,8 +367,8 @@ var createApp = async (cmd, version) => {
|
|
|
367
367
|
};
|
|
368
368
|
|
|
369
369
|
const main = (argv) => {
|
|
370
|
-
program__default[
|
|
371
|
-
program__default[
|
|
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));
|
|
371
|
+
program__default["default"].parse(argv);
|
|
372
372
|
};
|
|
373
373
|
process.on("unhandledRejection", (rejection) => {
|
|
374
374
|
if (rejection instanceof Error) {
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -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 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 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 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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"}
|
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.
|
|
4
|
+
"version": "0.4.8",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"lint": "backstage-cli lint",
|
|
26
26
|
"test": "backstage-cli test",
|
|
27
27
|
"clean": "backstage-cli clean",
|
|
28
|
+
"prepack": "node scripts/prepack.js",
|
|
29
|
+
"postpack": "node scripts/postpack.js",
|
|
28
30
|
"start": "nodemon --"
|
|
29
31
|
},
|
|
30
32
|
"dependencies": {
|
|
@@ -39,45 +41,12 @@
|
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@types/fs-extra": "^9.0.1",
|
|
42
|
-
"@types/inquirer": "^
|
|
44
|
+
"@types/inquirer": "^8.1.3",
|
|
45
|
+
"@types/node": "^14.14.32",
|
|
43
46
|
"@types/recursive-readdir": "^2.2.0",
|
|
44
47
|
"mock-fs": "^5.1.1",
|
|
45
48
|
"ts-node": "^10.0.0"
|
|
46
49
|
},
|
|
47
|
-
"peerDependencies": {
|
|
48
|
-
"@backstage/backend-common": "*",
|
|
49
|
-
"@backstage/catalog-client": "*",
|
|
50
|
-
"@backstage/catalog-model": "*",
|
|
51
|
-
"@backstage/cli": "*",
|
|
52
|
-
"@backstage/config": "*",
|
|
53
|
-
"@backstage/core-app-api": "*",
|
|
54
|
-
"@backstage/core-components": "*",
|
|
55
|
-
"@backstage/core-plugin-api": "*",
|
|
56
|
-
"@backstage/errors": "*",
|
|
57
|
-
"@backstage/integration-react": "*",
|
|
58
|
-
"@backstage/plugin-api-docs": "*",
|
|
59
|
-
"@backstage/plugin-app-backend": "*",
|
|
60
|
-
"@backstage/plugin-auth-backend": "*",
|
|
61
|
-
"@backstage/plugin-catalog": "*",
|
|
62
|
-
"@backstage/plugin-catalog-backend": "*",
|
|
63
|
-
"@backstage/plugin-catalog-import": "*",
|
|
64
|
-
"@backstage/plugin-explore": "*",
|
|
65
|
-
"@backstage/plugin-github-actions": "*",
|
|
66
|
-
"@backstage/plugin-lighthouse": "*",
|
|
67
|
-
"@backstage/plugin-proxy-backend": "*",
|
|
68
|
-
"@backstage/plugin-rollbar-backend": "*",
|
|
69
|
-
"@backstage/plugin-scaffolder": "*",
|
|
70
|
-
"@backstage/plugin-scaffolder-backend": "*",
|
|
71
|
-
"@backstage/plugin-search": "*",
|
|
72
|
-
"@backstage/plugin-search-backend": "*",
|
|
73
|
-
"@backstage/plugin-search-backend-node": "*",
|
|
74
|
-
"@backstage/plugin-tech-radar": "*",
|
|
75
|
-
"@backstage/plugin-techdocs": "*",
|
|
76
|
-
"@backstage/plugin-techdocs-backend": "*",
|
|
77
|
-
"@backstage/plugin-user-settings": "*",
|
|
78
|
-
"@backstage/test-utils": "*",
|
|
79
|
-
"@backstage/theme": "*"
|
|
80
|
-
},
|
|
81
50
|
"nodemonConfig": {
|
|
82
51
|
"watch": "./src",
|
|
83
52
|
"exec": "bin/backstage-create-app",
|
|
@@ -88,5 +57,5 @@
|
|
|
88
57
|
"dist",
|
|
89
58
|
"templates"
|
|
90
59
|
],
|
|
91
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "9ff0f1e76d4510edda2f1b1b3e58cba168a76190"
|
|
92
61
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
app:
|
|
2
2
|
# Should be the same as backend.baseUrl when using the `app-backend` plugin
|
|
3
|
-
baseUrl: http://localhost:
|
|
3
|
+
baseUrl: http://localhost:7007
|
|
4
4
|
|
|
5
5
|
backend:
|
|
6
|
-
baseUrl: http://localhost:
|
|
6
|
+
baseUrl: http://localhost:7007
|
|
7
7
|
listen:
|
|
8
|
-
port:
|
|
8
|
+
port: 7007
|
|
@@ -6,9 +6,14 @@ organization:
|
|
|
6
6
|
name: My Company
|
|
7
7
|
|
|
8
8
|
backend:
|
|
9
|
-
|
|
9
|
+
# Used for enabling authentication, secret is shared by all backend plugins
|
|
10
|
+
# See backend-to-backend-auth.md in the docs for information on the format
|
|
11
|
+
# auth:
|
|
12
|
+
# keys:
|
|
13
|
+
# - secret: ${BACKEND_SECRET}
|
|
14
|
+
baseUrl: http://localhost:7007
|
|
10
15
|
listen:
|
|
11
|
-
port:
|
|
16
|
+
port: 7007
|
|
12
17
|
csp:
|
|
13
18
|
connect-src: ["'self'", 'http:', 'https:']
|
|
14
19
|
# Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference
|
|
@@ -32,7 +37,9 @@ backend:
|
|
|
32
37
|
user: ${POSTGRES_USER}
|
|
33
38
|
password: ${POSTGRES_PASSWORD}
|
|
34
39
|
# https://node-postgres.com/features/ssl
|
|
35
|
-
#
|
|
40
|
+
# you can set the sslmode configuration option via the `PGSSLMODE` environment variable
|
|
41
|
+
# see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
|
|
42
|
+
# ssl:
|
|
36
43
|
# ca: # if you have a CA file and want to verify it you can uncomment this section
|
|
37
44
|
# $file: <file-path>/ca/server.crt
|
|
38
45
|
{{/if}}
|
|
@@ -70,9 +77,7 @@ auth:
|
|
|
70
77
|
providers: {}
|
|
71
78
|
|
|
72
79
|
scaffolder:
|
|
73
|
-
|
|
74
|
-
token: ${GITHUB_TOKEN}
|
|
75
|
-
visibility: public # or 'internal' or 'private'
|
|
80
|
+
# see https://backstage.io/docs/features/software-templates/configuration for software template options
|
|
76
81
|
|
|
77
82
|
catalog:
|
|
78
83
|
rules:
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@backstage/cli": "^{{version '@backstage/cli'}}",
|
|
34
|
-
"@spotify/prettier-config": "^
|
|
34
|
+
"@spotify/prettier-config": "^12.0.0",
|
|
35
35
|
"concurrently": "^6.0.0",
|
|
36
36
|
"lerna": "^4.0.0",
|
|
37
37
|
"prettier": "^2.3.2"
|
|
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
|
],
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"@backstage/plugin-tech-radar": "^{{version '@backstage/plugin-tech-radar'}}",
|
|
23
23
|
"@backstage/plugin-techdocs": "^{{version '@backstage/plugin-techdocs'}}",
|
|
24
24
|
"@backstage/plugin-user-settings": "^{{version '@backstage/plugin-user-settings'}}",
|
|
25
|
-
"@backstage/test-utils": "^{{version '@backstage/test-utils'}}",
|
|
26
25
|
"@backstage/theme": "^{{version '@backstage/theme'}}",
|
|
27
26
|
"@material-ui/core": "^4.12.2",
|
|
28
27
|
"@material-ui/icons": "^4.9.1",
|
|
@@ -34,6 +33,7 @@
|
|
|
34
33
|
"react-use": "^15.3.3"
|
|
35
34
|
},
|
|
36
35
|
"devDependencies": {
|
|
36
|
+
"@backstage/test-utils": "^{{version '@backstage/test-utils'}}",
|
|
37
37
|
"@testing-library/jest-dom": "^5.10.1",
|
|
38
38
|
"@testing-library/react": "^10.4.1",
|
|
39
39
|
"@testing-library/user-event": "^12.0.7",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"scripts": {
|
|
49
49
|
"start": "backstage-cli app:serve",
|
|
50
50
|
"build": "backstage-cli app:build",
|
|
51
|
-
"test": "backstage-cli test",
|
|
52
|
-
"lint": "backstage-cli lint",
|
|
53
51
|
"clean": "backstage-cli clean",
|
|
52
|
+
"test": "backstage-cli test",
|
|
54
53
|
"test:e2e": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:dev",
|
|
55
54
|
"test:e2e:ci": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:run",
|
|
55
|
+
"lint": "backstage-cli lint",
|
|
56
56
|
"cy:dev": "cypress open",
|
|
57
57
|
"cy:run": "cypress run"
|
|
58
58
|
},
|
|
@@ -10,9 +10,9 @@ describe('App', () => {
|
|
|
10
10
|
{
|
|
11
11
|
data: {
|
|
12
12
|
app: { title: 'Test' },
|
|
13
|
-
backend: { baseUrl: 'http://localhost:
|
|
13
|
+
backend: { baseUrl: 'http://localhost:7007' },
|
|
14
14
|
techdocs: {
|
|
15
|
-
storageUrl: 'http://localhost:
|
|
15
|
+
storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
|
|
16
16
|
},
|
|
17
17
|
},
|
|
18
18
|
context: 'test',
|
|
@@ -25,7 +25,10 @@ import LogoFull from './LogoFull';
|
|
|
25
25
|
import LogoIcon from './LogoIcon';
|
|
26
26
|
import { NavLink } from 'react-router-dom';
|
|
27
27
|
import { Settings as SidebarSettings } from '@backstage/plugin-user-settings';
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
SidebarSearchModal,
|
|
30
|
+
SearchContextProvider,
|
|
31
|
+
} from '@backstage/plugin-search';
|
|
29
32
|
import {
|
|
30
33
|
Sidebar,
|
|
31
34
|
SidebarPage,
|
|
@@ -74,7 +77,9 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
|
|
|
74
77
|
<SidebarPage>
|
|
75
78
|
<Sidebar>
|
|
76
79
|
<SidebarLogo />
|
|
77
|
-
<
|
|
80
|
+
<SearchContextProvider>
|
|
81
|
+
<SidebarSearchModal />
|
|
82
|
+
</SearchContextProvider>
|
|
78
83
|
<SidebarDivider />
|
|
79
84
|
{/* Global nav, not org-specific */}
|
|
80
85
|
<SidebarItem icon={HomeIcon} to="catalog" text="Home" />
|
|
@@ -2,10 +2,13 @@ import React from 'react';
|
|
|
2
2
|
import { makeStyles, Theme, Grid, List, Paper } from '@material-ui/core';
|
|
3
3
|
|
|
4
4
|
import { CatalogResultListItem } from '@backstage/plugin-catalog';
|
|
5
|
+
import { DocsResultListItem } from '@backstage/plugin-techdocs';
|
|
6
|
+
|
|
5
7
|
import {
|
|
6
8
|
SearchBar,
|
|
7
9
|
SearchFilter,
|
|
8
10
|
SearchResult,
|
|
11
|
+
SearchType,
|
|
9
12
|
DefaultResultListItem,
|
|
10
13
|
} from '@backstage/plugin-search';
|
|
11
14
|
import { Content, Header, Page } from '@backstage/core-components';
|
|
@@ -39,6 +42,11 @@ const SearchPage = () => {
|
|
|
39
42
|
</Grid>
|
|
40
43
|
<Grid item xs={3}>
|
|
41
44
|
<Paper className={classes.filters}>
|
|
45
|
+
<SearchType
|
|
46
|
+
values={['techdocs', 'software-catalog']}
|
|
47
|
+
name="type"
|
|
48
|
+
defaultValue="software-catalog"
|
|
49
|
+
/>
|
|
42
50
|
<SearchFilter.Select
|
|
43
51
|
className={classes.filter}
|
|
44
52
|
name="kind"
|
|
@@ -64,6 +72,13 @@ const SearchPage = () => {
|
|
|
64
72
|
result={document}
|
|
65
73
|
/>
|
|
66
74
|
);
|
|
75
|
+
case 'techdocs':
|
|
76
|
+
return (
|
|
77
|
+
<DocsResultListItem
|
|
78
|
+
key={document.location}
|
|
79
|
+
result={document}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
67
82
|
default:
|
|
68
83
|
return (
|
|
69
84
|
<DefaultResultListItem
|
|
@@ -36,7 +36,7 @@ yarn start
|
|
|
36
36
|
Substitute `x` for actual values, or leave them as dummy values just to try out
|
|
37
37
|
the backend without using the auth or sentry features.
|
|
38
38
|
|
|
39
|
-
The backend starts up on port
|
|
39
|
+
The backend starts up on port 7007 per default.
|
|
40
40
|
|
|
41
41
|
## Populating The Catalog
|
|
42
42
|
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@backstage/plugin-search-backend": "^{{version '@backstage/plugin-search-backend'}}",
|
|
28
28
|
"@backstage/plugin-search-backend-node": "^{{version '@backstage/plugin-search-backend-node'}}",
|
|
29
29
|
"@backstage/plugin-techdocs-backend": "^{{version '@backstage/plugin-techdocs-backend'}}",
|
|
30
|
-
"@gitbeaker/node": "^
|
|
30
|
+
"@gitbeaker/node": "^34.6.0",
|
|
31
31
|
"@octokit/rest": "^18.5.3",
|
|
32
32
|
"dockerode": "^3.3.1",
|
|
33
33
|
"express": "^4.17.1",
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
DatabaseManager,
|
|
18
18
|
SingleHostDiscovery,
|
|
19
19
|
UrlReaders,
|
|
20
|
+
ServerTokenManager,
|
|
20
21
|
} from '@backstage/backend-common';
|
|
21
22
|
import { Config } from '@backstage/config';
|
|
22
23
|
import app from './plugins/app';
|
|
@@ -37,12 +38,13 @@ function makeCreateEnv(config: Config) {
|
|
|
37
38
|
|
|
38
39
|
const cacheManager = CacheManager.fromConfig(config);
|
|
39
40
|
const databaseManager = DatabaseManager.fromConfig(config);
|
|
41
|
+
const tokenManager = ServerTokenManager.noop();
|
|
40
42
|
|
|
41
43
|
return (plugin: string): PluginEnvironment => {
|
|
42
44
|
const logger = root.child({ type: 'plugin', plugin });
|
|
43
45
|
const database = databaseManager.forPlugin(plugin);
|
|
44
46
|
const cache = cacheManager.forPlugin(plugin);
|
|
45
|
-
return { logger, database, cache, config, reader, discovery };
|
|
47
|
+
return { logger, database, cache, config, reader, discovery, tokenManager };
|
|
46
48
|
};
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -6,21 +6,36 @@ import {
|
|
|
6
6
|
} from '@backstage/plugin-search-backend-node';
|
|
7
7
|
import { PluginEnvironment } from '../types';
|
|
8
8
|
import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
|
|
9
|
+
import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend';
|
|
9
10
|
|
|
10
11
|
export default async function createPlugin({
|
|
11
12
|
logger,
|
|
12
13
|
discovery,
|
|
13
14
|
config,
|
|
15
|
+
tokenManager,
|
|
14
16
|
}: PluginEnvironment) {
|
|
15
17
|
// Initialize a connection to a search engine.
|
|
16
18
|
const searchEngine = new LunrSearchEngine({ logger });
|
|
17
19
|
const indexBuilder = new IndexBuilder({ logger, searchEngine });
|
|
18
20
|
|
|
19
21
|
// Collators are responsible for gathering documents known to plugins. This
|
|
20
|
-
//
|
|
22
|
+
// collator gathers entities from the software catalog.
|
|
21
23
|
indexBuilder.addCollator({
|
|
22
24
|
defaultRefreshIntervalSeconds: 600,
|
|
23
|
-
collator: DefaultCatalogCollator.fromConfig(config, {
|
|
25
|
+
collator: DefaultCatalogCollator.fromConfig(config, {
|
|
26
|
+
discovery,
|
|
27
|
+
tokenManager,
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// collator gathers entities from techdocs.
|
|
32
|
+
indexBuilder.addCollator({
|
|
33
|
+
defaultRefreshIntervalSeconds: 600,
|
|
34
|
+
collator: DefaultTechDocsCollator.fromConfig(config, {
|
|
35
|
+
discovery,
|
|
36
|
+
logger,
|
|
37
|
+
tokenManager,
|
|
38
|
+
}),
|
|
24
39
|
});
|
|
25
40
|
|
|
26
41
|
// The scheduler controls when documents are gathered from collators and sent
|
|
@@ -14,6 +14,7 @@ export default async function createPlugin({
|
|
|
14
14
|
config,
|
|
15
15
|
discovery,
|
|
16
16
|
reader,
|
|
17
|
+
cache,
|
|
17
18
|
}: PluginEnvironment): Promise<Router> {
|
|
18
19
|
// Preparers are responsible for fetching source files for documentation.
|
|
19
20
|
const preparers = await Preparers.fromConfig(config, {
|
|
@@ -49,5 +50,6 @@ export default async function createPlugin({
|
|
|
49
50
|
logger,
|
|
50
51
|
config,
|
|
51
52
|
discovery,
|
|
53
|
+
cache,
|
|
52
54
|
});
|
|
53
55
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
PluginCacheManager,
|
|
5
5
|
PluginDatabaseManager,
|
|
6
6
|
PluginEndpointDiscovery,
|
|
7
|
+
TokenManager,
|
|
7
8
|
UrlReader,
|
|
8
9
|
} from '@backstage/backend-common';
|
|
9
10
|
|
|
@@ -14,4 +15,5 @@ export type PluginEnvironment = {
|
|
|
14
15
|
config: Config;
|
|
15
16
|
reader: UrlReader;
|
|
16
17
|
discovery: PluginEndpointDiscovery;
|
|
18
|
+
tokenManager: TokenManager;
|
|
17
19
|
};
|