@backstage/cli 0.34.4-next.3 → 0.34.5-next.0

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/dist/lib/versioning/Lockfile.cjs.js +8 -5
  3. package/dist/modules/create-github-app/commands/create-github-app/GithubCreateAppServer.cjs.js +8 -6
  4. package/dist/modules/migrate/commands/versions/bump.cjs.js +15 -9
  5. package/dist/modules/new/lib/defaultTemplates.cjs.js +1 -0
  6. package/dist/modules/new/lib/execution/writeTemplateContents.cjs.js +7 -1
  7. package/dist/packages/backend-defaults/package.json.cjs.js +1 -1
  8. package/dist/packages/backend-plugin-api/package.json.cjs.js +1 -1
  9. package/dist/packages/backend-test-utils/package.json.cjs.js +1 -1
  10. package/dist/packages/catalog-client/package.json.cjs.js +1 -1
  11. package/dist/packages/cli/package.json.cjs.js +1 -1
  12. package/dist/packages/config/package.json.cjs.js +1 -1
  13. package/dist/packages/core-app-api/package.json.cjs.js +1 -1
  14. package/dist/packages/core-components/package.json.cjs.js +1 -1
  15. package/dist/packages/core-plugin-api/package.json.cjs.js +1 -1
  16. package/dist/packages/dev-utils/package.json.cjs.js +1 -1
  17. package/dist/packages/frontend-defaults/package.json.cjs.js +1 -1
  18. package/dist/packages/frontend-plugin-api/package.json.cjs.js +1 -1
  19. package/dist/packages/frontend-test-utils/package.json.cjs.js +1 -1
  20. package/dist/packages/test-utils/package.json.cjs.js +1 -1
  21. package/dist/packages/theme/package.json.cjs.js +1 -1
  22. package/dist/plugins/auth-backend/package.json.cjs.js +1 -1
  23. package/dist/plugins/auth-backend-module-guest-provider/package.json.cjs.js +1 -1
  24. package/dist/plugins/catalog-node/package.json.cjs.js +1 -1
  25. package/dist/plugins/scaffolder-node/package.json.cjs.js +1 -1
  26. package/dist/plugins/scaffolder-node-test-utils/package.json.cjs.js +1 -1
  27. package/package.json +22 -22
  28. package/templates/catalog-provider-module/.eslintrc.js.hbs +1 -0
  29. package/templates/catalog-provider-module/README.md.hbs +5 -0
  30. package/templates/catalog-provider-module/config.d.ts.hbs +34 -0
  31. package/templates/catalog-provider-module/package.json.hbs +36 -0
  32. package/templates/catalog-provider-module/portable-template.yaml +9 -0
  33. package/templates/catalog-provider-module/src/index.ts.hbs +8 -0
  34. package/templates/catalog-provider-module/src/module.ts.hbs +29 -0
  35. package/templates/catalog-provider-module/src/provider/readProviderConfigs.ts.hbs +78 -0
  36. package/templates/catalog-provider-module/src/provider/{{providerClass}}.test.ts.hbs +18 -0
  37. package/templates/catalog-provider-module/src/provider/{{providerClass}}.ts.hbs +109 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # @backstage/cli
2
2
 
