@backstage/cli 0.34.4 → 0.34.5-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/lib/versioning/Lockfile.cjs.js +8 -5
- package/dist/modules/build/lib/builder/types.cjs.js +5 -6
- package/dist/modules/create-github-app/commands/create-github-app/GithubCreateAppServer.cjs.js +8 -6
- package/dist/modules/new/lib/defaultTemplates.cjs.js +1 -0
- package/dist/modules/new/lib/execution/writeTemplateContents.cjs.js +7 -1
- package/dist/modules/new/lib/preparation/loadPortableTemplateConfig.cjs.js +13 -2
- package/dist/packages/backend-defaults/package.json.cjs.js +1 -1
- package/dist/packages/backend-plugin-api/package.json.cjs.js +1 -1
- package/dist/packages/backend-test-utils/package.json.cjs.js +1 -1
- package/dist/packages/catalog-client/package.json.cjs.js +1 -1
- package/dist/packages/cli/package.json.cjs.js +1 -1
- package/dist/packages/config/package.json.cjs.js +1 -1
- package/dist/packages/core-app-api/package.json.cjs.js +1 -1
- package/dist/packages/core-components/package.json.cjs.js +1 -1
- package/dist/packages/core-plugin-api/package.json.cjs.js +1 -1
- package/dist/packages/dev-utils/package.json.cjs.js +1 -1
- package/dist/packages/frontend-defaults/package.json.cjs.js +1 -1
- package/dist/packages/frontend-plugin-api/package.json.cjs.js +1 -1
- package/dist/packages/frontend-test-utils/package.json.cjs.js +1 -1
- package/dist/packages/test-utils/package.json.cjs.js +1 -1
- package/dist/plugins/auth-backend/package.json.cjs.js +1 -1
- package/dist/plugins/auth-backend-module-guest-provider/package.json.cjs.js +1 -1
- package/dist/plugins/catalog-node/package.json.cjs.js +1 -1
- package/dist/plugins/scaffolder-node/package.json.cjs.js +1 -1
- package/dist/plugins/scaffolder-node-test-utils/package.json.cjs.js +1 -1
- package/package.json +27 -27
- package/templates/catalog-provider-module/.eslintrc.js.hbs +1 -0
- package/templates/catalog-provider-module/README.md.hbs +5 -0
- package/templates/catalog-provider-module/config.d.ts.hbs +34 -0
- package/templates/catalog-provider-module/package.json.hbs +36 -0
- package/templates/catalog-provider-module/portable-template.yaml +9 -0
- package/templates/catalog-provider-module/src/index.ts.hbs +8 -0
- package/templates/catalog-provider-module/src/module.ts.hbs +29 -0
- package/templates/catalog-provider-module/src/provider/readProviderConfigs.ts.hbs +78 -0
- package/templates/catalog-provider-module/src/provider/{{providerClass}}.test.ts.hbs +18 -0
- package/templates/catalog-provider-module/src/provider/{{providerClass}}.ts.hbs +109 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @backstage/cli
|
|
2
2
|
|
|
3
|
+
## 0.34.5-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- da19cb5: Fix inconsistent behavior in the `new` command for the `@internal` scope: it now consistently defaults to the `backstage-plugin-` infix whether the `--scope` option is not set or it's set to `internal`.
|
|
8
|
+
- b2bef92: Convert all enums to erasable-syntax compliant patterns
|
|
9
|
+
|
|
10
|
+
## 0.34.5-next.0
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- fc7cbfc: The templates executed with the `yarn new` command now supports templating filenames.
|
|
15
|
+
- fc7cbfc: Added a template for the `yarn new` command to create an catalog entity provider. To add this template to an explicit list in the root `package.json`, use `@backstage/cli/templates/catalog-provider-module`.
|
|
16
|
+
- 05f60e1: Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @backstage/eslint-plugin@0.2.0-next.0
|
|
19
|
+
- @backstage/config-loader@1.10.6-next.0
|
|
20
|
+
- @backstage/config@1.3.6-next.0
|
|
21
|
+
- @backstage/cli-node@0.2.15-next.0
|
|
22
|
+
- @backstage/catalog-model@1.7.6-next.0
|
|
23
|
+
- @backstage/integration@1.18.2-next.0
|
|
24
|
+
- @backstage/cli-common@0.1.15
|
|
25
|
+
- @backstage/errors@1.2.7
|
|
26
|
+
- @backstage/release-manifests@0.0.13
|
|
27
|
+
- @backstage/types@1.2.2
|
|
28
|
+
|
|
3
29
|
## 0.34.4
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
|
@@ -28,11 +28,6 @@ const SPECIAL_OBJECT_KEYS = [
|
|
|
28
28
|
`binaries`
|
|
29
29
|
];
|
|
30
30
|
class Lockfile {
|
|
31
|
-
constructor(packages, data, legacy = false) {
|
|
32
|
-
this.packages = packages;
|
|
33
|
-
this.data = data;
|
|
34
|
-
this.legacy = legacy;
|
|
35
|
-
}
|
|
36
31
|
static async load(path) {
|
|
37
32
|
const lockfileContents = await fs__default.default.readFile(path, "utf8");
|
|
38
33
|
return Lockfile.parse(lockfileContents);
|
|
@@ -69,6 +64,14 @@ class Lockfile {
|
|
|
69
64
|
}
|
|
70
65
|
return new Lockfile(packages, data, legacy);
|
|
71
66
|
}
|
|
67
|
+
packages;
|
|
68
|
+
data;
|
|
69
|
+
legacy;
|
|
70
|
+
constructor(packages, data, legacy = false) {
|
|
71
|
+
this.packages = packages;
|
|
72
|
+
this.data = data;
|
|
73
|
+
this.legacy = legacy;
|
|
74
|
+
}
|
|
72
75
|
/** Get the entries for a single package in the lockfile */
|
|
73
76
|
get(name) {
|
|
74
77
|
return this.packages.get(name);
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
})(Output || {});
|
|
3
|
+
const Output = {
|
|
4
|
+
esm: 0,
|
|
5
|
+
cjs: 1,
|
|
6
|
+
types: 2
|
|
7
|
+
};
|
|
9
8
|
|
|
10
9
|
exports.Output = Output;
|
|
11
10
|
//# sourceMappingURL=types.cjs.js.map
|
package/dist/modules/create-github-app/commands/create-github-app/GithubCreateAppServer.cjs.js
CHANGED
|
@@ -25,12 +25,6 @@ const FORM_PAGE = `
|
|
|
25
25
|
</html>
|
|
26
26
|
`;
|
|
27
27
|
class GithubCreateAppServer {
|
|
28
|
-
constructor(actionUrl, permissions) {
|
|
29
|
-
this.actionUrl = actionUrl;
|
|
30
|
-
this.permissions = permissions;
|
|
31
|
-
const webhookId = crypto__default.default.randomBytes(15).toString("base64").replace(/[\+\/]/g, "");
|
|
32
|
-
this.webhookUrl = `https://smee.io/${webhookId}`;
|
|
33
|
-
}
|
|
34
28
|
baseUrl;
|
|
35
29
|
webhookUrl;
|
|
36
30
|
static async run(options) {
|
|
@@ -39,6 +33,14 @@ class GithubCreateAppServer {
|
|
|
39
33
|
const server = new GithubCreateAppServer(actionUrl, options.permissions);
|
|
40
34
|
return server.start();
|
|
41
35
|
}
|
|
36
|
+
actionUrl;
|
|
37
|
+
permissions;
|
|
38
|
+
constructor(actionUrl, permissions) {
|
|
39
|
+
this.actionUrl = actionUrl;
|
|
40
|
+
this.permissions = permissions;
|
|
41
|
+
const webhookId = crypto__default.default.randomBytes(15).toString("base64").replace(/[\+\/]/g, "");
|
|
42
|
+
this.webhookUrl = `https://smee.io/${webhookId}`;
|
|
43
|
+
}
|
|
42
44
|
async start() {
|
|
43
45
|
const app = express__default.default();
|
|
44
46
|
app.get("/", this.formHandler);
|
|
@@ -9,6 +9,7 @@ const defaultTemplates = [
|
|
|
9
9
|
"@backstage/cli/templates/plugin-common-library",
|
|
10
10
|
"@backstage/cli/templates/web-library",
|
|
11
11
|
"@backstage/cli/templates/node-library",
|
|
12
|
+
"@backstage/cli/templates/catalog-provider-module",
|
|
12
13
|
"@backstage/cli/templates/scaffolder-backend-module"
|
|
13
14
|
];
|
|
14
15
|
|
|
@@ -6,6 +6,7 @@ var paths = require('../../../../lib/paths.cjs.js');
|
|
|
6
6
|
var errors = require('@backstage/errors');
|
|
7
7
|
var cliNode = require('@backstage/cli-node');
|
|
8
8
|
var PortableTemplater = require('./PortableTemplater.cjs.js');
|
|
9
|
+
var cliCommon = require('@backstage/cli-common');
|
|
9
10
|
|
|
10
11
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
11
12
|
|
|
@@ -42,7 +43,12 @@ async function writeTemplateContents(template, input) {
|
|
|
42
43
|
);
|
|
43
44
|
}
|
|
44
45
|
for (const file of template.files) {
|
|
45
|
-
const destPath = path.resolve(targetDir, file.path);
|
|
46
|
+
const destPath = path.resolve(targetDir, templater.template(file.path));
|
|
47
|
+
if (!cliCommon.isChildPath(targetDir, destPath)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Path ${destPath} is outside of target directory ${targetDir}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
46
52
|
await fs__default.default.ensureDir(path.dirname(destPath));
|
|
47
53
|
let content = file.syntax === "handlebars" ? templater.template(file.content) : file.content;
|
|
48
54
|
if (file.path === "package.json") {
|
|
@@ -40,6 +40,12 @@ const pkgJsonWithNewConfigSchema = z.z.object({
|
|
|
40
40
|
}).optional()
|
|
41
41
|
}).optional()
|
|
42
42
|
});
|
|
43
|
+
function computePackageNamePluginInfix(packageNamePrefix, namePluginInfix) {
|
|
44
|
+
const packageNamePluginInfix = namePluginInfix ?? (packageNamePrefix.includes("backstage") ? defaults.packageNamePluginInfix : "backstage-plugin-");
|
|
45
|
+
return {
|
|
46
|
+
packageNamePluginInfix
|
|
47
|
+
};
|
|
48
|
+
}
|
|
43
49
|
async function loadPortableTemplateConfig(options = {}) {
|
|
44
50
|
const { overrides = {} } = options;
|
|
45
51
|
const pkgPath = options.packagePath ?? paths.paths.resolveTargetRoot("package.json");
|
|
@@ -77,6 +83,11 @@ async function loadPortableTemplateConfig(options = {}) {
|
|
|
77
83
|
}
|
|
78
84
|
templateNameConflicts.set(pointer.name, rawPointer);
|
|
79
85
|
}
|
|
86
|
+
const packageNamePrefix = overrides.packageNamePrefix ?? config?.globals?.namePrefix ?? defaults.packageNamePrefix;
|
|
87
|
+
const { packageNamePluginInfix } = computePackageNamePluginInfix(
|
|
88
|
+
packageNamePrefix,
|
|
89
|
+
overrides.packageNamePluginInfix ?? config?.globals?.namePluginInfix
|
|
90
|
+
);
|
|
80
91
|
return {
|
|
81
92
|
isUsingDefaultTemplates: !config?.templates,
|
|
82
93
|
templatePointers: templatePointerEntries.map(({ pointer }) => pointer),
|
|
@@ -84,8 +95,8 @@ async function loadPortableTemplateConfig(options = {}) {
|
|
|
84
95
|
version: overrides.version ?? config?.globals?.version ?? defaults.version,
|
|
85
96
|
private: overrides.private ?? config?.globals?.private ?? defaults.private,
|
|
86
97
|
publishRegistry: overrides.publishRegistry ?? config?.globals?.publishRegistry ?? defaults.publishRegistry,
|
|
87
|
-
packageNamePrefix
|
|
88
|
-
packageNamePluginInfix
|
|
98
|
+
packageNamePrefix,
|
|
99
|
+
packageNamePluginInfix
|
|
89
100
|
};
|
|
90
101
|
}
|
|
91
102
|
function resolveLocalTemplatePath(pointer, basePath) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/cli",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.5-next.1",
|
|
4
4
|
"description": "CLI for developing Backstage plugins and apps",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "cli"
|
|
@@ -47,16 +47,16 @@
|
|
|
47
47
|
]
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@backstage/catalog-model": "
|
|
51
|
-
"@backstage/cli-common": "
|
|
52
|
-
"@backstage/cli-node": "
|
|
53
|
-
"@backstage/config": "
|
|
54
|
-
"@backstage/config-loader": "
|
|
55
|
-
"@backstage/errors": "
|
|
56
|
-
"@backstage/eslint-plugin": "
|
|
57
|
-
"@backstage/integration": "
|
|
58
|
-
"@backstage/release-manifests": "
|
|
59
|
-
"@backstage/types": "
|
|
50
|
+
"@backstage/catalog-model": "1.7.6-next.0",
|
|
51
|
+
"@backstage/cli-common": "0.1.15",
|
|
52
|
+
"@backstage/cli-node": "0.2.15-next.0",
|
|
53
|
+
"@backstage/config": "1.3.6-next.0",
|
|
54
|
+
"@backstage/config-loader": "1.10.6-next.0",
|
|
55
|
+
"@backstage/errors": "1.2.7",
|
|
56
|
+
"@backstage/eslint-plugin": "0.2.0-next.0",
|
|
57
|
+
"@backstage/integration": "1.18.2-next.0",
|
|
58
|
+
"@backstage/release-manifests": "0.0.13",
|
|
59
|
+
"@backstage/types": "1.2.2",
|
|
60
60
|
"@manypkg/get-packages": "^1.1.3",
|
|
61
61
|
"@module-federation/enhanced": "^0.9.0",
|
|
62
62
|
"@octokit/request": "^8.0.0",
|
|
@@ -151,22 +151,22 @@
|
|
|
151
151
|
"zod-validation-error": "^3.4.0"
|
|
152
152
|
},
|
|
153
153
|
"devDependencies": {
|
|
154
|
-
"@backstage/backend-plugin-api": "
|
|
155
|
-
"@backstage/backend-test-utils": "
|
|
156
|
-
"@backstage/catalog-client": "
|
|
157
|
-
"@backstage/config": "
|
|
158
|
-
"@backstage/core-app-api": "
|
|
159
|
-
"@backstage/core-components": "
|
|
160
|
-
"@backstage/core-plugin-api": "
|
|
161
|
-
"@backstage/dev-utils": "
|
|
162
|
-
"@backstage/errors": "
|
|
163
|
-
"@backstage/plugin-auth-backend": "
|
|
164
|
-
"@backstage/plugin-auth-backend-module-guest-provider": "
|
|
165
|
-
"@backstage/plugin-catalog-node": "
|
|
166
|
-
"@backstage/plugin-scaffolder-node": "
|
|
167
|
-
"@backstage/plugin-scaffolder-node-test-utils": "
|
|
168
|
-
"@backstage/test-utils": "
|
|
169
|
-
"@backstage/theme": "
|
|
154
|
+
"@backstage/backend-plugin-api": "1.5.0-next.1",
|
|
155
|
+
"@backstage/backend-test-utils": "1.10.0-next.1",
|
|
156
|
+
"@backstage/catalog-client": "1.12.1-next.0",
|
|
157
|
+
"@backstage/config": "1.3.6-next.0",
|
|
158
|
+
"@backstage/core-app-api": "1.19.2-next.1",
|
|
159
|
+
"@backstage/core-components": "0.18.3-next.1",
|
|
160
|
+
"@backstage/core-plugin-api": "1.11.2-next.1",
|
|
161
|
+
"@backstage/dev-utils": "1.1.17-next.1",
|
|
162
|
+
"@backstage/errors": "1.2.7",
|
|
163
|
+
"@backstage/plugin-auth-backend": "0.25.6-next.1",
|
|
164
|
+
"@backstage/plugin-auth-backend-module-guest-provider": "0.2.14-next.1",
|
|
165
|
+
"@backstage/plugin-catalog-node": "1.20.0-next.1",
|
|
166
|
+
"@backstage/plugin-scaffolder-node": "0.12.1-next.1",
|
|
167
|
+
"@backstage/plugin-scaffolder-node-test-utils": "0.3.5-next.1",
|
|
168
|
+
"@backstage/test-utils": "1.7.13-next.0",
|
|
169
|
+
"@backstage/theme": "0.7.0",
|
|
170
170
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
|
|
171
171
|
"@types/cross-spawn": "^6.0.2",
|
|
172
172
|
"@types/ejs": "^3.1.3",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SchedulerServiceTaskScheduleDefinitionConfig } from '@backstage/backend-plugin-api';
|
|
2
|
+
|
|
3
|
+
export interface Config {
|
|
4
|
+
catalog?: {
|
|
5
|
+
providers?: {
|
|
6
|
+
/**
|
|
7
|
+
* {{providerClass}} configuration.
|
|
8
|
+
*/
|
|
9
|
+
{{providerVar}}?:
|
|
10
|
+
| {
|
|
11
|
+
/**
|
|
12
|
+
* The target that this provider should consume.
|
|
13
|
+
*/
|
|
14
|
+
target: string;
|
|
15
|
+
/**
|
|
16
|
+
* Overrides the schedule at which this provider runs.
|
|
17
|
+
*/
|
|
18
|
+
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
[name: string]: {
|
|
22
|
+
/**
|
|
23
|
+
* The target that this provider should consume.
|
|
24
|
+
*/
|
|
25
|
+
target: string;
|
|
26
|
+
/**
|
|
27
|
+
* Overrides the schedule at which this provider runs.
|
|
28
|
+
*/
|
|
29
|
+
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{packageName}}",
|
|
3
|
+
"description": "The {{fullModuleId}} module for @backstage/plugin-catalog-backend",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"types": "src/index.ts",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public",
|
|
8
|
+
"main": "dist/index.cjs.js",
|
|
9
|
+
"types": "dist/index.d.ts"
|
|
10
|
+
},
|
|
11
|
+
"backstage": {
|
|
12
|
+
"role": "backend-plugin-module",
|
|
13
|
+
"pluginId": "catalog",
|
|
14
|
+
"pluginPackage": "@backstage/plugin-catalog-backend"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"start": "backstage-cli package start",
|
|
18
|
+
"build": "backstage-cli package build",
|
|
19
|
+
"lint": "backstage-cli package lint",
|
|
20
|
+
"test": "backstage-cli package test",
|
|
21
|
+
"clean": "backstage-cli package clean",
|
|
22
|
+
"prepack": "backstage-cli package prepack",
|
|
23
|
+
"postpack": "backstage-cli package postpack"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@backstage/backend-plugin-api": "{{versionQuery '@backstage/backend-plugin-api'}}",
|
|
27
|
+
"@backstage/plugin-catalog-node": "{{versionQuery '@backstage/plugin-catalog-node'}}"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@backstage/cli": "{{versionQuery '@backstage/cli'}}",
|
|
31
|
+
"@backstage/backend-test-utils": "{{versionQuery '@backstage/backend-test-utils'}}"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
name: catalog-provider-module
|
|
2
|
+
role: backend-plugin-module
|
|
3
|
+
description: An Entity Provider module for the Software Catalog
|
|
4
|
+
values:
|
|
5
|
+
pluginId: catalog
|
|
6
|
+
fullModuleId: '{{ moduleId }}-provider'
|
|
7
|
+
moduleVar: '{{ camelCase pluginId }}Module{{ upperFirst ( camelCase moduleId ) }}'
|
|
8
|
+
providerVar: '{{ camelCase moduleId }}Provider'
|
|
9
|
+
providerClass: '{{ upperFirst ( camelCase moduleId ) }}Provider'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
coreServices,
|
|
3
|
+
createBackendModule,
|
|
4
|
+
} from '@backstage/backend-plugin-api';
|
|
5
|
+
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
|
|
6
|
+
import { {{providerClass}} } from './provider/{{providerClass}}';
|
|
7
|
+
|
|
8
|
+
export const {{moduleVar}} = createBackendModule({
|
|
9
|
+
moduleId: '{{fullModuleId}}',
|
|
10
|
+
pluginId: '{{pluginId}}',
|
|
11
|
+
register({ registerInit }) {
|
|
12
|
+
registerInit({
|
|
13
|
+
deps: {
|
|
14
|
+
logger: coreServices.logger,
|
|
15
|
+
config: coreServices.rootConfig,
|
|
16
|
+
scheduler: coreServices.scheduler,
|
|
17
|
+
processing: catalogProcessingExtensionPoint,
|
|
18
|
+
},
|
|
19
|
+
async init({ logger, scheduler, config, processing }) {
|
|
20
|
+
processing.addEntityProvider(
|
|
21
|
+
{{providerClass}}.fromConfig(config, {
|
|
22
|
+
logger,
|
|
23
|
+
scheduler,
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
})
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readSchedulerServiceTaskScheduleDefinitionFromConfig,
|
|
3
|
+
SchedulerServiceTaskScheduleDefinition,
|
|
4
|
+
} from '@backstage/backend-plugin-api';
|
|
5
|
+
import { Config } from '@backstage/config';
|
|
6
|
+
|
|
7
|
+
const DEFAULT_PROVIDER_ID = 'default';
|
|
8
|
+
const DEFAULT_SCHEDULE: SchedulerServiceTaskScheduleDefinition = {
|
|
9
|
+
frequency: {
|
|
10
|
+
minutes: 30,
|
|
11
|
+
},
|
|
12
|
+
timeout: {
|
|
13
|
+
minutes: 3,
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type {{providerClass}}ProviderConfig = {
|
|
18
|
+
id: string;
|
|
19
|
+
target: string;
|
|
20
|
+
schedule: SchedulerServiceTaskScheduleDefinition;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Parses all configured providers.
|
|
25
|
+
*
|
|
26
|
+
* @param config - The root of the provider config hierarchy
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export function readProviderConfigs(
|
|
31
|
+
config: Config,
|
|
32
|
+
): {{providerClass}}ProviderConfig[] {
|
|
33
|
+
const providersConfig = config.getOptionalConfig(
|
|
34
|
+
'catalog.providers.{{providerVar}}',
|
|
35
|
+
);
|
|
36
|
+
if (!providersConfig) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if ((providersConfig).has('target')) {
|
|
41
|
+
// simple/single config variant
|
|
42
|
+
return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return providersConfig.keys().map(id => {
|
|
46
|
+
const providerConfig = providersConfig.getConfig(id);
|
|
47
|
+
|
|
48
|
+
return readProviderConfig(id, providerConfig);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Parses a single configured provider by id.
|
|
54
|
+
*
|
|
55
|
+
* @param id - the id of the provider to parse
|
|
56
|
+
* @param config - The root of the provider config hierarchy
|
|
57
|
+
*
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
export function readProviderConfig(
|
|
61
|
+
id: string,
|
|
62
|
+
config: Config,
|
|
63
|
+
): {{providerClass}}ProviderConfig {
|
|
64
|
+
|
|
65
|
+
const target = config.getString('target');
|
|
66
|
+
|
|
67
|
+
const schedule = config.has('schedule')
|
|
68
|
+
? readSchedulerServiceTaskScheduleDefinitionFromConfig(
|
|
69
|
+
config.getConfig('schedule'),
|
|
70
|
+
)
|
|
71
|
+
: DEFAULT_SCHEDULE;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
id,
|
|
75
|
+
target,
|
|
76
|
+
schedule,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { {{providerClass}} } from './{{providerClass}}';
|
|
2
|
+
import { mockServices } from '@backstage/backend-test-utils';
|
|
3
|
+
|
|
4
|
+
describe('{{providerClass}}', () => {
|
|
5
|
+
it('should read entities from the target', async () => {
|
|
6
|
+
const logger = mockServices.logger.mock();
|
|
7
|
+
const provider = new {{providerClass}}({
|
|
8
|
+
id: 'test',
|
|
9
|
+
target: 'https://example.com',
|
|
10
|
+
logger: mockServices.logger.mock(),
|
|
11
|
+
taskRunner: { run: jest.fn() },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const entities = await provider.read({ logger });
|
|
15
|
+
|
|
16
|
+
expect(entities).toEqual([]);
|
|
17
|
+
});
|
|
18
|
+
})
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Config } from '@backstage/config';
|
|
2
|
+
import {
|
|
3
|
+
DeferredEntity,
|
|
4
|
+
EntityProvider,
|
|
5
|
+
EntityProviderConnection,
|
|
6
|
+
} from '@backstage/plugin-catalog-node';
|
|
7
|
+
import * as uuid from 'uuid';
|
|
8
|
+
import { readProviderConfigs } from './readProviderConfigs';
|
|
9
|
+
import {
|
|
10
|
+
LoggerService,
|
|
11
|
+
SchedulerService,
|
|
12
|
+
SchedulerServiceTaskRunner,
|
|
13
|
+
} from '@backstage/backend-plugin-api';
|
|
14
|
+
|
|
15
|
+
export type {{providerClass}}Options = {
|
|
16
|
+
/**
|
|
17
|
+
* The logger to use.
|
|
18
|
+
*/
|
|
19
|
+
logger: LoggerService;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Scheduler used to schedule refreshes based on
|
|
23
|
+
* the schedule config.
|
|
24
|
+
*/
|
|
25
|
+
scheduler: SchedulerService;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export class {{providerClass}} implements EntityProvider {
|
|
29
|
+
static fromConfig(
|
|
30
|
+
configRoot: Config,
|
|
31
|
+
options: {{providerClass}}Options,
|
|
32
|
+
): {{providerClass}}[] {
|
|
33
|
+
return readProviderConfigs(configRoot).map(providerConfig => {
|
|
34
|
+
return new {{providerClass}}({
|
|
35
|
+
id: providerConfig.id,
|
|
36
|
+
target: providerConfig.target,
|
|
37
|
+
logger: options.logger,
|
|
38
|
+
taskRunner: options.scheduler.createScheduledTaskRunner(
|
|
39
|
+
providerConfig.schedule,
|
|
40
|
+
),
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
readonly #id: string;
|
|
46
|
+
readonly #target: string;
|
|
47
|
+
readonly #logger: LoggerService;
|
|
48
|
+
readonly #taskRunner: SchedulerServiceTaskRunner;
|
|
49
|
+
|
|
50
|
+
constructor(options: {
|
|
51
|
+
id: string;
|
|
52
|
+
target: string;
|
|
53
|
+
logger: LoggerService;
|
|
54
|
+
taskRunner: SchedulerServiceTaskRunner;
|
|
55
|
+
}) {
|
|
56
|
+
this.#id = options.id;
|
|
57
|
+
this.#target = options.target;
|
|
58
|
+
this.#logger = options.logger;
|
|
59
|
+
this.#taskRunner = options.taskRunner;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.getProviderName} */
|
|
63
|
+
getProviderName() {
|
|
64
|
+
return `{{providerClass}}:${this.#id}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.connect} */
|
|
68
|
+
async connect(connection: EntityProviderConnection) {
|
|
69
|
+
const id = `${this.getProviderName()}:refresh`;
|
|
70
|
+
|
|
71
|
+
// Schedule a refresh task to be run periodically
|
|
72
|
+
await this.#taskRunner.run({
|
|
73
|
+
id,
|
|
74
|
+
fn: async () => {
|
|
75
|
+
const logger = this.#logger.child({
|
|
76
|
+
taskId: id,
|
|
77
|
+
taskInstanceId: uuid.v4(),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const entities = await this.read({ logger });
|
|
82
|
+
|
|
83
|
+
logger.info(`Read ${entities.length} entities`);
|
|
84
|
+
|
|
85
|
+
await connection.applyMutation({
|
|
86
|
+
type: 'full',
|
|
87
|
+
entities,
|
|
88
|
+
});
|
|
89
|
+
} catch (error) {
|
|
90
|
+
logger.error(`Refresh failed`, error);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Reads entities to be added to the catalog.
|
|
98
|
+
*/
|
|
99
|
+
async read(options: { logger: LoggerService }): Promise<DeferredEntity[]> {
|
|
100
|
+
const { logger } = options;
|
|
101
|
+
|
|
102
|
+
logger.info(`Reading entities from ${this.#target}`);
|
|
103
|
+
|
|
104
|
+
// TODO: Implement entity reading logic from the target
|
|
105
|
+
const entities: DeferredEntity[] = [];
|
|
106
|
+
|
|
107
|
+
return entities;
|
|
108
|
+
}
|
|
109
|
+
}
|