@backstage/plugin-catalog-backend-module-unprocessed 0.0.0-nightly-20230531023430

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 ADDED
@@ -0,0 +1,27 @@
1
+ # @backstage/plugin-catalog-backend-module-unprocessed
2
+
3
+ ## 0.0.0-nightly-20230531023430
4
+
5
+ ### Minor Changes
6
+
7
+ - d44fcd9829c2: Added a new plugin to expose entities which are unprocessed or have errors processing
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/backend-plugin-api@0.0.0-nightly-20230531023430
13
+ - @backstage/catalog-model@0.0.0-nightly-20230531023430
14
+ - @backstage/plugin-auth-node@0.0.0-nightly-20230531023430
15
+
16
+ ## 0.1.0-next.0
17
+
18
+ ### Minor Changes
19
+
20
+ - d44fcd9829c2: Added a new plugin to expose entities which are unprocessed or have errors processing
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies
25
+ - @backstage/backend-plugin-api@0.5.3-next.1
26
+ - @backstage/catalog-model@1.4.0-next.0
27
+ - @backstage/plugin-auth-node@0.2.15-next.1
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @backstage/plugin-catalog-backend-module-unprocessed-node
2
+
3
+ This catalog-backend module adds support for viewing unprocessed entities. An unprocessed entity is one that doesn't show up in the catalog.
4
+
5
+ A distinction is made between `failed` and `pending` entities.
6
+
7
+ A `failed` entity has validation error that breaks processing.
8
+
9
+ A `pending` entity has not been processed yet.
10
+
11
+ ## Installation
12
+
13
+ ### backend
14
+
15
+ In `packages/backend/src/plugins/catalog.ts` import the module and initialize it after invoking `CatalogBuilder.build()`:
16
+
17
+ ```ts
18
+ import { UnprocessedEntitesModule } from '@backstage/plugin-catalog-backend-module-unprocessed';
19
+
20
+ //...
21
+
22
+ const unprocessed = new UnprocessedEntitesModule(
23
+ await env.database.getClient(),
24
+ router,
25
+ env.logger,
26
+ );
27
+ unprocessed.registerRoutes();
28
+ ```
29
+
30
+ ### backend-next
31
+
32
+ In `packages/backend-next/src/index.ts` add the module:
33
+
34
+ ```ts
35
+ backend.add(catalogModuleUnprocessedEntities());
36
+ ```
37
+
38
+ _This plugin was created through the Backstage CLI_
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var backendPluginApi = require('@backstage/backend-plugin-api');
6
+ var Router = require('express-promise-router');
7
+ var pluginAuthNode = require('@backstage/plugin-auth-node');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
12
+
13
+ class UnprocessedEntitesModule {
14
+ constructor(database, router) {
15
+ this.database = database;
16
+ this.router = router;
17
+ this.moduleRouter = Router__default["default"]();
18
+ this.router.use(this.moduleRouter);
19
+ }
20
+ async unprocessed(request) {
21
+ if (request.reason === "pending") {
22
+ return {
23
+ type: "pending",
24
+ entities: await this.pending(request.owner)
25
+ };
26
+ }
27
+ return {
28
+ type: "failed",
29
+ entities: await this.failed(request.owner)
30
+ };
31
+ }
32
+ hydrateRefreshState(r) {
33
+ return {
34
+ ...r,
35
+ unprocessed_entity: JSON.parse(r.unprocessed_entity),
36
+ ...r.processed_entity && {
37
+ processed_entity: JSON.parse(r.processed_entity)
38
+ },
39
+ ...r.errors && { errors: JSON.parse(r.errors) },
40
+ ...r.cache && { cache: JSON.parse(r.cache) }
41
+ };
42
+ }
43
+ async pending(owner) {
44
+ const res = (await this.database("refresh_state.*").from("refresh_state").leftJoin(
45
+ "final_entities",
46
+ "final_entities.entity_id",
47
+ "refresh_state.entity_id"
48
+ ).whereNull("final_entities.entity_id")).map(this.hydrateRefreshState);
49
+ if (owner) {
50
+ return res.filter((r) => {
51
+ var _a;
52
+ return ((_a = r.unprocessed_entity.spec) == null ? void 0 : _a.owner) === owner;
53
+ });
54
+ }
55
+ return res;
56
+ }
57
+ async failed(owner) {
58
+ const res = (await this.database("refresh_state.*").from("refresh_state").rightJoin(
59
+ "final_entities",
60
+ "final_entities.entity_id",
61
+ "refresh_state.entity_id"
62
+ ).whereNull("final_entities.final_entity")).map(this.hydrateRefreshState);
63
+ if (owner) {
64
+ return res.filter((r) => {
65
+ var _a;
66
+ return ((_a = r.unprocessed_entity.spec) == null ? void 0 : _a.owner) === owner;
67
+ });
68
+ }
69
+ return res;
70
+ }
71
+ registerRoutes() {
72
+ this.moduleRouter.get("/entities/unprocessed/failed", async (req, res) => {
73
+ return res.json(
74
+ await this.unprocessed({
75
+ reason: "failed",
76
+ owner: req.query.owner,
77
+ authorizationToken: pluginAuthNode.getBearerTokenFromAuthorizationHeader(
78
+ req.header("authorization")
79
+ )
80
+ })
81
+ );
82
+ }).get("/entities/unprocessed/pending", async (req, res) => {
83
+ return res.json(
84
+ await this.unprocessed({
85
+ reason: "pending",
86
+ owner: req.query.owner,
87
+ authorizationToken: pluginAuthNode.getBearerTokenFromAuthorizationHeader(
88
+ req.header("authorization")
89
+ )
90
+ })
91
+ );
92
+ });
93
+ }
94
+ }
95
+
96
+ const catalogModuleUnprocessedEntities = backendPluginApi.createBackendModule({
97
+ pluginId: "catalog",
98
+ moduleId: "catalogModuleUnprocessedEntities",
99
+ register(env) {
100
+ env.registerInit({
101
+ deps: {
102
+ database: backendPluginApi.coreServices.database,
103
+ router: backendPluginApi.coreServices.httpRouter,
104
+ logger: backendPluginApi.coreServices.logger
105
+ },
106
+ async init({ database, router, logger }) {
107
+ const module = new UnprocessedEntitesModule(
108
+ await database.getClient(),
109
+ router
110
+ );
111
+ module.registerRoutes();
112
+ logger.info(
113
+ "registered additional routes for catalogModuleUnprocessedEntities"
114
+ );
115
+ }
116
+ });
117
+ }
118
+ });
119
+
120
+ exports.UnprocessedEntitesModule = UnprocessedEntitesModule;
121
+ exports.catalogModuleUnprocessedEntities = catalogModuleUnprocessedEntities;
122
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/UnprocessedEntitiesModule.ts","../src/module.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n HydratedRefreshState,\n RefreshState,\n UnprocessedEntitiesRequest,\n UnprocessedEntitiesResponse,\n} from './types';\nimport { Knex } from 'knex';\nimport { HttpRouterService } from '@backstage/backend-plugin-api';\nimport Router from 'express-promise-router';\nimport { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';\n\n/**\n * Module providing Unprocessed Entities API endpoints\n *\n * @public\n */\nexport class UnprocessedEntitesModule {\n private readonly moduleRouter;\n\n constructor(\n private readonly database: Knex,\n private readonly router: HttpRouterService,\n ) {\n this.moduleRouter = Router();\n this.router.use(this.moduleRouter);\n }\n\n private async unprocessed(\n request: UnprocessedEntitiesRequest,\n ): Promise<UnprocessedEntitiesResponse> {\n if (request.reason === 'pending') {\n return {\n type: 'pending',\n entities: await this.pending(request.owner),\n };\n }\n return {\n type: 'failed',\n entities: await this.failed(request.owner),\n };\n }\n\n private hydrateRefreshState(r: RefreshState): HydratedRefreshState {\n return {\n ...r,\n unprocessed_entity: JSON.parse(r.unprocessed_entity),\n ...(r.processed_entity && {\n processed_entity: JSON.parse(r.processed_entity),\n }),\n ...(r.errors && { errors: JSON.parse(r.errors) }),\n ...(r.cache && { cache: JSON.parse(r.cache) }),\n };\n }\n\n private async pending(owner?: string): Promise<HydratedRefreshState[]> {\n const res = (\n await this.database('refresh_state.*')\n .from('refresh_state')\n .leftJoin(\n 'final_entities',\n 'final_entities.entity_id',\n 'refresh_state.entity_id',\n )\n .whereNull('final_entities.entity_id')\n ).map(this.hydrateRefreshState);\n if (owner) {\n return res.filter(r => r.unprocessed_entity.spec?.owner === owner);\n }\n\n return res;\n }\n\n private async failed(owner?: string): Promise<HydratedRefreshState[]> {\n const res = (\n await this.database('refresh_state.*')\n .from('refresh_state')\n .rightJoin(\n 'final_entities',\n 'final_entities.entity_id',\n 'refresh_state.entity_id',\n )\n .whereNull('final_entities.final_entity')\n ).map(this.hydrateRefreshState);\n if (owner) {\n return res.filter(r => r.unprocessed_entity.spec?.owner === owner);\n }\n\n return res;\n }\n\n registerRoutes() {\n this.moduleRouter\n .get('/entities/unprocessed/failed', async (req, res) => {\n return res.json(\n await this.unprocessed({\n reason: 'failed',\n owner: req.query.owner as string,\n authorizationToken: getBearerTokenFromAuthorizationHeader(\n req.header('authorization'),\n ),\n }),\n );\n })\n .get('/entities/unprocessed/pending', async (req, res) => {\n return res.json(\n await this.unprocessed({\n reason: 'pending',\n owner: req.query.owner as string,\n authorizationToken: getBearerTokenFromAuthorizationHeader(\n req.header('authorization'),\n ),\n }),\n );\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { UnprocessedEntitesModule } from './UnprocessedEntitiesModule';\n\n/**\n * Catalog Module for Unprocessed Entities\n *\n * @public\n */\nexport const catalogModuleUnprocessedEntities = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'catalogModuleUnprocessedEntities',\n register(env) {\n env.registerInit({\n deps: {\n database: coreServices.database,\n router: coreServices.httpRouter,\n logger: coreServices.logger,\n },\n async init({ database, router, logger }) {\n const module = new UnprocessedEntitesModule(\n await database.getClient(),\n router,\n );\n\n module.registerRoutes();\n logger.info(\n 'registered additional routes for catalogModuleUnprocessedEntities',\n );\n },\n });\n },\n});\n"],"names":["Router","getBearerTokenFromAuthorizationHeader","createBackendModule","coreServices"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
+ import { HttpRouterService } from '@backstage/backend-plugin-api';
3
+ import { Knex } from 'knex';
4
+
5
+ /**
6
+ * Catalog Module for Unprocessed Entities
7
+ *
8
+ * @public
9
+ */
10
+ declare const catalogModuleUnprocessedEntities: () => _backstage_backend_plugin_api.BackendFeature;
11
+
12
+ /**
13
+ * Module providing Unprocessed Entities API endpoints
14
+ *
15
+ * @public
16
+ */
17
+ declare class UnprocessedEntitesModule {
18
+ private readonly database;
19
+ private readonly router;
20
+ private readonly moduleRouter;
21
+ constructor(database: Knex, router: HttpRouterService);
22
+ private unprocessed;
23
+ private hydrateRefreshState;
24
+ private pending;
25
+ private failed;
26
+ registerRoutes(): void;
27
+ }
28
+
29
+ export { UnprocessedEntitesModule, catalogModuleUnprocessedEntities };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@backstage/plugin-catalog-backend-module-unprocessed",
3
+ "description": "Backstage Catalog module to view unprocessed entities",
4
+ "version": "0.0.0-nightly-20230531023430",
5
+ "main": "dist/index.cjs.js",
6
+ "types": "dist/index.d.ts",
7
+ "license": "Apache-2.0",
8
+ "publishConfig": {
9
+ "access": "public",
10
+ "main": "dist/index.cjs.js",
11
+ "types": "dist/index.d.ts"
12
+ },
13
+ "backstage": {
14
+ "role": "backend-plugin-module"
15
+ },
16
+ "scripts": {
17
+ "build": "backstage-cli package build",
18
+ "lint": "backstage-cli package lint",
19
+ "test": "backstage-cli package test",
20
+ "clean": "backstage-cli package clean",
21
+ "prepack": "backstage-cli package prepack",
22
+ "postpack": "backstage-cli package postpack"
23
+ },
24
+ "devDependencies": {
25
+ "@backstage/cli": "^0.0.0-nightly-20230531023430"
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "dependencies": {
31
+ "@backstage/backend-plugin-api": "^0.0.0-nightly-20230531023430",
32
+ "@backstage/catalog-model": "^0.0.0-nightly-20230531023430",
33
+ "@backstage/plugin-auth-node": "^0.0.0-nightly-20230531023430",
34
+ "express-promise-router": "^4.1.1",
35
+ "knex": "^2.4.2"
36
+ }
37
+ }