3
+ ## 0.34.5-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - fc7cbfc: The templates executed with the `yarn new` command now supports templating filenames.
8
+ - 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`.
9
+ - 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.
10
+ - Updated dependencies
11
+ - @backstage/eslint-plugin@0.2.0-next.0
12
+ - @backstage/config-loader@1.10.6-next.0
13
+ - @backstage/config@1.3.6-next.0
14
+ - @backstage/cli-node@0.2.15-next.0
15
+ - @backstage/catalog-model@1.7.6-next.0
16
+ - @backstage/integration@1.18.2-next.0
17
+ - @backstage/cli-common@0.1.15
18
+ - @backstage/errors@1.2.7
19
+ - @backstage/release-manifests@0.0.13
20
+ - @backstage/types@1.2.2
21
+
22
+ ## 0.34.4
23
+
24
+ ### Patch Changes
25
+
26
+ - f2cf564: Removed the script transform cache from the default Jest configuration. The script cache provided a moderate performance boost, but it is incompatible with Jest 30.
27
+ - 33faad2: Allow using custom manifest location in the yarn plugin and version bump.
28
+
29
+ The Backstage yarn plugin and version bump allows two new environment variables to configure custom manifest location:
30
+
31
+ - `BACKSTAGE_VERSIONS_BASE_URL`: The base URL for fetching the Backstage version
32
+ manifest. Defaults to `https://versions.backstage.io/v1/releases/VERSION/manifest.json`.
33
+ Useful for running the plugin in environment without direct access to the internet,
34
+ for example by using a mirror of the versions API or a proxy.
35
+ Note that the environment variable is just the host name, and the path is appended by
36
+ the plugin. If you are using the yarn plugin, bump version command will also try
37
+ to fetch the new version of the yarn plugin from the same base URL (defaults to
38
+ `https://versions.backstage.io/v1/releases/RELEASE/yarn-plugin`)
39
+ - `BACKSTAGE_MANIFEST_FILE`: Path to a local manifest file. If set, the plugin
40
+ will not attempt to fetch the manifest from the network. Useful for running
41
+ the plugin in environment without internet access and without mirror of the
42
+ versions API.
43
+
44
+ - 6ebc1ea: Fixed module federation config by only setting `import: false` on shared libraries for remote.
45
+ - ab96bb7: Added a new `--entrypoint` option to the `package start` command, which allows you to specify a custom entry directory/file for development applications. This is particularly useful when maintaining separate dev apps for different versions of your plugin (e.g., stable and alpha).
46
+
47
+ **Example usage:**
48
+
49
+ Consider the following plugin dev folder structure:
50
+
51
+ ```
52
+ dev/
53
+ index.tsx
54
+ alpha/
55
+ index.ts
56
+ ```
57
+
58
+ - The default `yarn package start` command uses the `dev/` folder as the entry point and executes `dev/index.tsx` file;
59
+ - Running `yarn package start --entrypoint dev/alpha` will instead use `dev/alpha/` as the entry point and execute `dev/alpha/index.ts` file.
60
+
61
+ - 024645e: Remove unused @octokit modules from cli package
62
+
63
+ - @octokit/graphql
64
+ - @octokit/graphql-schema
65
+ - @octokit/oauth-app
66
+
67
+ - d14ef24: Added automatic detection and support for the Backstage Yarn plugin when generating new packages with `yarn new`. When the plugin is installed, new packages will automatically use `backstage:^` ranges for `@backstage/*` dependencies.
68
+ - Updated dependencies
69
+ - @backstage/eslint-plugin@0.1.12
70
+ - @backstage/integration@1.18.1
71
+ - @backstage/config-loader@1.10.5
72
+ - @backstage/config@1.3.5
73
+
3
74
  ## 0.34.4-next.3
4
75
 
5
76
  ### 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);
@@ -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);
@@ -2,6 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var process$1 = require('process');
5
6
  var fs = require('fs-extra');
6
7
  var chalk = require('chalk');
7
8
  var minimatch = require('minimatch');
@@ -65,7 +66,12 @@ var bump = async (opts) => {
65
66
  }
66
67
  let findTargetVersion;
67
68
  let releaseManifest;
