@backstage/cli 0.28.0-next.1 → 0.28.0-next.2
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 +25 -0
- package/config/jest.js +9 -1
- package/config/jestCacheResultProcessor.cjs +23 -0
- package/config/jestSwcTransform.js +4 -1
- package/dist/commands/build/buildBackend.cjs.js +65 -0
- package/dist/commands/build/buildFrontend.cjs.js +56 -0
- package/dist/commands/build/command.cjs.js +72 -0
- package/dist/commands/build/index.cjs.js +8 -0
- package/dist/commands/buildWorkspace.cjs.js +24 -0
- package/dist/commands/clean/clean.cjs.js +19 -0
- package/dist/{cjs/docs-BGyA6jwW.cjs.js → commands/config/docs.cjs.js} +4 -12
- package/dist/{cjs/print-Dd6aChXU.cjs.js → commands/config/print.cjs.js} +4 -12
- package/dist/{cjs/schema-D93FRhBL.cjs.js → commands/config/schema.cjs.js} +4 -12
- package/dist/commands/config/validate.cjs.js +19 -0
- package/dist/{cjs/index-j193pV_Y.cjs.js → commands/create-github-app/GithubCreateAppServer.cjs.js} +2 -110
- package/dist/commands/create-github-app/index.cjs.js +117 -0
- package/dist/commands/index.cjs.js +231 -0
- package/dist/{cjs/info-DuAv1Tsx.cjs.js → commands/info.cjs.js} +13 -17
- package/dist/{cjs/lint-BwiDJkjE.cjs.js → commands/lint.cjs.js} +10 -10
- package/dist/commands/migrate/packageExports.cjs.js +17 -0
- package/dist/{cjs/packageLintConfigs-DeUGBP17.cjs.js → commands/migrate/packageLintConfigs.cjs.js} +2 -10
- package/dist/{cjs/packageRole-Iuv9NRii.cjs.js → commands/migrate/packageRole.cjs.js} +5 -8
- package/dist/{cjs/packageScripts-DX6dilK6.cjs.js → commands/migrate/packageScripts.cjs.js} +1 -1
- package/dist/{cjs/reactRouterDeps-CR-hjviw.cjs.js → commands/migrate/reactRouterDeps.cjs.js} +1 -1
- package/dist/commands/new/new.cjs.js +101 -0
- package/dist/commands/pack.cjs.js +29 -0
- package/dist/commands/repo/build.cjs.js +113 -0
- package/dist/{cjs/clean-a6Q4k9Vm.cjs.js → commands/repo/clean.cjs.js} +5 -10
- package/dist/{cjs/fix-COitqgqm.cjs.js → commands/repo/fix.cjs.js} +8 -13
- package/dist/commands/repo/lint.cjs.js +193 -0
- package/dist/{cjs/list-deprecations-CtUaQgaP.cjs.js → commands/repo/list-deprecations.cjs.js} +7 -12
- package/dist/commands/repo/optionsParser.cjs.js +37 -0
- package/dist/commands/repo/test.cjs.js +274 -0
- package/dist/commands/start/command.cjs.js +48 -0
- package/dist/commands/start/index.cjs.js +8 -0
- package/dist/commands/start/startBackend.cjs.js +112 -0
- package/dist/commands/start/startFrontend.cjs.js +47 -0
- package/dist/{cjs/test-COxIko8N.cjs.js → commands/test.cjs.js} +6 -12
- package/dist/{cjs/bump-BHEh5ytx.cjs.js → commands/versions/bump.cjs.js} +21 -190
- package/dist/commands/versions/migrate.cjs.js +112 -0
- package/dist/index.cjs.js +29 -7
- package/dist/lib/builder/config.cjs.js +199 -0
- package/dist/lib/builder/packager.cjs.js +131 -0
- package/dist/lib/builder/plugins.cjs.js +71 -0
- package/dist/lib/builder/types.cjs.js +11 -0
- package/dist/lib/bundler/LinkedPackageResolvePlugin.cjs.js +47 -0
- package/dist/lib/bundler/backend.cjs.js +36 -0
- package/dist/{cjs/buildBackend-CkhZWCz1.cjs.js → lib/bundler/bundle.cjs.js} +26 -113
- package/dist/lib/bundler/config.cjs.js +469 -0
- package/dist/lib/bundler/hasReactDomClient.cjs.js +13 -0
- package/dist/lib/bundler/moduleFederation.cjs.js +28 -0
- package/dist/lib/bundler/optimization.cjs.js +63 -0
- package/dist/lib/bundler/packageDetection.cjs.js +117 -0
- package/dist/lib/bundler/paths.cjs.js +60 -0
- package/dist/lib/bundler/server.cjs.js +246 -0
- package/dist/lib/bundler/transforms.cjs.js +171 -0
- package/dist/lib/codeowners/codeowners.cjs.js +92 -0
- package/dist/{cjs/config-DBpmZirN.cjs.js → lib/config.cjs.js} +6 -6
- package/dist/{cjs/entryPoints-coip0t-x.cjs.js → lib/entryPoints.cjs.js} +1 -1
- package/dist/lib/errors.cjs.js +45 -0
- package/dist/lib/experimental/IpcServer.cjs.js +60 -0
- package/dist/lib/experimental/ServerDataStore.cjs.js +36 -0
- package/dist/lib/experimental/startBackendExperimental.cjs.js +128 -0
- package/dist/lib/new/FactoryRegistry.cjs.js +96 -0
- package/dist/lib/new/factories/backendModule.cjs.js +82 -0
- package/dist/lib/new/factories/backendPlugin.cjs.js +78 -0
- package/dist/lib/new/factories/common/prompts.cjs.js +57 -0
- package/dist/lib/new/factories/common/tasks.cjs.js +66 -0
- package/dist/lib/new/factories/common/util.cjs.js +16 -0
- package/dist/lib/new/factories/frontendPlugin.cjs.js +107 -0
- package/dist/lib/new/factories/index.cjs.js +24 -0
- package/dist/lib/new/factories/nodeLibraryPackage.cjs.js +57 -0
- package/dist/lib/new/factories/pluginCommon.cjs.js +58 -0
- package/dist/lib/new/factories/pluginNode.cjs.js +58 -0
- package/dist/lib/new/factories/pluginWeb.cjs.js +58 -0
- package/dist/lib/new/factories/scaffolderModule.cjs.js +90 -0
- package/dist/lib/new/factories/webLibraryPackage.cjs.js +57 -0
- package/dist/lib/new/types.cjs.js +8 -0
- package/dist/lib/packager/createDistWorkspace.cjs.js +219 -0
- package/dist/{cjs/productionPack-BxoMbBkH.cjs.js → lib/packager/productionPack.cjs.js} +8 -96
- package/dist/{cjs/parallel-BszNaKyc.cjs.js → lib/parallel.cjs.js} +2 -1
- package/dist/lib/paths.cjs.js +8 -0
- package/dist/{cjs/publishing-DQtsKTbc.cjs.js → lib/publishing.cjs.js} +1 -1
- package/dist/{cjs/role-BjiBExhi.cjs.js → lib/role.cjs.js} +3 -3
- package/dist/{cjs/run-CpZGNJQr.cjs.js → lib/run.cjs.js} +6 -5
- package/dist/{cjs/svgrTemplate-BTjBQ3by.cjs.js → lib/svgrTemplate.cjs.js} +1 -1
- package/dist/lib/tasks.cjs.js +188 -0
- package/dist/lib/typeDistProject.cjs.js +94 -0
- package/dist/lib/urls.cjs.js +13 -0
- package/dist/lib/version.cjs.js +86 -0
- package/dist/{cjs/yarn-6FNAgNBK.cjs.js → lib/versioning/Lockfile.cjs.js} +1 -31
- package/dist/lib/versioning/packages.cjs.js +75 -0
- package/dist/lib/yarn.cjs.js +34 -0
- package/dist/packages/backend-defaults/package.json.cjs.js +6 -0
- package/dist/packages/backend-plugin-api/package.json.cjs.js +6 -0
- package/dist/packages/backend-test-utils/package.json.cjs.js +6 -0
- package/dist/packages/cli/package.json.cjs.js +159 -0
- package/dist/packages/config/package.json.cjs.js +6 -0
- package/dist/packages/core-app-api/package.json.cjs.js +6 -0
- package/dist/packages/core-components/package.json.cjs.js +6 -0
- package/dist/packages/core-plugin-api/package.json.cjs.js +6 -0
- package/dist/packages/dev-utils/package.json.cjs.js +6 -0
- package/dist/packages/test-utils/package.json.cjs.js +6 -0
- package/dist/packages/theme/package.json.cjs.js +6 -0
- package/dist/plugins/auth-backend/package.json.cjs.js +6 -0
- package/dist/plugins/auth-backend-module-guest-provider/package.json.cjs.js +6 -0
- package/dist/plugins/scaffolder-node/package.json.cjs.js +6 -0
- package/package.json +13 -11
- package/dist/cjs/build-CQdcGuBr.cjs.js +0 -194
- package/dist/cjs/buildWorkspace-CZPp9oRm.cjs.js +0 -53
- package/dist/cjs/clean-W6nxsHeK.cjs.js +0 -22
- package/dist/cjs/createDistWorkspace-DdHPGSMS.cjs.js +0 -576
- package/dist/cjs/index-BXv4Xa2e.cjs.js +0 -625
- package/dist/cjs/index-CGuAP7nv.cjs.js +0 -131
- package/dist/cjs/index-b1ouG3q6.cjs.js +0 -518
- package/dist/cjs/lint-Dsiocf9K.cjs.js +0 -91
- package/dist/cjs/moduleFederation-DmStnvEg.cjs.js +0 -910
- package/dist/cjs/new-CEnFhTT-.cjs.js +0 -1043
- package/dist/cjs/pack-XLRcGJqH.cjs.js +0 -34
- package/dist/cjs/packageExports-BJBwdvUH.cjs.js +0 -27
- package/dist/cjs/test-JcLI2pPM.cjs.js +0 -126
- package/dist/cjs/validate-CELljsEX.cjs.js +0 -28
- /package/templates/default-backend-module/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/default-backend-plugin/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/default-common-plugin-package/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/default-node-plugin-package/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/default-plugin/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/default-react-plugin-package/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/node-library-package/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/scaffolder-module/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
- /package/templates/web-library-package/{.eslintrc.js → .eslintrc.js.hbs} +0 -0
|
@@ -1,1043 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var os = require('os');
|
|
4
|
-
var fs = require('fs-extra');
|
|
5
|
-
var path = require('path');
|
|
6
|
-
var chalk = require('chalk');
|
|
7
|
-
var inquirer = require('inquirer');
|
|
8
|
-
var camelCase = require('lodash/camelCase');
|
|
9
|
-
var upperFirst = require('lodash/upperFirst');
|
|
10
|
-
var index = require('./index-b1ouG3q6.cjs.js');
|
|
11
|
-
var handlebars = require('handlebars');
|
|
12
|
-
var ora = require('ora');
|
|
13
|
-
var util = require('util');
|
|
14
|
-
var recursive = require('recursive-readdir');
|
|
15
|
-
var child_process = require('child_process');
|
|
16
|
-
var errors = require('@backstage/errors');
|
|
17
|
-
var yarn = require('./yarn-6FNAgNBK.cjs.js');
|
|
18
|
-
require('minimatch');
|
|
19
|
-
require('@manypkg/get-packages');
|
|
20
|
-
require('./run-CpZGNJQr.cjs.js');
|
|
21
|
-
var partition = require('lodash/partition');
|
|
22
|
-
var cliNode = require('@backstage/cli-node');
|
|
23
|
-
require('commander');
|
|
24
|
-
require('semver');
|
|
25
|
-
require('@backstage/cli-common');
|
|
26
|
-
require('@yarnpkg/parsers');
|
|
27
|
-
require('@yarnpkg/lockfile');
|
|
28
|
-
|
|
29
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
30
|
-
|
|
31
|
-
var os__default = /*#__PURE__*/_interopDefaultCompat(os);
|
|
32
|
-
var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
33
|
-
var path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
34
|
-
var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
|
|
35
|
-
var inquirer__default = /*#__PURE__*/_interopDefaultCompat(inquirer);
|
|
36
|
-
var camelCase__default = /*#__PURE__*/_interopDefaultCompat(camelCase);
|
|
37
|
-
var upperFirst__default = /*#__PURE__*/_interopDefaultCompat(upperFirst);
|
|
38
|
-
var handlebars__default = /*#__PURE__*/_interopDefaultCompat(handlebars);
|
|
39
|
-
var ora__default = /*#__PURE__*/_interopDefaultCompat(ora);
|
|
40
|
-
var recursive__default = /*#__PURE__*/_interopDefaultCompat(recursive);
|
|
41
|
-
var partition__default = /*#__PURE__*/_interopDefaultCompat(partition);
|
|
42
|
-
|
|
43
|
-
const TEAM_ID_RE = /^@[-\w]+\/[-\w]+$/;
|
|
44
|
-
const USER_ID_RE = /^@[-\w]+$/;
|
|
45
|
-
const EMAIL_RE = /^[^@]+@[-.\w]+\.[-\w]+$/i;
|
|
46
|
-
const DEFAULT_OWNER = "@backstage/maintainers";
|
|
47
|
-
async function getCodeownersFilePath(rootDir) {
|
|
48
|
-
const possiblePaths = [
|
|
49
|
-
path__default.default.join(rootDir, ".github", "CODEOWNERS"),
|
|
50
|
-
path__default.default.join(rootDir, ".gitlab", "CODEOWNERS"),
|
|
51
|
-
path__default.default.join(rootDir, "docs", "CODEOWNERS"),
|
|
52
|
-
path__default.default.join(rootDir, "CODEOWNERS")
|
|
53
|
-
];
|
|
54
|
-
for (const p of possiblePaths) {
|
|
55
|
-
if (await fs__default.default.pathExists(p)) {
|
|
56
|
-
return p;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return void 0;
|
|
60
|
-
}
|
|
61
|
-
function isValidSingleOwnerId(id) {
|
|
62
|
-
if (!id || typeof id !== "string") {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
return TEAM_ID_RE.test(id) || USER_ID_RE.test(id) || EMAIL_RE.test(id);
|
|
66
|
-
}
|
|
67
|
-
function parseOwnerIds(spaceSeparatedOwnerIds) {
|
|
68
|
-
if (!spaceSeparatedOwnerIds || typeof spaceSeparatedOwnerIds !== "string") {
|
|
69
|
-
return void 0;
|
|
70
|
-
}
|
|
71
|
-
const ids = spaceSeparatedOwnerIds.split(" ").filter(Boolean);
|
|
72
|
-
if (!ids.every(isValidSingleOwnerId)) {
|
|
73
|
-
return void 0;
|
|
74
|
-
}
|
|
75
|
-
return ids;
|
|
76
|
-
}
|
|
77
|
-
async function addCodeownersEntry(ownedPath, ownerStr, codeownersFilePath) {
|
|
78
|
-
const ownerIds = parseOwnerIds(ownerStr);
|
|
79
|
-
if (!ownerIds || ownerIds.length === 0) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
let filePath = codeownersFilePath;
|
|
83
|
-
if (!filePath) {
|
|
84
|
-
filePath = await getCodeownersFilePath(index.paths.targetRoot);
|
|
85
|
-
if (!filePath) {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const allLines = (await fs__default.default.readFile(filePath, "utf8")).split("\n");
|
|
90
|
-
const commentLines = [];
|
|
91
|
-
for (const line of allLines) {
|
|
92
|
-
if (line[0] !== "#") {
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
commentLines.push(line);
|
|
96
|
-
}
|
|
97
|
-
const oldDeclarationEntries = allLines.filter((line) => line[0] !== "#").map((line) => line.split(/\s+/).filter(Boolean)).filter((tokens) => tokens.length >= 2).map((tokens) => ({
|
|
98
|
-
ownedPath: tokens[0],
|
|
99
|
-
ownerIds: tokens.slice(1)
|
|
100
|
-
}));
|
|
101
|
-
const newDeclarationEntries = oldDeclarationEntries.filter((entry) => entry.ownedPath !== "*").concat([{ ownedPath, ownerIds }]).sort((l1, l2) => l1.ownedPath.localeCompare(l2.ownedPath));
|
|
102
|
-
newDeclarationEntries.unshift({
|
|
103
|
-
ownedPath: "*",
|
|
104
|
-
ownerIds: [DEFAULT_OWNER]
|
|
105
|
-
});
|
|
106
|
-
const longestOwnedPath = newDeclarationEntries.reduce(
|
|
107
|
-
(length, entry) => Math.max(length, entry.ownedPath.length),
|
|
108
|
-
0
|
|
109
|
-
);
|
|
110
|
-
const newDeclarationLines = newDeclarationEntries.map((entry) => {
|
|
111
|
-
const entryPath = entry.ownedPath + " ".repeat(longestOwnedPath - entry.ownedPath.length);
|
|
112
|
-
return [entryPath, ...entry.ownerIds].join(" ");
|
|
113
|
-
});
|
|
114
|
-
const newLines = [...commentLines, "", ...newDeclarationLines, ""];
|
|
115
|
-
await fs__default.default.writeFile(filePath, newLines.join("\n"), "utf8");
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function createFactory(config) {
|
|
120
|
-
return config;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const exec = util.promisify(child_process.exec);
|
|
124
|
-
const TASK_NAME_MAX_LENGTH = 14;
|
|
125
|
-
class Task {
|
|
126
|
-
static log(name = "") {
|
|
127
|
-
process.stderr.write(`${chalk__default.default.green(name)}
|
|
128
|
-
`);
|
|
129
|
-
}
|
|
130
|
-
static error(message = "") {
|
|
131
|
-
process.stderr.write(`
|
|
132
|
-
${chalk__default.default.red(message)}
|
|
133
|
-
|
|
134
|
-
`);
|
|
135
|
-
}
|
|
136
|
-
static section(name) {
|
|
137
|
-
const title = chalk__default.default.green(`${name}:`);
|
|
138
|
-
process.stderr.write(`
|
|
139
|
-
${title}
|
|
140
|
-
`);
|
|
141
|
-
}
|
|
142
|
-
static exit(code = 0) {
|
|
143
|
-
process.exit(code);
|
|
144
|
-
}
|
|
145
|
-
static async forItem(task, item, taskFunc) {
|
|
146
|
-
const paddedTask = chalk__default.default.green(task.padEnd(TASK_NAME_MAX_LENGTH));
|
|
147
|
-
const spinner = ora__default.default({
|
|
148
|
-
prefixText: chalk__default.default.green(` ${paddedTask}${chalk__default.default.cyan(item)}`),
|
|
149
|
-
spinner: "arc",
|
|
150
|
-
color: "green"
|
|
151
|
-
}).start();
|
|
152
|
-
try {
|
|
153
|
-
const result = await taskFunc();
|
|
154
|
-
spinner.succeed();
|
|
155
|
-
return result;
|
|
156
|
-
} catch (error) {
|
|
157
|
-
spinner.fail();
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
static async forCommand(command, options) {
|
|
162
|
-
try {
|
|
163
|
-
await Task.forItem("executing", command, async () => {
|
|
164
|
-
await exec(command, { cwd: options?.cwd });
|
|
165
|
-
});
|
|
166
|
-
} catch (error) {
|
|
167
|
-
errors.assertError(error);
|
|
168
|
-
if (error.stderr) {
|
|
169
|
-
process.stderr.write(error.stderr);
|
|
170
|
-
}
|
|
171
|
-
if (error.stdout) {
|
|
172
|
-
process.stdout.write(error.stdout);
|
|
173
|
-
}
|
|
174
|
-
if (options?.optional) {
|
|
175
|
-
Task.error(`Warning: Failed to execute command ${chalk__default.default.cyan(command)}`);
|
|
176
|
-
} else {
|
|
177
|
-
throw new Error(
|
|
178
|
-
`Failed to execute command '${chalk__default.default.cyan(command)}', ${error}`
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
async function templatingTask(templateDir, destinationDir, context, versionProvider, isMonoRepo) {
|
|
185
|
-
const files = await recursive__default.default(templateDir).catch((error) => {
|
|
186
|
-
throw new Error(`Failed to read template directory: ${error.message}`);
|
|
187
|
-
});
|
|
188
|
-
for (const file of files) {
|
|
189
|
-
const destinationFile = file.replace(templateDir, destinationDir);
|
|
190
|
-
await fs__default.default.ensureDir(path.dirname(destinationFile));
|
|
191
|
-
if (file.endsWith(".hbs")) {
|
|
192
|
-
await Task.forItem("templating", path.basename(file), async () => {
|
|
193
|
-
const destination = destinationFile.replace(/\.hbs$/, "");
|
|
194
|
-
const template = await fs__default.default.readFile(file);
|
|
195
|
-
const compiled = handlebars__default.default.compile(template.toString(), {
|
|
196
|
-
strict: true
|
|
197
|
-
});
|
|
198
|
-
const contents = compiled(
|
|
199
|
-
{ name: path.basename(destination), ...context },
|
|
200
|
-
{
|
|
201
|
-
helpers: {
|
|
202
|
-
versionQuery(name, versionHint) {
|
|
203
|
-
return versionProvider(
|
|
204
|
-
name,
|
|
205
|
-
typeof versionHint === "string" ? versionHint : void 0
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
);
|
|
211
|
-
await fs__default.default.writeFile(destination, contents).catch((error) => {
|
|
212
|
-
throw new Error(
|
|
213
|
-
`Failed to create file: ${destination}: ${error.message}`
|
|
214
|
-
);
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
} else {
|
|
218
|
-
if (isMonoRepo && file.match("tsconfig.json")) {
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
await Task.forItem("copying", path.basename(file), async () => {
|
|
222
|
-
await fs__default.default.copyFile(file, destinationFile).catch((error) => {
|
|
223
|
-
const destination = destinationFile;
|
|
224
|
-
throw new Error(
|
|
225
|
-
`Failed to copy file to ${destination} : ${error.message}`
|
|
226
|
-
);
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
async function addPackageDependency(path, options) {
|
|
233
|
-
try {
|
|
234
|
-
const pkgJson = await fs__default.default.readJson(path);
|
|
235
|
-
const normalize = (obj) => {
|
|
236
|
-
if (Object.keys(obj).length === 0) {
|
|
237
|
-
return void 0;
|
|
238
|
-
}
|
|
239
|
-
return Object.fromEntries(
|
|
240
|
-
Object.keys(obj).sort().map((key) => [key, obj[key]])
|
|
241
|
-
);
|
|
242
|
-
};
|
|
243
|
-
pkgJson.dependencies = normalize({
|
|
244
|
-
...pkgJson.dependencies,
|
|
245
|
-
...options.dependencies
|
|
246
|
-
});
|
|
247
|
-
pkgJson.devDependencies = normalize({
|
|
248
|
-
...pkgJson.devDependencies,
|
|
249
|
-
...options.devDependencies
|
|
250
|
-
});
|
|
251
|
-
pkgJson.peerDependencies = normalize({
|
|
252
|
-
...pkgJson.peerDependencies,
|
|
253
|
-
...options.peerDependencies
|
|
254
|
-
});
|
|
255
|
-
await fs__default.default.writeJson(path, pkgJson, { spaces: 2 });
|
|
256
|
-
} catch (error) {
|
|
257
|
-
throw new Error(`Failed to add package dependencies, ${error}`);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
async function addToBackend(name, options) {
|
|
261
|
-
if (await fs__default.default.pathExists(index.paths.resolveTargetRoot("packages/backend"))) {
|
|
262
|
-
await Task.forItem("backend", `adding ${options.type}`, async () => {
|
|
263
|
-
const backendFilePath = index.paths.resolveTargetRoot(
|
|
264
|
-
"packages/backend/src/index.ts"
|
|
265
|
-
);
|
|
266
|
-
if (!await fs__default.default.pathExists(backendFilePath)) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
const content = await fs__default.default.readFile(backendFilePath, "utf8");
|
|
270
|
-
const lines = content.split("\n");
|
|
271
|
-
const backendAddLine = `backend.add(import('${name}'));`;
|
|
272
|
-
const backendStartIndex = lines.findIndex(
|
|
273
|
-
(line) => line.match(/backend.start/)
|
|
274
|
-
);
|
|
275
|
-
if (backendStartIndex !== -1) {
|
|
276
|
-
const [indentation] = lines[backendStartIndex].match(/^\s*/);
|
|
277
|
-
lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`);
|
|
278
|
-
const newContent = lines.join("\n");
|
|
279
|
-
await fs__default.default.writeFile(backendFilePath, newContent, "utf8");
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function pluginIdPrompt() {
|
|
286
|
-
return {
|
|
287
|
-
type: "input",
|
|
288
|
-
name: "id",
|
|
289
|
-
message: "Enter the ID of the plugin [required]",
|
|
290
|
-
validate: (value) => {
|
|
291
|
-
if (!value) {
|
|
292
|
-
return "Please enter the ID of the plugin";
|
|
293
|
-
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
|
294
|
-
return "Plugin IDs must be lowercase and contain only letters, digits, and dashes.";
|
|
295
|
-
}
|
|
296
|
-
return true;
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
function moduleIdIdPrompt() {
|
|
301
|
-
return {
|
|
302
|
-
type: "input",
|
|
303
|
-
name: "moduleId",
|
|
304
|
-
message: "Enter the ID of the module [required]",
|
|
305
|
-
validate: (value) => {
|
|
306
|
-
if (!value) {
|
|
307
|
-
return "Please enter the ID of the module";
|
|
308
|
-
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
|
309
|
-
return "Module IDs must be lowercase and contain only letters, digits, and dashes.";
|
|
310
|
-
}
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
function ownerPrompt() {
|
|
316
|
-
return {
|
|
317
|
-
type: "input",
|
|
318
|
-
name: "owner",
|
|
319
|
-
message: "Enter an owner to add to CODEOWNERS [optional]",
|
|
320
|
-
when: (opts) => Boolean(opts.codeOwnersPath),
|
|
321
|
-
validate: (value) => {
|
|
322
|
-
if (!value) {
|
|
323
|
-
return true;
|
|
324
|
-
}
|
|
325
|
-
const ownerIds = parseOwnerIds(value);
|
|
326
|
-
if (!ownerIds) {
|
|
327
|
-
return "The owner must be a space separated list of team names (e.g. @org/team-name), usernames (e.g. @username), or the email addresses (e.g. user@example.com).";
|
|
328
|
-
}
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
async function executePluginPackageTemplate(ctx, options) {
|
|
335
|
-
const { targetDir } = options;
|
|
336
|
-
let lockfile;
|
|
337
|
-
try {
|
|
338
|
-
lockfile = await yarn.Lockfile.load(index.paths.resolveTargetRoot("yarn.lock"));
|
|
339
|
-
} catch {
|
|
340
|
-
}
|
|
341
|
-
Task.section("Checking Prerequisites");
|
|
342
|
-
const shortPluginDir = path.relative(index.paths.targetRoot, targetDir);
|
|
343
|
-
await Task.forItem("availability", shortPluginDir, async () => {
|
|
344
|
-
if (await fs__default.default.pathExists(targetDir)) {
|
|
345
|
-
throw new Error(
|
|
346
|
-
`A package with the same plugin ID already exists at ${chalk__default.default.cyan(
|
|
347
|
-
shortPluginDir
|
|
348
|
-
)}. Please try again with a different ID.`
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
const tempDir = await Task.forItem("creating", "temp dir", async () => {
|
|
353
|
-
return await ctx.createTemporaryDirectory("backstage-create");
|
|
354
|
-
});
|
|
355
|
-
Task.section("Executing Template");
|
|
356
|
-
await templatingTask(
|
|
357
|
-
index.paths.resolveOwn("templates", options.templateName),
|
|
358
|
-
tempDir,
|
|
359
|
-
options.values,
|
|
360
|
-
index.createPackageVersionProvider(lockfile),
|
|
361
|
-
ctx.isMonoRepo
|
|
362
|
-
);
|
|
363
|
-
const pkgJsonPath = path.resolve(tempDir, "package.json");
|
|
364
|
-
if (await fs__default.default.pathExists(pkgJsonPath)) {
|
|
365
|
-
const pkgJson = await fs__default.default.readJson(pkgJsonPath);
|
|
366
|
-
await fs__default.default.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
367
|
-
}
|
|
368
|
-
Task.section("Installing");
|
|
369
|
-
await Task.forItem("moving", shortPluginDir, async () => {
|
|
370
|
-
await fs__default.default.move(tempDir, targetDir).catch((error) => {
|
|
371
|
-
throw new Error(
|
|
372
|
-
`Failed to move package from ${tempDir} to ${targetDir}, ${error.message}`
|
|
373
|
-
);
|
|
374
|
-
});
|
|
375
|
-
});
|
|
376
|
-
ctx.markAsModified();
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const resolvePackageName = (options) => {
|
|
380
|
-
const { baseName, scope, plugin } = options;
|
|
381
|
-
if (scope) {
|
|
382
|
-
if (plugin) {
|
|
383
|
-
const pluginName = scope.startsWith("backstage") ? "plugin" : "backstage-plugin";
|
|
384
|
-
return scope.includes("/") ? `@${scope}${pluginName}-${baseName}` : `@${scope}/${pluginName}-${baseName}`;
|
|
385
|
-
}
|
|
386
|
-
return scope.includes("/") ? `@${scope}${baseName}` : `@${scope}/${baseName}`;
|
|
387
|
-
}
|
|
388
|
-
return plugin ? `backstage-plugin-${baseName}` : baseName;
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
const frontendPlugin = createFactory({
|
|
392
|
-
name: "plugin",
|
|
393
|
-
description: "A new frontend plugin",
|
|
394
|
-
optionsDiscovery: async () => ({
|
|
395
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
396
|
-
}),
|
|
397
|
-
optionsPrompts: [pluginIdPrompt(), ownerPrompt()],
|
|
398
|
-
async create(options, ctx) {
|
|
399
|
-
const { id } = options;
|
|
400
|
-
const name = resolvePackageName({
|
|
401
|
-
baseName: id,
|
|
402
|
-
scope: ctx.scope,
|
|
403
|
-
plugin: true
|
|
404
|
-
});
|
|
405
|
-
const extensionName = `${upperFirst__default.default(camelCase__default.default(id))}Page`;
|
|
406
|
-
Task.log();
|
|
407
|
-
Task.log(`Creating frontend plugin ${chalk__default.default.cyan(name)}`);
|
|
408
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("plugins", id) : index.paths.resolveTargetRoot(`backstage-plugin-${id}`);
|
|
409
|
-
await executePluginPackageTemplate(ctx, {
|
|
410
|
-
targetDir,
|
|
411
|
-
templateName: "default-plugin",
|
|
412
|
-
values: {
|
|
413
|
-
id,
|
|
414
|
-
name,
|
|
415
|
-
extensionName,
|
|
416
|
-
pluginVar: `${camelCase__default.default(id)}Plugin`,
|
|
417
|
-
pluginVersion: ctx.defaultVersion,
|
|
418
|
-
privatePackage: ctx.private,
|
|
419
|
-
npmRegistry: ctx.npmRegistry,
|
|
420
|
-
license: ctx.license
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
if (await fs__default.default.pathExists(index.paths.resolveTargetRoot("packages/app"))) {
|
|
424
|
-
await Task.forItem("app", "adding dependency", async () => {
|
|
425
|
-
await addPackageDependency(
|
|
426
|
-
index.paths.resolveTargetRoot("packages/app/package.json"),
|
|
427
|
-
{
|
|
428
|
-
dependencies: {
|
|
429
|
-
[name]: `^${ctx.defaultVersion}`
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
);
|
|
433
|
-
});
|
|
434
|
-
await Task.forItem("app", "adding import", async () => {
|
|
435
|
-
const pluginsFilePath = index.paths.resolveTargetRoot(
|
|
436
|
-
"packages/app/src/App.tsx"
|
|
437
|
-
);
|
|
438
|
-
if (!await fs__default.default.pathExists(pluginsFilePath)) {
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
const content = await fs__default.default.readFile(pluginsFilePath, "utf8");
|
|
442
|
-
const revLines = content.split("\n").reverse();
|
|
443
|
-
const lastImportIndex = revLines.findIndex(
|
|
444
|
-
(line) => line.match(/ from ("|').*("|')/)
|
|
445
|
-
);
|
|
446
|
-
const lastRouteIndex = revLines.findIndex(
|
|
447
|
-
(line) => line.match(/<\/FlatRoutes/)
|
|
448
|
-
);
|
|
449
|
-
if (lastImportIndex !== -1 && lastRouteIndex !== -1) {
|
|
450
|
-
const importLine = `import { ${extensionName} } from '${name}';`;
|
|
451
|
-
if (!content.includes(importLine)) {
|
|
452
|
-
revLines.splice(lastImportIndex, 0, importLine);
|
|
453
|
-
}
|
|
454
|
-
const componentLine = `<Route path="/${id}" element={<${extensionName} />} />`;
|
|
455
|
-
if (!content.includes(componentLine)) {
|
|
456
|
-
const [indentation] = revLines[lastRouteIndex + 1].match(/^\s*/) ?? [];
|
|
457
|
-
revLines.splice(lastRouteIndex + 1, 0, indentation + componentLine);
|
|
458
|
-
}
|
|
459
|
-
const newContent = revLines.reverse().join("\n");
|
|
460
|
-
await fs__default.default.writeFile(pluginsFilePath, newContent, "utf8");
|
|
461
|
-
}
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
if (options.owner) {
|
|
465
|
-
await addCodeownersEntry(`/plugins/${id}`, options.owner);
|
|
466
|
-
}
|
|
467
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
468
|
-
await Task.forCommand("yarn lint --fix", {
|
|
469
|
-
cwd: targetDir,
|
|
470
|
-
optional: true
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
const backendPlugin = createFactory({
|
|
476
|
-
name: "backend-plugin",
|
|
477
|
-
description: "A new backend plugin",
|
|
478
|
-
optionsDiscovery: async () => ({
|
|
479
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
480
|
-
}),
|
|
481
|
-
optionsPrompts: [pluginIdPrompt(), ownerPrompt()],
|
|
482
|
-
async create(options, ctx) {
|
|
483
|
-
const { id } = options;
|
|
484
|
-
const pluginId = `${id}-backend`;
|
|
485
|
-
const name = resolvePackageName({
|
|
486
|
-
baseName: pluginId,
|
|
487
|
-
scope: ctx.scope,
|
|
488
|
-
plugin: true
|
|
489
|
-
});
|
|
490
|
-
Task.log();
|
|
491
|
-
Task.log(`Creating backend plugin ${chalk__default.default.cyan(name)}`);
|
|
492
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("plugins", pluginId) : index.paths.resolveTargetRoot(`backstage-plugin-${pluginId}`);
|
|
493
|
-
await executePluginPackageTemplate(ctx, {
|
|
494
|
-
targetDir,
|
|
495
|
-
templateName: "default-backend-plugin",
|
|
496
|
-
values: {
|
|
497
|
-
id,
|
|
498
|
-
name,
|
|
499
|
-
pluginVar: `${camelCase__default.default(id)}Plugin`,
|
|
500
|
-
pluginVersion: ctx.defaultVersion,
|
|
501
|
-
privatePackage: ctx.private,
|
|
502
|
-
npmRegistry: ctx.npmRegistry,
|
|
503
|
-
license: ctx.license
|
|
504
|
-
}
|
|
505
|
-
});
|
|
506
|
-
if (await fs__default.default.pathExists(index.paths.resolveTargetRoot("packages/backend"))) {
|
|
507
|
-
await Task.forItem("backend", "adding dependency", async () => {
|
|
508
|
-
await addPackageDependency(
|
|
509
|
-
index.paths.resolveTargetRoot("packages/backend/package.json"),
|
|
510
|
-
{
|
|
511
|
-
dependencies: {
|
|
512
|
-
[name]: `^${ctx.defaultVersion}`
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
);
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
await addToBackend(name, {
|
|
519
|
-
type: "plugin"
|
|
520
|
-
});
|
|
521
|
-
if (options.owner) {
|
|
522
|
-
await addCodeownersEntry(`/plugins/${id}`, options.owner);
|
|
523
|
-
}
|
|
524
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
525
|
-
await Task.forCommand("yarn lint --fix", {
|
|
526
|
-
cwd: targetDir,
|
|
527
|
-
optional: true
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
const backendModule = createFactory({
|
|
533
|
-
name: "backend-module",
|
|
534
|
-
description: "A new backend module that extends an existing backend plugin with additional features",
|
|
535
|
-
optionsDiscovery: async () => ({
|
|
536
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
537
|
-
}),
|
|
538
|
-
optionsPrompts: [pluginIdPrompt(), moduleIdIdPrompt(), ownerPrompt()],
|
|
539
|
-
async create(options, ctx) {
|
|
540
|
-
const { id: pluginId, moduleId } = options;
|
|
541
|
-
const dirName = `${pluginId}-backend-module-${moduleId}`;
|
|
542
|
-
const name = resolvePackageName({
|
|
543
|
-
baseName: dirName,
|
|
544
|
-
scope: ctx.scope,
|
|
545
|
-
plugin: true
|
|
546
|
-
});
|
|
547
|
-
Task.log();
|
|
548
|
-
Task.log(`Creating backend module ${chalk__default.default.cyan(name)}`);
|
|
549
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("plugins", dirName) : index.paths.resolveTargetRoot(`backstage-plugin-${dirName}`);
|
|
550
|
-
const moduleCamelCase = camelCase__default.default(moduleId);
|
|
551
|
-
const modulePascalCase = moduleCamelCase[0].toUpperCase() + moduleCamelCase.slice(1);
|
|
552
|
-
const moduleVar = `${camelCase__default.default(pluginId)}Module${modulePascalCase}`;
|
|
553
|
-
await executePluginPackageTemplate(ctx, {
|
|
554
|
-
targetDir,
|
|
555
|
-
templateName: "default-backend-module",
|
|
556
|
-
values: {
|
|
557
|
-
pluginId,
|
|
558
|
-
moduleId,
|
|
559
|
-
name,
|
|
560
|
-
moduleVar,
|
|
561
|
-
packageVersion: ctx.defaultVersion,
|
|
562
|
-
privatePackage: ctx.private,
|
|
563
|
-
npmRegistry: ctx.npmRegistry,
|
|
564
|
-
license: ctx.license
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
if (await fs__default.default.pathExists(index.paths.resolveTargetRoot("packages/backend"))) {
|
|
568
|
-
await Task.forItem("backend", "adding dependency", async () => {
|
|
569
|
-
await addPackageDependency(
|
|
570
|
-
index.paths.resolveTargetRoot("packages/backend/package.json"),
|
|
571
|
-
{
|
|
572
|
-
dependencies: {
|
|
573
|
-
[name]: `^${ctx.defaultVersion}`
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
);
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
await addToBackend(name, {
|
|
580
|
-
type: "module"
|
|
581
|
-
});
|
|
582
|
-
if (options.owner) {
|
|
583
|
-
await addCodeownersEntry(`/plugins/${dirName}`, options.owner);
|
|
584
|
-
}
|
|
585
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
586
|
-
await Task.forCommand("yarn lint --fix", {
|
|
587
|
-
cwd: targetDir,
|
|
588
|
-
optional: true
|
|
589
|
-
});
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
const nodeLibraryPackage = createFactory({
|
|
594
|
-
name: "node-library",
|
|
595
|
-
description: "A new node-library package, exporting shared functionality for backend plugins and modules",
|
|
596
|
-
optionsDiscovery: async () => ({
|
|
597
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
598
|
-
}),
|
|
599
|
-
optionsPrompts: [pluginIdPrompt(), ownerPrompt()],
|
|
600
|
-
async create(options, ctx) {
|
|
601
|
-
const { id } = options;
|
|
602
|
-
const name = resolvePackageName({
|
|
603
|
-
baseName: id,
|
|
604
|
-
scope: ctx.scope,
|
|
605
|
-
plugin: false
|
|
606
|
-
});
|
|
607
|
-
Task.log();
|
|
608
|
-
Task.log(`Creating node-library package ${chalk__default.default.cyan(name)}`);
|
|
609
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("packages", id) : index.paths.resolveTargetRoot(`${id}`);
|
|
610
|
-
await executePluginPackageTemplate(ctx, {
|
|
611
|
-
targetDir,
|
|
612
|
-
templateName: "node-library-package",
|
|
613
|
-
values: {
|
|
614
|
-
id,
|
|
615
|
-
name,
|
|
616
|
-
pluginVersion: ctx.defaultVersion,
|
|
617
|
-
privatePackage: ctx.private,
|
|
618
|
-
npmRegistry: ctx.npmRegistry,
|
|
619
|
-
license: ctx.license
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
if (options.owner) {
|
|
623
|
-
await addCodeownersEntry(`/packages/${id}`, options.owner);
|
|
624
|
-
}
|
|
625
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
626
|
-
await Task.forCommand("yarn lint --fix", {
|
|
627
|
-
cwd: targetDir,
|
|
628
|
-
optional: true
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
const webLibraryPackage = createFactory({
|
|
634
|
-
name: "web-library",
|
|
635
|
-
description: "A new web-library package, exporting shared functionality for frontend plugins",
|
|
636
|
-
optionsDiscovery: async () => ({
|
|
637
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
638
|
-
}),
|
|
639
|
-
optionsPrompts: [pluginIdPrompt(), ownerPrompt()],
|
|
640
|
-
async create(options, ctx) {
|
|
641
|
-
const { id } = options;
|
|
642
|
-
const name = resolvePackageName({
|
|
643
|
-
baseName: id,
|
|
644
|
-
scope: ctx.scope,
|
|
645
|
-
plugin: false
|
|
646
|
-
});
|
|
647
|
-
Task.log();
|
|
648
|
-
Task.log(`Creating web-library package ${chalk__default.default.cyan(name)}`);
|
|
649
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("packages", id) : index.paths.resolveTargetRoot(`${id}`);
|
|
650
|
-
await executePluginPackageTemplate(ctx, {
|
|
651
|
-
targetDir,
|
|
652
|
-
templateName: "web-library-package",
|
|
653
|
-
values: {
|
|
654
|
-
id,
|
|
655
|
-
name,
|
|
656
|
-
pluginVersion: ctx.defaultVersion,
|
|
657
|
-
privatePackage: ctx.private,
|
|
658
|
-
npmRegistry: ctx.npmRegistry,
|
|
659
|
-
license: ctx.license
|
|
660
|
-
}
|
|
661
|
-
});
|
|
662
|
-
if (options.owner) {
|
|
663
|
-
await addCodeownersEntry(`/packages/${id}`, options.owner);
|
|
664
|
-
}
|
|
665
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
666
|
-
await Task.forCommand("yarn lint --fix", {
|
|
667
|
-
cwd: targetDir,
|
|
668
|
-
optional: true
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
});
|
|
672
|
-
|
|
673
|
-
const pluginCommon = createFactory({
|
|
674
|
-
name: "plugin-common",
|
|
675
|
-
description: "A new isomorphic common plugin package",
|
|
676
|
-
optionsDiscovery: async () => ({
|
|
677
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
678
|
-
}),
|
|
679
|
-
optionsPrompts: [pluginIdPrompt(), ownerPrompt()],
|
|
680
|
-
async create(options, ctx) {
|
|
681
|
-
const { id } = options;
|
|
682
|
-
const suffix = `${id}-common`;
|
|
683
|
-
const name = resolvePackageName({
|
|
684
|
-
baseName: suffix,
|
|
685
|
-
scope: ctx.scope,
|
|
686
|
-
plugin: true
|
|
687
|
-
});
|
|
688
|
-
Task.log();
|
|
689
|
-
Task.log(`Creating common plugin package ${chalk__default.default.cyan(name)}`);
|
|
690
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("plugins", suffix) : index.paths.resolveTargetRoot(`backstage-plugin-${suffix}`);
|
|
691
|
-
await executePluginPackageTemplate(ctx, {
|
|
692
|
-
targetDir,
|
|
693
|
-
templateName: "default-common-plugin-package",
|
|
694
|
-
values: {
|
|
695
|
-
id,
|
|
696
|
-
name,
|
|
697
|
-
privatePackage: ctx.private,
|
|
698
|
-
npmRegistry: ctx.npmRegistry,
|
|
699
|
-
pluginVersion: ctx.defaultVersion,
|
|
700
|
-
license: ctx.license
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
if (options.owner) {
|
|
704
|
-
await addCodeownersEntry(`/plugins/${suffix}`, options.owner);
|
|
705
|
-
}
|
|
706
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
707
|
-
await Task.forCommand("yarn lint --fix", {
|
|
708
|
-
cwd: targetDir,
|
|
709
|
-
optional: true
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
});
|
|
713
|
-
|
|
714
|
-
const pluginNode = createFactory({
|
|
715
|
-
name: "plugin-node",
|
|
716
|
-
description: "A new Node.js library plugin package",
|
|
717
|
-
optionsDiscovery: async () => ({
|
|
718
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
719
|
-
}),
|
|
720
|
-
optionsPrompts: [pluginIdPrompt(), ownerPrompt()],
|
|
721
|
-
async create(options, ctx) {
|
|
722
|
-
const { id } = options;
|
|
723
|
-
const suffix = `${id}-node`;
|
|
724
|
-
const name = resolvePackageName({
|
|
725
|
-
baseName: suffix,
|
|
726
|
-
scope: ctx.scope,
|
|
727
|
-
plugin: true
|
|
728
|
-
});
|
|
729
|
-
Task.log();
|
|
730
|
-
Task.log(`Creating Node.js plugin library ${chalk__default.default.cyan(name)}`);
|
|
731
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("plugins", suffix) : index.paths.resolveTargetRoot(`backstage-plugin-${suffix}`);
|
|
732
|
-
await executePluginPackageTemplate(ctx, {
|
|
733
|
-
targetDir,
|
|
734
|
-
templateName: "default-node-plugin-package",
|
|
735
|
-
values: {
|
|
736
|
-
id,
|
|
737
|
-
name,
|
|
738
|
-
privatePackage: ctx.private,
|
|
739
|
-
npmRegistry: ctx.npmRegistry,
|
|
740
|
-
pluginVersion: ctx.defaultVersion,
|
|
741
|
-
license: ctx.license
|
|
742
|
-
}
|
|
743
|
-
});
|
|
744
|
-
if (options.owner) {
|
|
745
|
-
await addCodeownersEntry(`/plugins/${suffix}`, options.owner);
|
|
746
|
-
}
|
|
747
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
748
|
-
await Task.forCommand("yarn lint --fix", {
|
|
749
|
-
cwd: targetDir,
|
|
750
|
-
optional: true
|
|
751
|
-
});
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
const pluginWeb = createFactory({
|
|
756
|
-
name: "plugin-react",
|
|
757
|
-
description: "A new web library plugin package",
|
|
758
|
-
optionsDiscovery: async () => ({
|
|
759
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
760
|
-
}),
|
|
761
|
-
optionsPrompts: [pluginIdPrompt(), ownerPrompt()],
|
|
762
|
-
async create(options, ctx) {
|
|
763
|
-
const { id } = options;
|
|
764
|
-
const suffix = `${id}-react`;
|
|
765
|
-
const name = resolvePackageName({
|
|
766
|
-
baseName: suffix,
|
|
767
|
-
scope: ctx.scope,
|
|
768
|
-
plugin: true
|
|
769
|
-
});
|
|
770
|
-
Task.log();
|
|
771
|
-
Task.log(`Creating web plugin library ${chalk__default.default.cyan(name)}`);
|
|
772
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("plugins", suffix) : index.paths.resolveTargetRoot(`backstage-plugin-${suffix}`);
|
|
773
|
-
await executePluginPackageTemplate(ctx, {
|
|
774
|
-
targetDir,
|
|
775
|
-
templateName: "default-react-plugin-package",
|
|
776
|
-
values: {
|
|
777
|
-
id,
|
|
778
|
-
name,
|
|
779
|
-
privatePackage: ctx.private,
|
|
780
|
-
npmRegistry: ctx.npmRegistry,
|
|
781
|
-
pluginVersion: ctx.defaultVersion,
|
|
782
|
-
license: ctx.license
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
if (options.owner) {
|
|
786
|
-
await addCodeownersEntry(`/plugins/${suffix}`, options.owner);
|
|
787
|
-
}
|
|
788
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
789
|
-
await Task.forCommand("yarn lint --fix", {
|
|
790
|
-
cwd: targetDir,
|
|
791
|
-
optional: true
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
const scaffolderModule = createFactory({
|
|
797
|
-
name: "scaffolder-module",
|
|
798
|
-
description: "An module exporting custom actions for @backstage/plugin-scaffolder-backend",
|
|
799
|
-
optionsDiscovery: async () => ({
|
|
800
|
-
codeOwnersPath: await getCodeownersFilePath(index.paths.targetRoot)
|
|
801
|
-
}),
|
|
802
|
-
optionsPrompts: [
|
|
803
|
-
{
|
|
804
|
-
type: "input",
|
|
805
|
-
name: "id",
|
|
806
|
-
message: "Enter the name of the module [required]",
|
|
807
|
-
validate: (value) => {
|
|
808
|
-
if (!value) {
|
|
809
|
-
return "Please enter the name of the module";
|
|
810
|
-
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
|
811
|
-
return "Module names must be lowercase and contain only letters, digits, and dashes.";
|
|
812
|
-
}
|
|
813
|
-
return true;
|
|
814
|
-
}
|
|
815
|
-
},
|
|
816
|
-
ownerPrompt()
|
|
817
|
-
],
|
|
818
|
-
async create(options, ctx) {
|
|
819
|
-
const { id } = options;
|
|
820
|
-
const slug = `scaffolder-backend-module-${id}`;
|
|
821
|
-
const name = resolvePackageName({
|
|
822
|
-
baseName: slug,
|
|
823
|
-
scope: ctx.scope,
|
|
824
|
-
plugin: true
|
|
825
|
-
});
|
|
826
|
-
Task.log();
|
|
827
|
-
Task.log(`Creating module ${chalk__default.default.cyan(name)}`);
|
|
828
|
-
const targetDir = ctx.isMonoRepo ? index.paths.resolveTargetRoot("plugins", slug) : index.paths.resolveTargetRoot(`backstage-plugin-${slug}`);
|
|
829
|
-
await executePluginPackageTemplate(ctx, {
|
|
830
|
-
targetDir,
|
|
831
|
-
templateName: "scaffolder-module",
|
|
832
|
-
values: {
|
|
833
|
-
id,
|
|
834
|
-
name,
|
|
835
|
-
privatePackage: ctx.private,
|
|
836
|
-
npmRegistry: ctx.npmRegistry,
|
|
837
|
-
pluginVersion: ctx.defaultVersion,
|
|
838
|
-
license: ctx.license
|
|
839
|
-
}
|
|
840
|
-
});
|
|
841
|
-
if (await fs__default.default.pathExists(index.paths.resolveTargetRoot("packages/backend"))) {
|
|
842
|
-
await Task.forItem("backend", "adding dependency", async () => {
|
|
843
|
-
await addPackageDependency(
|
|
844
|
-
index.paths.resolveTargetRoot("packages/backend/package.json"),
|
|
845
|
-
{
|
|
846
|
-
dependencies: {
|
|
847
|
-
[name]: `^${ctx.defaultVersion}`
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
);
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
await addToBackend(name, {
|
|
854
|
-
type: "module"
|
|
855
|
-
});
|
|
856
|
-
if (options.owner) {
|
|
857
|
-
await addCodeownersEntry(`/plugins/${slug}`, options.owner);
|
|
858
|
-
}
|
|
859
|
-
await Task.forCommand("yarn install", { cwd: targetDir, optional: true });
|
|
860
|
-
await Task.forCommand("yarn lint --fix", {
|
|
861
|
-
cwd: targetDir,
|
|
862
|
-
optional: true
|
|
863
|
-
});
|
|
864
|
-
}
|
|
865
|
-
});
|
|
866
|
-
|
|
867
|
-
var factories = /*#__PURE__*/Object.freeze({
|
|
868
|
-
__proto__: null,
|
|
869
|
-
backendModule: backendModule,
|
|
870
|
-
backendPlugin: backendPlugin,
|
|
871
|
-
frontendPlugin: frontendPlugin,
|
|
872
|
-
nodeLibraryPackage: nodeLibraryPackage,
|
|
873
|
-
pluginCommon: pluginCommon,
|
|
874
|
-
pluginNode: pluginNode,
|
|
875
|
-
pluginWeb: pluginWeb,
|
|
876
|
-
scaffolderModule: scaffolderModule,
|
|
877
|
-
webLibraryPackage: webLibraryPackage
|
|
878
|
-
});
|
|
879
|
-
|
|
880
|
-
function applyPromptMessageTransforms(prompt, transforms) {
|
|
881
|
-
return {
|
|
882
|
-
...prompt,
|
|
883
|
-
message: prompt.message && (async (answers) => {
|
|
884
|
-
if (typeof prompt.message === "function") {
|
|
885
|
-
return transforms.message(await prompt.message(answers));
|
|
886
|
-
}
|
|
887
|
-
return transforms.message(await prompt.message);
|
|
888
|
-
}),
|
|
889
|
-
validate: prompt.validate && (async (...args) => {
|
|
890
|
-
const result = await prompt.validate(...args);
|
|
891
|
-
if (typeof result === "string") {
|
|
892
|
-
return transforms.error(result);
|
|
893
|
-
}
|
|
894
|
-
return result;
|
|
895
|
-
})
|
|
896
|
-
};
|
|
897
|
-
}
|
|
898
|
-
class FactoryRegistry {
|
|
899
|
-
static factoryMap = new Map(
|
|
900
|
-
Object.values(factories).map((factory) => [factory.name, factory])
|
|
901
|
-
);
|
|
902
|
-
static async interactiveSelect(preselected) {
|
|
903
|
-
let selected = preselected;
|
|
904
|
-
if (!selected) {
|
|
905
|
-
const answers = await inquirer__default.default.prompt([
|
|
906
|
-
{
|
|
907
|
-
type: "list",
|
|
908
|
-
name: "name",
|
|
909
|
-
message: "What do you want to create?",
|
|
910
|
-
choices: Array.from(this.factoryMap.values()).map((factory2) => ({
|
|
911
|
-
name: `${factory2.name} - ${factory2.description}`,
|
|
912
|
-
value: factory2.name
|
|
913
|
-
}))
|
|
914
|
-
}
|
|
915
|
-
]);
|
|
916
|
-
selected = answers.name;
|
|
917
|
-
}
|
|
918
|
-
const factory = this.factoryMap.get(selected);
|
|
919
|
-
if (!factory) {
|
|
920
|
-
throw new Error(`Unknown selection '${selected}'`);
|
|
921
|
-
}
|
|
922
|
-
return factory;
|
|
923
|
-
}
|
|
924
|
-
static async populateOptions(factory, provided) {
|
|
925
|
-
let currentOptions = provided;
|
|
926
|
-
if (factory.optionsDiscovery) {
|
|
927
|
-
const discoveredOptions = await factory.optionsDiscovery();
|
|
928
|
-
currentOptions = {
|
|
929
|
-
...currentOptions,
|
|
930
|
-
...discoveredOptions
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
if (factory.optionsPrompts) {
|
|
934
|
-
const [hasAnswers, needsAnswers] = partition__default.default(
|
|
935
|
-
factory.optionsPrompts,
|
|
936
|
-
(option) => option.name in currentOptions
|
|
937
|
-
);
|
|
938
|
-
for (const option of hasAnswers) {
|
|
939
|
-
const value = provided[option.name];
|
|
940
|
-
if (option.validate) {
|
|
941
|
-
const result = option.validate(value);
|
|
942
|
-
if (result !== true) {
|
|
943
|
-
throw new Error(`Invalid option '${option.name}'. ${result}`);
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
currentOptions = await inquirer__default.default.prompt(
|
|
948
|
-
needsAnswers.map(
|
|
949
|
-
(option) => applyPromptMessageTransforms(option, {
|
|
950
|
-
message: chalk__default.default.blue,
|
|
951
|
-
error: chalk__default.default.red
|
|
952
|
-
})
|
|
953
|
-
),
|
|
954
|
-
currentOptions
|
|
955
|
-
);
|
|
956
|
-
}
|
|
957
|
-
return currentOptions;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
function parseOptions(optionStrings) {
|
|
962
|
-
const options = {};
|
|
963
|
-
for (const str of optionStrings) {
|
|
964
|
-
const [key] = str.split("=", 1);
|
|
965
|
-
const value = str.slice(key.length + 1);
|
|
966
|
-
if (!key || str[key.length] !== "=") {
|
|
967
|
-
throw new Error(
|
|
968
|
-
`Invalid option '${str}', must be of the format <key>=<value>`
|
|
969
|
-
);
|
|
970
|
-
}
|
|
971
|
-
options[key] = value;
|
|
972
|
-
}
|
|
973
|
-
return options;
|
|
974
|
-
}
|
|
975
|
-
var _new = async (opts) => {
|
|
976
|
-
const factory = await FactoryRegistry.interactiveSelect(opts.select);
|
|
977
|
-
const providedOptions = parseOptions(opts.option);
|
|
978
|
-
const options = await FactoryRegistry.populateOptions(
|
|
979
|
-
factory,
|
|
980
|
-
providedOptions
|
|
981
|
-
);
|
|
982
|
-
let defaultVersion = "0.1.0";
|
|
983
|
-
if (opts.baseVersion) {
|
|
984
|
-
defaultVersion = opts.baseVersion;
|
|
985
|
-
} else {
|
|
986
|
-
const lernaVersion = await fs__default.default.readJson(index.paths.resolveTargetRoot("lerna.json")).then((pkg) => pkg.version).catch(() => void 0);
|
|
987
|
-
if (lernaVersion) {
|
|
988
|
-
defaultVersion = lernaVersion;
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
const tempDirs = new Array();
|
|
992
|
-
async function createTemporaryDirectory(name) {
|
|
993
|
-
const dir = await fs__default.default.mkdtemp(path.join(os__default.default.tmpdir(), name));
|
|
994
|
-
tempDirs.push(dir);
|
|
995
|
-
return dir;
|
|
996
|
-
}
|
|
997
|
-
const license = opts.license ?? "Apache-2.0";
|
|
998
|
-
let modified = false;
|
|
999
|
-
try {
|
|
1000
|
-
await factory.create(options, {
|
|
1001
|
-
isMonoRepo: await cliNode.isMonoRepo(),
|
|
1002
|
-
defaultVersion,
|
|
1003
|
-
license,
|
|
1004
|
-
scope: opts.scope?.replace(/^@/, ""),
|
|
1005
|
-
npmRegistry: opts.npmRegistry,
|
|
1006
|
-
private: Boolean(opts.private),
|
|
1007
|
-
createTemporaryDirectory,
|
|
1008
|
-
markAsModified() {
|
|
1009
|
-
modified = true;
|
|
1010
|
-
}
|
|
1011
|
-
});
|
|
1012
|
-
Task.log();
|
|
1013
|
-
Task.log(`\u{1F389} Successfully created ${factory.name}`);
|
|
1014
|
-
Task.log();
|
|
1015
|
-
} catch (error) {
|
|
1016
|
-
errors.assertError(error);
|
|
1017
|
-
Task.error(error.message);
|
|
1018
|
-
if (modified) {
|
|
1019
|
-
Task.log("It seems that something went wrong in the creation process \u{1F914}");
|
|
1020
|
-
Task.log();
|
|
1021
|
-
Task.log(
|
|
1022
|
-
"We have left the changes that were made intact in case you want to"
|
|
1023
|
-
);
|
|
1024
|
-
Task.log(
|
|
1025
|
-
"continue manually, but you can also revert the changes and try again."
|
|
1026
|
-
);
|
|
1027
|
-
Task.error(`\u{1F525} Failed to create ${factory.name}!`);
|
|
1028
|
-
}
|
|
1029
|
-
} finally {
|
|
1030
|
-
for (const dir of tempDirs) {
|
|
1031
|
-
try {
|
|
1032
|
-
await fs__default.default.remove(dir);
|
|
1033
|
-
} catch (error) {
|
|
1034
|
-
console.error(
|
|
1035
|
-
`Failed to remove temporary directory '${dir}', ${error}`
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
};
|
|
1041
|
-
|
|
1042
|
-
exports.default = _new;
|
|
1043
|
-
//# sourceMappingURL=new-CEnFhTT-.cjs.js.map
|