68
- if (semver__default.default.valid(opts.release)) {
69
+ if (process$1.env.BACKSTAGE_MANIFEST_FILE) {
70
+ releaseManifest = await fs__default.default.readJson(process$1.env.BACKSTAGE_MANIFEST_FILE);
71
+ findTargetVersion = createStrictVersionFinder({
72
+ releaseManifest
73
+ });
74
+ } else if (semver__default.default.valid(opts.release)) {
69
75
  releaseManifest = await releaseManifests.getManifestByVersion({ version: opts.release });
70
76
  findTargetVersion = createStrictVersionFinder({
71
77
  releaseManifest
@@ -73,15 +79,18 @@ var bump = async (opts) => {
73
79
  } else {
74
80
  if (opts.release === "next") {
75
81
  const next = await releaseManifests.getManifestByReleaseLine({
76
- releaseLine: "next"
82
+ releaseLine: "next",
83
+ versionsBaseUrl: process$1.env.BACKSTAGE_VERSIONS_BASE_URL
77
84
  });
78
85
  const main = await releaseManifests.getManifestByReleaseLine({
79
- releaseLine: "main"
86
+ releaseLine: "main",
87
+ versionsBaseUrl: process$1.env.BACKSTAGE_VERSIONS_BASE_URL
80
88
  });
81
89
  releaseManifest = semver__default.default.gt(next.releaseVersion, main.releaseVersion) ? next : main;
82
90
  } else {
83
91
  releaseManifest = await releaseManifests.getManifestByReleaseLine({
84
- releaseLine: opts.release
92
+ releaseLine: opts.release,
93
+ versionsBaseUrl: process$1.env.BACKSTAGE_VERSIONS_BASE_URL
85
94
  });
86
95
  }
87
96
  findTargetVersion = createVersionFinder({
@@ -95,11 +104,8 @@ var bump = async (opts) => {
95
104
  `Updating yarn plugin to v${releaseManifest.releaseVersion}...`
96
105
  );
97
106
  console.log();
98
- await run.run("yarn", [
99
- "plugin",
100
- "import",
101
- `https://versions.backstage.io/v1/releases/${releaseManifest.releaseVersion}/yarn-plugin`
102
- ]);
107
+ const yarnPluginUrl = process$1.env.BACKSTAGE_VERSIONS_BASE_URL ? `${process$1.env.BACKSTAGE_VERSIONS_BASE_URL}/v1/releases/${releaseManifest.releaseVersion}/yarn-plugin` : `https://versions.backstage.io/v1/releases/${releaseManifest.releaseVersion}/yarn-plugin`;
108
+ await run.run("yarn", ["plugin", "import", yarnPluginUrl]);
103
109
  console.log();
104
110
  }
105
111
  const dependencyMap = await packages.mapDependencies(paths.paths.targetDir, pattern);
@@ -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") {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.13.0-next.2";
3
+ var version = "0.13.1-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.4.4-next.0";
3
+ var version = "1.4.5-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.9.1-next.1";
3
+ var version = "1.10.0-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.12.0";
3
+ var version = "1.12.1-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.34.4-next.3";
3
+ var version = "0.34.5-next.0";
4
4
  var dependencies = {
5
5
  "@backstage/catalog-model": "workspace:^",
6
6
  "@backstage/cli-common": "workspace:^",
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.3.5-next.0";
3
+ var version = "1.3.6-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.19.1-next.0";
3
+ var version = "1.19.2-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.18.2-next.3";
3
+ var version = "0.18.3-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.11.1-next.0";
3
+ var version = "1.11.2-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.1.15-next.2";
3
+ var version = "1.1.17-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.3.2-next.1";
3
+ var version = "0.3.3-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.12.1-next.2";
3
+ var version = "0.12.2-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.3.7-next.1";
3
+ var version = "0.4.1-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.7.12-next.1";
3
+ var version = "1.7.13-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.6.9-next.0";
3
+ var version = "0.7.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.25.5-next.0";
3
+ var version = "0.25.6-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.2.13-next.0";
3
+ var version = "0.2.14-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.19.1-next.0";
3
+ var version = "1.19.2-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.12.0-next.1";
3
+ var version = "0.12.1-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.3.4-next.1";
3
+ var version = "0.3.5-next.0";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/cli",
3
- "version": "0.34.4-next.3",
3
+ "version": "0.34.5-next.0",
4
4
  "description": "CLI for developing Backstage plugins and apps",
5
5
  "backstage": {
6
6
  "role": "cli"
@@ -47,14 +47,14 @@
47
47
  ]
48
48
  },
49
49
  "dependencies": {
50
- "@backstage/catalog-model": "1.7.5",
50
+ "@backstage/catalog-model": "1.7.6-next.0",
51
51
  "@backstage/cli-common": "0.1.15",
52
- "@backstage/cli-node": "0.2.14",
53
- "@backstage/config": "1.3.5-next.0",
54
- "@backstage/config-loader": "1.10.5-next.0",
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
55
  "@backstage/errors": "1.2.7",
56
- "@backstage/eslint-plugin": "0.1.11",
57
- "@backstage/integration": "1.18.1-next.1",
56
+ "@backstage/eslint-plugin": "0.2.0-next.0",
57
+ "@backstage/integration": "1.18.2-next.0",
58
58
  "@backstage/release-manifests": "0.0.13",
59
59
  "@backstage/types": "1.2.2",
60
60
  "@manypkg/get-packages": "^1.1.3",
@@ -151,22 +151,22 @@
151
151
  "zod-validation-error": "^3.4.0"
152
152
  },
153
153
  "devDependencies": {
154
- "@backstage/backend-plugin-api": "1.4.4-next.0",
155
- "@backstage/backend-test-utils": "1.9.1-next.1",
156
- "@backstage/catalog-client": "1.12.0",
157
- "@backstage/config": "1.3.5-next.0",
158
- "@backstage/core-app-api": "1.19.1-next.0",
159
- "@backstage/core-components": "0.18.2-next.3",
160
- "@backstage/core-plugin-api": "1.11.1-next.0",
161
- "@backstage/dev-utils": "1.1.15-next.2",
154
+ "@backstage/backend-plugin-api": "1.4.5-next.0",
155
+ "@backstage/backend-test-utils": "1.10.0-next.0",
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.0",
159
+ "@backstage/core-components": "0.18.3-next.0",
160
+ "@backstage/core-plugin-api": "1.11.2-next.0",
161
+ "@backstage/dev-utils": "1.1.17-next.0",
162
162
  "@backstage/errors": "1.2.7",
163
- "@backstage/plugin-auth-backend": "0.25.5-next.0",
164
- "@backstage/plugin-auth-backend-module-guest-provider": "0.2.13-next.0",
165
- "@backstage/plugin-catalog-node": "1.19.1-next.0",
166
- "@backstage/plugin-scaffolder-node": "0.12.0-next.1",
167
- "@backstage/plugin-scaffolder-node-test-utils": "0.3.4-next.1",
168
- "@backstage/test-utils": "1.7.12-next.1",
169
- "@backstage/theme": "0.6.9-next.0",
163
+ "@backstage/plugin-auth-backend": "0.25.6-next.0",
164
+ "@backstage/plugin-auth-backend-module-guest-provider": "0.2.14-next.0",
165
+ "@backstage/plugin-catalog-node": "1.19.2-next.0",
166
+ "@backstage/plugin-scaffolder-node": "0.12.1-next.0",
167
+ "@backstage/plugin-scaffolder-node-test-utils": "0.3.5-next.0",
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,5 @@
1
+ # {{packageName}}
2
+
3
+ The {{fullModuleId}} module for [@backstage/plugin-catalog-backend](https://www.npmjs.com/package/@backstage/plugin-catalog-backend).
4
+
5
+ _This plugin was created through the Backstage CLI_
@@ -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,8 @@
1
+ /***/
2
+ /**
3
+ * The {{fullModuleId}} module for @backstage/plugin-catalog-backend
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+
8
+ export { {{moduleVar}} as default } from './module';
@@ -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
+ }