@backstage/plugin-catalog-backend 1.26.2-next.2 → 1.27.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @backstage/plugin-catalog-backend
2
2
 
3
+ ## 1.27.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3109c24: The export for the new backend system at the `/alpha` export is now also available via the main entry point, which means that you can remove the `/alpha` suffix from the import.
8
+
9
+ ### Patch Changes
10
+
11
+ - 094eaa3: Remove references to in-repo backend-common
12
+ - 83a8830: Added migration `20241003170511_alter_target_in_locations.js` to change the target column in the `locations` table to TEXT type.
13
+ Added a hash for the key column in the `refresh_keys` table.
14
+ - 62747f8: Fixed a bug where the concurrency limiter for URL reading was not honored
15
+ - c1f9764: Add configuration parameters for deferred stitcher
16
+ - 720a2f9: Updated dependency `git-url-parse` to `^15.0.0`.
17
+ - d1cf90a: Adds the ability to disable catalog processing `catalog.processingInterval: false` in `app-config`
18
+ - f1cab41: Update catalog search table in transaction
19
+ - 8206f49: Fix a bug where etags were expiring too soon in the URL reader
20
+ - Updated dependencies
21
+ - @backstage/plugin-search-backend-module-catalog@0.2.3
22
+ - @backstage/plugin-permission-node@0.8.4
23
+ - @backstage/plugin-events-node@0.4.1
24
+ - @backstage/plugin-catalog-node@1.13.1
25
+ - @backstage/integration@1.15.1
26
+ - @backstage/backend-openapi-utils@0.2.0
27
+ - @backstage/catalog-client@1.7.1
28
+ - @backstage/backend-plugin-api@1.0.1
29
+ - @backstage/catalog-model@1.7.0
30
+ - @backstage/config@1.2.0
31
+ - @backstage/errors@1.2.4
32
+ - @backstage/types@1.1.1
33
+ - @backstage/plugin-catalog-common@1.1.0
34
+ - @backstage/plugin-permission-common@0.8.1
35
+
3
36
  ## 1.26.2-next.2
4
37
 
5
38
  ### Patch Changes
package/README.md CHANGED
@@ -33,7 +33,7 @@ Then add the plugin to your backend, typically in `packages/backend/src/index.ts
33
33
  ```ts
34
34
  const backend = createBackend();
35
35
  // ...
36
- backend.add(import('@backstage/plugin-catalog-backend/alpha'));
36
+ backend.add(import('@backstage/plugin-catalog-backend'));
37
37
  ```
38
38
 
39
39
  #### Old backend system
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend__alpha",
3
- "version": "1.26.2-next.2",
3
+ "version": "1.27.0",
4
4
  "main": "../dist/alpha.cjs.js",
5
5
  "types": "../dist/alpha.d.ts"
6
6
  }
package/config.d.ts CHANGED
@@ -156,11 +156,14 @@ export interface Config {
156
156
  | {
157
157
  /** Defer stitching to be performed asynchronously */
158
158
  mode: 'deferred';
159
+ /** Polling interval for tasks in seconds */
160
+ pollingInterval?: HumanDuration;
161
+ /** How long to wait for a stitch to complete before giving up in seconds */
162
+ stitchTimeout?: HumanDuration;
159
163
  };
160
164
 
161
165
  /**
162
166
  * The interval at which the catalog should process its entities.
163
- *
164
167
  * @remarks
165
168
  *
166
169
  * Example:
@@ -170,6 +173,13 @@ export interface Config {
170
173
  * processingInterval: { minutes: 30 }
171
174
  * ```
172
175
  *
176
+ * or to disabled processing:
177
+ *
178
+ * ```yaml
179
+ * catalog:
180
+ * processingInterval: false
181
+ * ```
182
+ *
173
183
  * Note that this is only a suggested minimum, and the actual interval may
174
184
  * be longer. Internally, the catalog will scale up this number by a small
175
185
  * factor and choose random numbers in that range to spread out the load. If
@@ -181,6 +191,6 @@ export interface Config {
181
191
  * systems that are queried by processors, such as version control systems
182
192
  * housing catalog-info files.
183
193
  */
184
- processingInterval?: HumanDuration;
194
+ processingInterval?: HumanDuration | false;
185
195
  };
186
196
  }
package/dist/alpha.cjs.js CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var CatalogPlugin = require('./service/CatalogPlugin.cjs.js');
5
6
  var conditionExports = require('./permissions/conditionExports.cjs.js');
6
7
  var index = require('./permissions/rules/index.cjs.js');
7
- var CatalogPlugin = require('./service/CatalogPlugin.cjs.js');
8
8
  var util = require('./permissions/rules/util.cjs.js');
9
9
 
10
-
10
+ const _feature = CatalogPlugin.catalogPlugin;
11
11
 
12
12
  exports.catalogConditions = conditionExports.catalogConditions;
13
13
  exports.createCatalogConditionalDecision = conditionExports.createCatalogConditionalDecision;
14
14
  exports.permissionRules = index.permissionRules;
15
- exports.default = CatalogPlugin.catalogPlugin;
16
15
  exports.createCatalogPermissionRule = util.createCatalogPermissionRule;
16
+ exports.default = _feature;
17
17
  //# sourceMappingURL=alpha.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"alpha.cjs.js","sources":["../src/alpha.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 { catalogPlugin } from './service/CatalogPlugin';\n\n/** @alpha */\nconst _feature = catalogPlugin;\nexport default _feature;\n\nexport * from './permissions';\n"],"names":["catalogPlugin"],"mappings":";;;;;;;;;AAmBA,MAAM,QAAW,GAAAA;;;;;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
1
2
  import * as _backstage_plugin_permission_common from '@backstage/plugin-permission-common';
2
3
  import { PermissionRuleParams } from '@backstage/plugin-permission-common';
3
4
  import * as _backstage_plugin_permission_node from '@backstage/plugin-permission-node';
@@ -6,7 +7,6 @@ import * as _backstage_plugin_catalog_node from '@backstage/plugin-catalog-node'
6
7
  import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node';
7
8
  import * as _backstage_catalog_model from '@backstage/catalog-model';
8
9
  import { Entity } from '@backstage/catalog-model';
9
- import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
10
10
 
11
11
  /**
12
12
  * These conditions are used when creating conditional decisions for catalog
@@ -117,10 +117,7 @@ declare const permissionRules: {
117
117
  }>;
118
118
  };
119
119
 
120
- /**
121
- * Catalog plugin
122
- * @alpha
123
- */
124
- declare const catalogPlugin: _backstage_backend_plugin_api.BackendFeature;
120
+ /** @alpha */
121
+ declare const _feature: _backstage_backend_plugin_api.BackendFeature;
125
122
 
126
- export { type CatalogPermissionRule, catalogConditions, createCatalogConditionalDecision, createCatalogPermissionRule, catalogPlugin as default, permissionRules };
123
+ export { type CatalogPermissionRule, catalogConditions, createCatalogConditionalDecision, createCatalogPermissionRule, _feature as default, permissionRules };
@@ -81,7 +81,7 @@ class DefaultProcessingDatabase {
81
81
  "refresh_keys",
82
82
  refreshKeys.map((k) => ({
83
83
  entity_id: id,
84
- key: k.key
84
+ key: util.generateTargetKey(k.key)
85
85
  })),
86
86
  BATCH_SIZE
87
87
  );
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultProcessingDatabase.cjs.js","sources":["../../src/database/DefaultProcessingDatabase.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { ConflictError } from '@backstage/errors';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport { ProcessingIntervalFunction } from '../processing';\nimport { rethrowError, timestampToDateTime } from './conversion';\nimport { initDatabaseMetrics } from './metrics';\nimport {\n DbRefreshKeysRow,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n} from './tables';\nimport {\n GetProcessableEntitiesResult,\n ListParentsOptions,\n ListParentsResult,\n ProcessingDatabase,\n RefreshStateItem,\n Transaction,\n UpdateEntityCacheOptions,\n UpdateProcessedEntityOptions,\n} from './types';\nimport { checkLocationKeyConflict } from './operations/refreshState/checkLocationKeyConflict';\nimport { insertUnprocessedEntity } from './operations/refreshState/insertUnprocessedEntity';\nimport { updateUnprocessedEntity } from './operations/refreshState/updateUnprocessedEntity';\nimport { generateStableHash } from './util';\nimport {\n EventBroker,\n EventParams,\n EventsService,\n} from '@backstage/plugin-events-node';\nimport { DateTime } from 'luxon';\nimport { CATALOG_CONFLICTS_TOPIC } from '../constants';\nimport { CatalogConflictEventPayload } from '../catalog/types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nconst BATCH_SIZE = 50;\n\nexport class DefaultProcessingDatabase implements ProcessingDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n refreshInterval: ProcessingIntervalFunction;\n eventBroker?: EventBroker | EventsService;\n },\n ) {\n initDatabaseMetrics(options.database);\n }\n\n async updateProcessedEntity(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise<{ previous: { relations: DbRelationsRow[] } }> {\n const tx = txOpaque as Knex.Transaction;\n const {\n id,\n processedEntity,\n resultHash,\n errors,\n relations,\n deferredEntities,\n refreshKeys,\n locationKey,\n } = options;\n const configClient = tx.client.config.client;\n const refreshResult = await tx<DbRefreshStateRow>('refresh_state')\n .update({\n processed_entity: JSON.stringify(processedEntity),\n result_hash: resultHash,\n errors,\n location_key: locationKey,\n })\n .where('entity_id', id)\n .andWhere(inner => {\n if (!locationKey) {\n return inner.whereNull('location_key');\n }\n return inner\n .where('location_key', locationKey)\n .orWhereNull('location_key');\n });\n if (refreshResult === 0) {\n throw new ConflictError(\n `Conflicting write of processing result for ${id} with location key '${locationKey}'`,\n );\n }\n const sourceEntityRef = stringifyEntityRef(processedEntity);\n\n // Schedule all deferred entities for future processing.\n await this.addUnprocessedEntities(tx, {\n entities: deferredEntities,\n sourceEntityRef,\n });\n\n // Delete old relations\n // NOTE(freben): knex implemented support for returning() on update queries for sqlite, but at the current time of writing (Sep 2022) not for delete() queries.\n let previousRelationRows: DbRelationsRow[];\n if (configClient.includes('sqlite3') || configClient.includes('mysql')) {\n previousRelationRows = await tx<DbRelationsRow>('relations')\n .select('*')\n .where({ originating_entity_id: id });\n await tx<DbRelationsRow>('relations')\n .where({ originating_entity_id: id })\n .delete();\n } else {\n previousRelationRows = await tx<DbRelationsRow>('relations')\n .where({ originating_entity_id: id })\n .delete()\n .returning('*');\n }\n\n // Batch insert new relations\n const relationRows: DbRelationsRow[] = relations.map(\n ({ source, target, type }) => ({\n originating_entity_id: id,\n source_entity_ref: stringifyEntityRef(source),\n target_entity_ref: stringifyEntityRef(target),\n type,\n }),\n );\n\n await tx.batchInsert(\n 'relations',\n this.deduplicateRelations(relationRows),\n BATCH_SIZE,\n );\n\n // Delete old refresh keys\n await tx<DbRefreshKeysRow>('refresh_keys')\n .where({ entity_id: id })\n .delete();\n\n // Insert the refresh keys for the processed entity\n await tx.batchInsert(\n 'refresh_keys',\n refreshKeys.map(k => ({\n entity_id: id,\n key: k.key,\n })),\n BATCH_SIZE,\n );\n\n return {\n previous: {\n relations: previousRelationRows,\n },\n };\n }\n\n async updateProcessedEntityErrors(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise<void> {\n const tx = txOpaque as Knex.Transaction;\n const { id, errors, resultHash } = options;\n\n await tx<DbRefreshStateRow>('refresh_state')\n .update({\n errors,\n result_hash: resultHash,\n })\n .where('entity_id', id);\n }\n\n async updateEntityCache(\n txOpaque: Transaction,\n options: UpdateEntityCacheOptions,\n ): Promise<void> {\n const tx = txOpaque as Knex.Transaction;\n const { id, state } = options;\n\n await tx<DbRefreshStateRow>('refresh_state')\n .update({ cache: JSON.stringify(state ?? {}) })\n .where('entity_id', id);\n }\n\n async getProcessableEntities(\n txOpaque: Transaction,\n request: { processBatchSize: number },\n ): Promise<GetProcessableEntitiesResult> {\n const tx = txOpaque as Knex.Transaction;\n\n let itemsQuery = tx<DbRefreshStateRow>('refresh_state').select();\n\n // This avoids duplication of work because of race conditions and is\n // also fast because locked rows are ignored rather than blocking.\n // It's only available in MySQL and PostgreSQL\n if (['mysql', 'mysql2', 'pg'].includes(tx.client.config.client)) {\n itemsQuery = itemsQuery.forUpdate().skipLocked();\n }\n\n const items = await itemsQuery\n .where('next_update_at', '<=', tx.fn.now())\n .limit(request.processBatchSize)\n .orderBy('next_update_at', 'asc');\n\n const interval = this.options.refreshInterval();\n\n const nextUpdateAt = (refreshInterval: number) => {\n if (tx.client.config.client.includes('sqlite3')) {\n return tx.raw(`datetime('now', ?)`, [`${refreshInterval} seconds`]);\n }\n\n if (tx.client.config.client.includes('mysql')) {\n return tx.raw(`now() + interval ${refreshInterval} second`);\n }\n\n return tx.raw(`now() + interval '${refreshInterval} seconds'`);\n };\n\n await tx<DbRefreshStateRow>('refresh_state')\n .whereIn(\n 'entity_ref',\n items.map(i => i.entity_ref),\n )\n .update({\n next_update_at: nextUpdateAt(interval),\n });\n\n return {\n items: items.map(\n i =>\n ({\n id: i.entity_id,\n entityRef: i.entity_ref,\n unprocessedEntity: JSON.parse(i.unprocessed_entity) as Entity,\n processedEntity: i.processed_entity\n ? (JSON.parse(i.processed_entity) as Entity)\n : undefined,\n resultHash: i.result_hash || '',\n nextUpdateAt: timestampToDateTime(i.next_update_at),\n lastDiscoveryAt: timestampToDateTime(i.last_discovery_at),\n state: i.cache ? JSON.parse(i.cache) : undefined,\n errors: i.errors,\n locationKey: i.location_key,\n } as RefreshStateItem),\n ),\n };\n }\n\n async listParents(\n txOpaque: Transaction,\n options: ListParentsOptions,\n ): Promise<ListParentsResult> {\n const tx = txOpaque as Knex.Transaction;\n\n const rows = await tx<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n )\n .where({ target_entity_ref: options.entityRef })\n .select();\n\n const entityRefs = rows.map(r => r.source_entity_ref!).filter(Boolean);\n\n return { entityRefs };\n }\n\n async transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T> {\n try {\n let result: T | undefined = undefined;\n\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n private deduplicateRelations(rows: DbRelationsRow[]): DbRelationsRow[] {\n return lodash.uniqBy(\n rows,\n r => `${r.source_entity_ref}:${r.target_entity_ref}:${r.type}`,\n );\n }\n\n /**\n * Add a set of deferred entities for processing.\n * The entities will be added at the front of the processing queue.\n */\n private async addUnprocessedEntities(\n txOpaque: Transaction,\n options: {\n sourceEntityRef: string;\n entities: DeferredEntity[];\n },\n ): Promise<void> {\n const tx = txOpaque as Knex.Transaction;\n\n // Keeps track of the entities that we end up inserting to update refresh_state_references afterwards\n const stateReferences = new Array<string>();\n\n // Upsert all of the unprocessed entities into the refresh_state table, by\n // their entity ref.\n for (const { entity, locationKey } of options.entities) {\n const entityRef = stringifyEntityRef(entity);\n const hash = generateStableHash(entity);\n\n const updated = await updateUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n });\n if (updated) {\n stateReferences.push(entityRef);\n continue;\n }\n\n const inserted = await insertUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n logger: this.options.logger,\n });\n if (inserted) {\n stateReferences.push(entityRef);\n continue;\n }\n\n // If the row can't be inserted, we have a conflict, but it could be either\n // because of a conflicting locationKey or a race with another instance, so check\n // whether the conflicting entity has the same entityRef but a different locationKey\n const conflictingKey = await checkLocationKeyConflict({\n tx,\n entityRef,\n locationKey,\n });\n if (conflictingKey) {\n this.options.logger.warn(\n `Detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`,\n );\n if (this.options.eventBroker && locationKey) {\n const eventParams: EventParams<CatalogConflictEventPayload> = {\n topic: CATALOG_CONFLICTS_TOPIC,\n eventPayload: {\n unprocessedEntity: entity,\n entityRef,\n newLocationKey: locationKey,\n existingLocationKey: conflictingKey,\n lastConflictAt: DateTime.now().toISO()!,\n },\n };\n await this.options.eventBroker?.publish(eventParams);\n }\n }\n }\n\n // Replace all references for the originating entity or source and then create new ones\n await tx<DbRefreshStateReferencesRow>('refresh_state_references')\n .andWhere({ source_entity_ref: options.sourceEntityRef })\n .delete();\n await tx.batchInsert(\n 'refresh_state_references',\n stateReferences.map(entityRef => ({\n source_entity_ref: options.sourceEntityRef,\n target_entity_ref: entityRef,\n })),\n BATCH_SIZE,\n );\n }\n}\n"],"names":["initDatabaseMetrics","errors","ConflictError","stringifyEntityRef","timestampToDateTime","rethrowError","lodash","generateStableHash","updateUnprocessedEntity","insertUnprocessedEntity","checkLocationKeyConflict","CATALOG_CONFLICTS_TOPIC","DateTime"],"mappings":"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"}
1
+ {"version":3,"file":"DefaultProcessingDatabase.cjs.js","sources":["../../src/database/DefaultProcessingDatabase.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { ConflictError } from '@backstage/errors';\nimport { DeferredEntity } from '@backstage/plugin-catalog-node';\nimport { Knex } from 'knex';\nimport lodash from 'lodash';\nimport { ProcessingIntervalFunction } from '../processing';\nimport { rethrowError, timestampToDateTime } from './conversion';\nimport { initDatabaseMetrics } from './metrics';\nimport {\n DbRefreshKeysRow,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n} from './tables';\nimport {\n GetProcessableEntitiesResult,\n ListParentsOptions,\n ListParentsResult,\n ProcessingDatabase,\n RefreshStateItem,\n Transaction,\n UpdateEntityCacheOptions,\n UpdateProcessedEntityOptions,\n} from './types';\nimport { checkLocationKeyConflict } from './operations/refreshState/checkLocationKeyConflict';\nimport { insertUnprocessedEntity } from './operations/refreshState/insertUnprocessedEntity';\nimport { updateUnprocessedEntity } from './operations/refreshState/updateUnprocessedEntity';\nimport { generateStableHash, generateTargetKey } from './util';\nimport {\n EventBroker,\n EventParams,\n EventsService,\n} from '@backstage/plugin-events-node';\nimport { DateTime } from 'luxon';\nimport { CATALOG_CONFLICTS_TOPIC } from '../constants';\nimport { CatalogConflictEventPayload } from '../catalog/types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n// The number of items that are sent per batch to the database layer, when\n// doing .batchInsert calls to knex. This needs to be low enough to not cause\n// errors in the underlying engine due to exceeding query limits, but large\n// enough to get the speed benefits.\nconst BATCH_SIZE = 50;\n\nexport class DefaultProcessingDatabase implements ProcessingDatabase {\n constructor(\n private readonly options: {\n database: Knex;\n logger: LoggerService;\n refreshInterval: ProcessingIntervalFunction;\n eventBroker?: EventBroker | EventsService;\n },\n ) {\n initDatabaseMetrics(options.database);\n }\n\n async updateProcessedEntity(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise<{ previous: { relations: DbRelationsRow[] } }> {\n const tx = txOpaque as Knex.Transaction;\n const {\n id,\n processedEntity,\n resultHash,\n errors,\n relations,\n deferredEntities,\n refreshKeys,\n locationKey,\n } = options;\n const configClient = tx.client.config.client;\n const refreshResult = await tx<DbRefreshStateRow>('refresh_state')\n .update({\n processed_entity: JSON.stringify(processedEntity),\n result_hash: resultHash,\n errors,\n location_key: locationKey,\n })\n .where('entity_id', id)\n .andWhere(inner => {\n if (!locationKey) {\n return inner.whereNull('location_key');\n }\n return inner\n .where('location_key', locationKey)\n .orWhereNull('location_key');\n });\n if (refreshResult === 0) {\n throw new ConflictError(\n `Conflicting write of processing result for ${id} with location key '${locationKey}'`,\n );\n }\n const sourceEntityRef = stringifyEntityRef(processedEntity);\n\n // Schedule all deferred entities for future processing.\n await this.addUnprocessedEntities(tx, {\n entities: deferredEntities,\n sourceEntityRef,\n });\n\n // Delete old relations\n // NOTE(freben): knex implemented support for returning() on update queries for sqlite, but at the current time of writing (Sep 2022) not for delete() queries.\n let previousRelationRows: DbRelationsRow[];\n if (configClient.includes('sqlite3') || configClient.includes('mysql')) {\n previousRelationRows = await tx<DbRelationsRow>('relations')\n .select('*')\n .where({ originating_entity_id: id });\n await tx<DbRelationsRow>('relations')\n .where({ originating_entity_id: id })\n .delete();\n } else {\n previousRelationRows = await tx<DbRelationsRow>('relations')\n .where({ originating_entity_id: id })\n .delete()\n .returning('*');\n }\n\n // Batch insert new relations\n const relationRows: DbRelationsRow[] = relations.map(\n ({ source, target, type }) => ({\n originating_entity_id: id,\n source_entity_ref: stringifyEntityRef(source),\n target_entity_ref: stringifyEntityRef(target),\n type,\n }),\n );\n\n await tx.batchInsert(\n 'relations',\n this.deduplicateRelations(relationRows),\n BATCH_SIZE,\n );\n\n // Delete old refresh keys\n await tx<DbRefreshKeysRow>('refresh_keys')\n .where({ entity_id: id })\n .delete();\n\n // Insert the refresh keys for the processed entity\n await tx.batchInsert(\n 'refresh_keys',\n refreshKeys.map(k => ({\n entity_id: id,\n key: generateTargetKey(k.key),\n })),\n BATCH_SIZE,\n );\n\n return {\n previous: {\n relations: previousRelationRows,\n },\n };\n }\n\n async updateProcessedEntityErrors(\n txOpaque: Transaction,\n options: UpdateProcessedEntityOptions,\n ): Promise<void> {\n const tx = txOpaque as Knex.Transaction;\n const { id, errors, resultHash } = options;\n\n await tx<DbRefreshStateRow>('refresh_state')\n .update({\n errors,\n result_hash: resultHash,\n })\n .where('entity_id', id);\n }\n\n async updateEntityCache(\n txOpaque: Transaction,\n options: UpdateEntityCacheOptions,\n ): Promise<void> {\n const tx = txOpaque as Knex.Transaction;\n const { id, state } = options;\n\n await tx<DbRefreshStateRow>('refresh_state')\n .update({ cache: JSON.stringify(state ?? {}) })\n .where('entity_id', id);\n }\n\n async getProcessableEntities(\n txOpaque: Transaction,\n request: { processBatchSize: number },\n ): Promise<GetProcessableEntitiesResult> {\n const tx = txOpaque as Knex.Transaction;\n\n let itemsQuery = tx<DbRefreshStateRow>('refresh_state').select();\n\n // This avoids duplication of work because of race conditions and is\n // also fast because locked rows are ignored rather than blocking.\n // It's only available in MySQL and PostgreSQL\n if (['mysql', 'mysql2', 'pg'].includes(tx.client.config.client)) {\n itemsQuery = itemsQuery.forUpdate().skipLocked();\n }\n\n const items = await itemsQuery\n .where('next_update_at', '<=', tx.fn.now())\n .limit(request.processBatchSize)\n .orderBy('next_update_at', 'asc');\n\n const interval = this.options.refreshInterval();\n\n const nextUpdateAt = (refreshInterval: number) => {\n if (tx.client.config.client.includes('sqlite3')) {\n return tx.raw(`datetime('now', ?)`, [`${refreshInterval} seconds`]);\n }\n\n if (tx.client.config.client.includes('mysql')) {\n return tx.raw(`now() + interval ${refreshInterval} second`);\n }\n\n return tx.raw(`now() + interval '${refreshInterval} seconds'`);\n };\n\n await tx<DbRefreshStateRow>('refresh_state')\n .whereIn(\n 'entity_ref',\n items.map(i => i.entity_ref),\n )\n .update({\n next_update_at: nextUpdateAt(interval),\n });\n\n return {\n items: items.map(\n i =>\n ({\n id: i.entity_id,\n entityRef: i.entity_ref,\n unprocessedEntity: JSON.parse(i.unprocessed_entity) as Entity,\n processedEntity: i.processed_entity\n ? (JSON.parse(i.processed_entity) as Entity)\n : undefined,\n resultHash: i.result_hash || '',\n nextUpdateAt: timestampToDateTime(i.next_update_at),\n lastDiscoveryAt: timestampToDateTime(i.last_discovery_at),\n state: i.cache ? JSON.parse(i.cache) : undefined,\n errors: i.errors,\n locationKey: i.location_key,\n } as RefreshStateItem),\n ),\n };\n }\n\n async listParents(\n txOpaque: Transaction,\n options: ListParentsOptions,\n ): Promise<ListParentsResult> {\n const tx = txOpaque as Knex.Transaction;\n\n const rows = await tx<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n )\n .where({ target_entity_ref: options.entityRef })\n .select();\n\n const entityRefs = rows.map(r => r.source_entity_ref!).filter(Boolean);\n\n return { entityRefs };\n }\n\n async transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T> {\n try {\n let result: T | undefined = undefined;\n\n await this.options.database.transaction(\n async tx => {\n // We can't return here, as knex swallows the return type in case the transaction is rolled back:\n // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136\n result = await fn(tx);\n },\n {\n // If we explicitly trigger a rollback, don't fail.\n doNotRejectOnRollback: true,\n },\n );\n\n return result!;\n } catch (e) {\n this.options.logger.debug(`Error during transaction, ${e}`);\n throw rethrowError(e);\n }\n }\n\n private deduplicateRelations(rows: DbRelationsRow[]): DbRelationsRow[] {\n return lodash.uniqBy(\n rows,\n r => `${r.source_entity_ref}:${r.target_entity_ref}:${r.type}`,\n );\n }\n\n /**\n * Add a set of deferred entities for processing.\n * The entities will be added at the front of the processing queue.\n */\n private async addUnprocessedEntities(\n txOpaque: Transaction,\n options: {\n sourceEntityRef: string;\n entities: DeferredEntity[];\n },\n ): Promise<void> {\n const tx = txOpaque as Knex.Transaction;\n\n // Keeps track of the entities that we end up inserting to update refresh_state_references afterwards\n const stateReferences = new Array<string>();\n\n // Upsert all of the unprocessed entities into the refresh_state table, by\n // their entity ref.\n for (const { entity, locationKey } of options.entities) {\n const entityRef = stringifyEntityRef(entity);\n const hash = generateStableHash(entity);\n\n const updated = await updateUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n });\n if (updated) {\n stateReferences.push(entityRef);\n continue;\n }\n\n const inserted = await insertUnprocessedEntity({\n tx,\n entity,\n hash,\n locationKey,\n logger: this.options.logger,\n });\n if (inserted) {\n stateReferences.push(entityRef);\n continue;\n }\n\n // If the row can't be inserted, we have a conflict, but it could be either\n // because of a conflicting locationKey or a race with another instance, so check\n // whether the conflicting entity has the same entityRef but a different locationKey\n const conflictingKey = await checkLocationKeyConflict({\n tx,\n entityRef,\n locationKey,\n });\n if (conflictingKey) {\n this.options.logger.warn(\n `Detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`,\n );\n if (this.options.eventBroker && locationKey) {\n const eventParams: EventParams<CatalogConflictEventPayload> = {\n topic: CATALOG_CONFLICTS_TOPIC,\n eventPayload: {\n unprocessedEntity: entity,\n entityRef,\n newLocationKey: locationKey,\n existingLocationKey: conflictingKey,\n lastConflictAt: DateTime.now().toISO()!,\n },\n };\n await this.options.eventBroker?.publish(eventParams);\n }\n }\n }\n\n // Replace all references for the originating entity or source and then create new ones\n await tx<DbRefreshStateReferencesRow>('refresh_state_references')\n .andWhere({ source_entity_ref: options.sourceEntityRef })\n .delete();\n await tx.batchInsert(\n 'refresh_state_references',\n stateReferences.map(entityRef => ({\n source_entity_ref: options.sourceEntityRef,\n target_entity_ref: entityRef,\n })),\n BATCH_SIZE,\n );\n }\n}\n"],"names":["initDatabaseMetrics","errors","ConflictError","stringifyEntityRef","generateTargetKey","timestampToDateTime","rethrowError","lodash","generateStableHash","updateUnprocessedEntity","insertUnprocessedEntity","checkLocationKeyConflict","CATALOG_CONFLICTS_TOPIC","DateTime"],"mappings":"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"}
@@ -1,9 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ var util = require('../../util.cjs.js');
4
+
3
5
  async function refreshByRefreshKeys(options) {
4
6
  const { tx, keys } = options;
7
+ const hashedKeys = keys.map((k) => util.generateTargetKey(k));
5
8
  await tx("refresh_state").whereIn("entity_id", function selectEntityRefs(inner) {
6
- inner.whereIn("key", keys).select({
9
+ inner.whereIn("key", hashedKeys).select({
7
10
  entity_id: "refresh_keys.entity_id"
8
11
  }).from("refresh_keys");
9
12
  }).update({ next_update_at: tx.fn.now() });
@@ -1 +1 @@
1
- {"version":3,"file":"refreshByRefreshKeys.cjs.js","sources":["../../../../src/database/operations/provider/refreshByRefreshKeys.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\n\n/**\n * Schedules a future refresh of entities, by so called \"refresh keys\" that may\n * be associated with one or more entities. Note that this does not mean that\n * the refresh happens immediately, but rather that their scheduling time gets\n * moved up the queue and will get picked up eventually by the regular\n * processing loop.\n */\nexport async function refreshByRefreshKeys(options: {\n tx: Knex.Transaction;\n keys: string[];\n}): Promise<void> {\n const { tx, keys } = options;\n\n await tx<DbRefreshStateRow>('refresh_state')\n .whereIn('entity_id', function selectEntityRefs(inner) {\n inner\n .whereIn('key', keys)\n .select({\n entity_id: 'refresh_keys.entity_id',\n })\n .from('refresh_keys');\n })\n .update({ next_update_at: tx.fn.now() });\n}\n"],"names":[],"mappings":";;AA0BA,eAAsB,qBAAqB,OAGzB,EAAA;AAChB,EAAM,MAAA,EAAE,EAAI,EAAA,IAAA,EAAS,GAAA,OAAA,CAAA;AAErB,EAAA,MAAM,GAAsB,eAAe,CAAA,CACxC,QAAQ,WAAa,EAAA,SAAS,iBAAiB,KAAO,EAAA;AACrD,IAAA,KAAA,CACG,OAAQ,CAAA,KAAA,EAAO,IAAI,CAAA,CACnB,MAAO,CAAA;AAAA,MACN,SAAW,EAAA,wBAAA;AAAA,KACZ,CACA,CAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAAA,GACvB,EACA,MAAO,CAAA,EAAE,gBAAgB,EAAG,CAAA,EAAA,CAAG,GAAI,EAAA,EAAG,CAAA,CAAA;AAC3C;;;;"}
1
+ {"version":3,"file":"refreshByRefreshKeys.cjs.js","sources":["../../../../src/database/operations/provider/refreshByRefreshKeys.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { Knex } from 'knex';\nimport { DbRefreshStateRow } from '../../tables';\nimport { generateTargetKey } from '../../util';\n\n/**\n * Schedules a future refresh of entities, by so called \"refresh keys\" that may\n * be associated with one or more entities. Note that this does not mean that\n * the refresh happens immediately, but rather that their scheduling time gets\n * moved up the queue and will get picked up eventually by the regular\n * processing loop.\n */\nexport async function refreshByRefreshKeys(options: {\n tx: Knex.Transaction;\n keys: string[];\n}): Promise<void> {\n const { tx, keys } = options;\n\n const hashedKeys = keys.map(k => generateTargetKey(k));\n\n await tx<DbRefreshStateRow>('refresh_state')\n .whereIn('entity_id', function selectEntityRefs(inner) {\n inner\n .whereIn('key', hashedKeys)\n .select({\n entity_id: 'refresh_keys.entity_id',\n })\n .from('refresh_keys');\n })\n .update({ next_update_at: tx.fn.now() });\n}\n"],"names":["generateTargetKey"],"mappings":";;;;AA2BA,eAAsB,qBAAqB,OAGzB,EAAA;AAChB,EAAM,MAAA,EAAE,EAAI,EAAA,IAAA,EAAS,GAAA,OAAA,CAAA;AAErB,EAAA,MAAM,aAAa,IAAK,CAAA,GAAA,CAAI,CAAK,CAAA,KAAAA,sBAAA,CAAkB,CAAC,CAAC,CAAA,CAAA;AAErD,EAAA,MAAM,GAAsB,eAAe,CAAA,CACxC,QAAQ,WAAa,EAAA,SAAS,iBAAiB,KAAO,EAAA;AACrD,IAAA,KAAA,CACG,OAAQ,CAAA,KAAA,EAAO,UAAU,CAAA,CACzB,MAAO,CAAA;AAAA,MACN,SAAW,EAAA,wBAAA;AAAA,KACZ,CACA,CAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAAA,GACvB,EACA,MAAO,CAAA,EAAE,gBAAgB,EAAG,CAAA,EAAA,CAAG,GAAI,EAAA,EAAG,CAAA,CAAA;AAC3C;;;;"}
@@ -10,6 +10,10 @@ var stableStringify__default = /*#__PURE__*/_interopDefaultCompat(stableStringif
10
10
  function generateStableHash(entity) {
11
11
  return crypto.createHash("sha1").update(stableStringify__default.default({ ...entity })).digest("hex");
12
12
  }
13
+ function generateTargetKey(target) {
14
+ return target.length > 255 ? `${target.slice(0, 180)}#sha256:${crypto.createHash("sha256").update(target).digest("hex")}` : target;
15
+ }
13
16
 
14
17
  exports.generateStableHash = generateStableHash;
18
+ exports.generateTargetKey = generateTargetKey;
15
19
  //# sourceMappingURL=util.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.cjs.js","sources":["../../src/database/util.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Entity } from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\n\nexport function generateStableHash(entity: Entity) {\n return createHash('sha1')\n .update(stableStringify({ ...entity }))\n .digest('hex');\n}\n"],"names":["createHash","stableStringify"],"mappings":";;;;;;;;;AAoBO,SAAS,mBAAmB,MAAgB,EAAA;AACjD,EAAA,OAAOA,iBAAW,CAAA,MAAM,CACrB,CAAA,MAAA,CAAOC,gCAAgB,CAAA,EAAE,GAAG,MAAA,EAAQ,CAAC,CACrC,CAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AACjB;;;;"}
1
+ {"version":3,"file":"util.cjs.js","sources":["../../src/database/util.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Entity } from '@backstage/catalog-model';\nimport { createHash } from 'crypto';\nimport stableStringify from 'fast-json-stable-stringify';\n\nexport function generateStableHash(entity: Entity) {\n return createHash('sha1')\n .update(stableStringify({ ...entity }))\n .digest('hex');\n}\n\nexport function generateTargetKey(target: string) {\n return target.length > 255\n ? `${target.slice(0, 180)}#sha256:${createHash('sha256')\n .update(target)\n .digest('hex')}`\n : target;\n}\n"],"names":["createHash","stableStringify"],"mappings":";;;;;;;;;AAoBO,SAAS,mBAAmB,MAAgB,EAAA;AACjD,EAAA,OAAOA,iBAAW,CAAA,MAAM,CACrB,CAAA,MAAA,CAAOC,gCAAgB,CAAA,EAAE,GAAG,MAAA,EAAQ,CAAC,CACrC,CAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AACjB,CAAA;AAEO,SAAS,kBAAkB,MAAgB,EAAA;AAChD,EAAA,OAAO,OAAO,MAAS,GAAA,GAAA,GACnB,GAAG,MAAO,CAAA,KAAA,CAAM,GAAG,GAAG,CAAC,WAAWD,iBAAW,CAAA,QAAQ,EAClD,MAAO,CAAA,MAAM,EACb,MAAO,CAAA,KAAK,CAAC,CAChB,CAAA,GAAA,MAAA,CAAA;AACN;;;;;"}
package/dist/index.cjs.js CHANGED
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var CatalogPlugin = require('./service/CatalogPlugin.cjs.js');
3
6
  var AnnotateLocationEntityProcessor = require('./processors/AnnotateLocationEntityProcessor.cjs.js');
4
7
  var AnnotateScmSlugEntityProcessor = require('./processors/AnnotateScmSlugEntityProcessor.cjs.js');
5
8
  var BuiltinKindsEntityProcessor = require('./processors/BuiltinKindsEntityProcessor.cjs.js');
@@ -18,6 +21,7 @@ var parse = require('./util/parse.cjs.js');
18
21
 
19
22
 
20
23
 
24
+ exports.default = CatalogPlugin.catalogPlugin;
21
25
  exports.AnnotateLocationEntityProcessor = AnnotateLocationEntityProcessor.AnnotateLocationEntityProcessor;
22
26
  exports.AnnotateScmSlugEntityProcessor = AnnotateScmSlugEntityProcessor.AnnotateScmSlugEntityProcessor;
23
27
  exports.BuiltinKindsEntityProcessor = BuiltinKindsEntityProcessor.BuiltinKindsEntityProcessor;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  /// <reference types="node" />
2
+ import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
3
+ import { LoggerService, UrlReaderService, DatabaseService, RootConfigService, PermissionsService, SchedulerService, DiscoveryService, AuthService, HttpAuthService } from '@backstage/backend-plugin-api';
2
4
  import * as _backstage_catalog_model from '@backstage/catalog-model';
3
5
  import { Entity, EntityPolicy, Validators } from '@backstage/catalog-model';
4
6
  import { ScmIntegrationRegistry } from '@backstage/integration';
5
7
  import { LocationSpec as LocationSpec$1, CatalogEntityDocument, AnalyzeLocationRequest as AnalyzeLocationRequest$1, AnalyzeLocationResponse as AnalyzeLocationResponse$1, AnalyzeLocationExistingEntity as AnalyzeLocationExistingEntity$1, AnalyzeLocationGenerateEntity as AnalyzeLocationGenerateEntity$1, AnalyzeLocationEntityField as AnalyzeLocationEntityField$1 } from '@backstage/plugin-catalog-common';
6
8
  import { CatalogProcessor as CatalogProcessor$1, CatalogProcessorEmit as CatalogProcessorEmit$1, CatalogProcessorParser as CatalogProcessorParser$1, PlaceholderResolver as PlaceholderResolver$1, CatalogProcessorCache as CatalogProcessorCache$1, EntitiesSearchFilter as EntitiesSearchFilter$1, LocationAnalyzer as LocationAnalyzer$1, EntityProvider as EntityProvider$1, ScmLocationAnalyzer as ScmLocationAnalyzer$1, locationSpecToMetadataName as locationSpecToMetadataName$1, locationSpecToLocationEntity as locationSpecToLocationEntity$1, CatalogProcessorResult as CatalogProcessorResult$1, EntityRelationSpec as EntityRelationSpec$1, EntityFilter as EntityFilter$1, DeferredEntity as DeferredEntity$1, CatalogProcessorLocationResult as CatalogProcessorLocationResult$1, CatalogProcessorEntityResult as CatalogProcessorEntityResult$1, CatalogProcessorRelationResult as CatalogProcessorRelationResult$1, CatalogProcessorErrorResult as CatalogProcessorErrorResult$1, CatalogProcessorRefreshKeysResult as CatalogProcessorRefreshKeysResult$1, EntityProviderConnection as EntityProviderConnection$1, EntityProviderMutation as EntityProviderMutation$1, AnalyzeOptions as AnalyzeOptions$1, PlaceholderResolverParams as PlaceholderResolverParams$1, PlaceholderResolverRead as PlaceholderResolverRead$1, PlaceholderResolverResolveUrl as PlaceholderResolverResolveUrl$1 } from '@backstage/plugin-catalog-node';
7
9
  import { Config } from '@backstage/config';
8
- import { LoggerService, UrlReaderService, DatabaseService, RootConfigService, PermissionsService, SchedulerService, DiscoveryService, AuthService, HttpAuthService } from '@backstage/backend-plugin-api';
9
10
  import { PluginEndpointDiscovery, TokenManager } from '@backstage/backend-common';
10
11
  import { GetEntitiesRequest, CatalogApi } from '@backstage/catalog-client';
11
12
  import { Permission, PermissionRuleParams, PermissionAuthorizer } from '@backstage/plugin-permission-common';
@@ -14,6 +15,12 @@ import { PermissionRule } from '@backstage/plugin-permission-node';
14
15
  import { EventBroker, EventsService } from '@backstage/plugin-events-node';
15
16
  import { DefaultCatalogCollatorFactory as DefaultCatalogCollatorFactory$1, CatalogCollatorEntityTransformer as CatalogCollatorEntityTransformer$1, DefaultCatalogCollatorFactoryOptions as DefaultCatalogCollatorFactoryOptions$1 } from '@backstage/plugin-search-backend-module-catalog';
16
17
 
18
+ /**
19
+ * Catalog plugin
20
+ * @public
21
+ */
22
+ declare const catalogPlugin: _backstage_backend_plugin_api.BackendFeature;
23
+
17
24
  /** @public */
18
25
  declare class AnnotateLocationEntityProcessor implements CatalogProcessor$1 {
19
26
  private readonly options;
@@ -652,4 +659,4 @@ declare const CATALOG_ERRORS_TOPIC = "experimental.catalog.errors";
652
659
  /** @public */
653
660
  declare function parseEntityYaml(data: Buffer, location: LocationSpec$1): Iterable<CatalogProcessorResult$1>;
654
661
 
655
- export { type AnalyzeLocationEntityField, type AnalyzeLocationExistingEntity, type AnalyzeLocationGenerateEntity, type AnalyzeLocationRequest, type AnalyzeLocationResponse, type AnalyzeOptions, AnnotateLocationEntityProcessor, AnnotateScmSlugEntityProcessor, BuiltinKindsEntityProcessor, CATALOG_CONFLICTS_TOPIC, CATALOG_ERRORS_TOPIC, CatalogBuilder, type CatalogCollatorEntityTransformer, type CatalogEnvironment, type CatalogPermissionRuleInput, type CatalogProcessingEngine, type CatalogProcessor, type CatalogProcessorCache, type CatalogProcessorEmit, type CatalogProcessorEntityResult, type CatalogProcessorErrorResult, type CatalogProcessorLocationResult, type CatalogProcessorParser, type CatalogProcessorRefreshKeysResult, type CatalogProcessorRelationResult, type CatalogProcessorResult, CodeOwnersProcessor, DefaultCatalogCollator, DefaultCatalogCollatorFactory, type DefaultCatalogCollatorFactoryOptions, type DeferredEntity, type EntitiesSearchFilter, type EntityFilter, type EntityProvider, type EntityProviderConnection, type EntityProviderMutation, type EntityRelationSpec, FileReaderProcessor, type LocationAnalyzer, LocationEntityProcessor, type LocationEntityProcessorOptions, type LocationSpec, PlaceholderProcessor, type PlaceholderProcessorOptions, type PlaceholderResolver, type PlaceholderResolverParams, type PlaceholderResolverRead, type PlaceholderResolverResolveUrl, type ProcessingIntervalFunction, type ScmLocationAnalyzer, UrlReaderProcessor, createRandomProcessingInterval, defaultCatalogCollatorEntityTransformer, locationSpecToLocationEntity, locationSpecToMetadataName, parseEntityYaml, processingResult, transformLegacyPolicyToProcessor };
662
+ export { type AnalyzeLocationEntityField, type AnalyzeLocationExistingEntity, type AnalyzeLocationGenerateEntity, type AnalyzeLocationRequest, type AnalyzeLocationResponse, type AnalyzeOptions, AnnotateLocationEntityProcessor, AnnotateScmSlugEntityProcessor, BuiltinKindsEntityProcessor, CATALOG_CONFLICTS_TOPIC, CATALOG_ERRORS_TOPIC, CatalogBuilder, type CatalogCollatorEntityTransformer, type CatalogEnvironment, type CatalogPermissionRuleInput, type CatalogProcessingEngine, type CatalogProcessor, type CatalogProcessorCache, type CatalogProcessorEmit, type CatalogProcessorEntityResult, type CatalogProcessorErrorResult, type CatalogProcessorLocationResult, type CatalogProcessorParser, type CatalogProcessorRefreshKeysResult, type CatalogProcessorRelationResult, type CatalogProcessorResult, CodeOwnersProcessor, DefaultCatalogCollator, DefaultCatalogCollatorFactory, type DefaultCatalogCollatorFactoryOptions, type DeferredEntity, type EntitiesSearchFilter, type EntityFilter, type EntityProvider, type EntityProviderConnection, type EntityProviderMutation, type EntityRelationSpec, FileReaderProcessor, type LocationAnalyzer, LocationEntityProcessor, type LocationEntityProcessorOptions, type LocationSpec, PlaceholderProcessor, type PlaceholderProcessorOptions, type PlaceholderResolver, type PlaceholderResolverParams, type PlaceholderResolverRead, type PlaceholderResolverResolveUrl, type ProcessingIntervalFunction, type ScmLocationAnalyzer, UrlReaderProcessor, createRandomProcessingInterval, catalogPlugin as default, defaultCatalogCollatorEntityTransformer, locationSpecToLocationEntity, locationSpecToMetadataName, parseEntityYaml, processingResult, transformLegacyPolicyToProcessor };
@@ -613,6 +613,13 @@ class CatalogBuilder {
613
613
  maxSeconds: 150
614
614
  });
615
615
  }
616
+ if (!Boolean(config$1.get("catalog.processingInterval"))) {
617
+ return () => {
618
+ throw new Error(
619
+ "catalog.processingInterval is set to false, processing is disabled."
620
+ );
621
+ };
622
+ }
616
623
  const duration = config.readDurationFromConfig(config$1, {
617
624
  key: processingIntervalKey
618
625
  });
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogBuilder.cjs.js","sources":["../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n} from '@backstage/backend-common';\nimport {\n DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n parseEntityRef,\n SchemaValidEntityPolicy,\n stringifyEntityRef,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash, { keyBy } from 'lodash';\n\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntitiesSearchFilter,\n EntityProvider,\n PlaceholderResolver,\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n CodeOwnersProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../processors';\nimport { ConfigLocationEntityProvider } from '../providers/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../providers/DefaultLocationStore';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport { AuthorizedLocationAnalyzer } from './AuthorizedLocationAnalyzer';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../processors/PlaceholderProcessor';\nimport { defaultEntityDataParser } from '../util/parse';\nimport {\n CatalogProcessingEngine,\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { createRouter } from './createRouter';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport {\n Permission,\n PermissionAuthorizer,\n PermissionRuleParams,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { basicEntityFilter } from './request';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n RootConfigService,\n UrlReaderService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * This is a duplicate of the alpha `CatalogPermissionRule` type, for use in the stable API.\n *\n * @public\n */\nexport type CatalogPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<Entity, EntitiesSearchFilter, 'catalog-entity', TParams>;\n\n/**\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: DatabaseService;\n config: RootConfigService;\n reader: UrlReaderService;\n permissions: PermissionsService | PermissionAuthorizer;\n scheduler?: SchedulerService;\n discovery?: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record<string, PlaceholderResolver>;\n private fieldFormatValidators: Partial<Validators>;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array<EntityPolicy | Array<EntityPolicy>>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial<Validators>): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n CodeOwnersProcessor.fromConfig(config, { logger, reader }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array<ScmLocationAnalyzer | Array<ScmLocationAnalyzer>>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array<Permission | Array<Permission>>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n discovery = HostDiscovery.fromConfig(config),\n } = this.env;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...this.env,\n discovery,\n });\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n createConditionTransformer(this.permissionRules),\n );\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources: async (resourceRefs: string[]) => {\n const { entities } = await unauthorizedEntitiesCatalog.entities({\n credentials: await auth.getOwnServiceCredentials(),\n filter: {\n anyOf: resourceRefs.map(resourceRef => {\n const { kind, namespace, name } = parseEntityRef(resourceRef);\n\n return basicEntityFilter({\n kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n });\n }),\n },\n });\n\n const entitiesByRef = keyBy(entities, stringifyEntityRef);\n\n return resourceRefs.map(\n resourceRef =>\n entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],\n );\n },\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new AuthorizedLocationAnalyzer(\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers),\n permissionsService,\n );\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n permissionsService,\n });\n\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record<string, PlaceholderResolver> = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n // These are only added unless the user replaced them all\n if (!this.processorsReplace) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["catalogPermissions","catalogPermissionRules","createRandomProcessingInterval","lodash","ScmIntegrations","FileReaderProcessor","UrlReaderProcessor","CodeOwnersProcessor","AnnotateLocationEntityProcessor","HostDiscovery","createLegacyAuthAdapters","defaultEntityDataParser","applyDatabaseMigrations","DefaultStitcher","DefaultProcessingDatabase","DefaultProviderDatabase","DefaultCatalogDatabase","DefaultCatalogRulesEnforcer","DefaultEntitiesCatalog","toPermissionEvaluator","DefaultCatalogProcessingOrchestrator","AuthorizedEntitiesCatalog","createConditionTransformer","createPermissionIntegrationRouter","RESOURCE_TYPE_CATALOG_ENTITY","parseEntityRef","basicEntityFilter","keyBy","stringifyEntityRef","DefaultLocationStore","ConfigLocationEntityProvider","DefaultCatalogProcessingEngine","createHash","AuthorizedLocationAnalyzer","RepoLocationAnalyzer","AuthorizedLocationService","DefaultLocationService","AuthorizedRefreshService","DefaultRefreshService","createRouter","connectEntityProviders","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","jsonPlaceholderResolver","yamlPlaceholderResolver","textPlaceholderResolver","PlaceholderProcessor","BuiltinKindsEntityProcessor","config","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
1
+ {"version":3,"file":"CatalogBuilder.cjs.js","sources":["../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n} from '@backstage/backend-common';\nimport {\n DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n parseEntityRef,\n SchemaValidEntityPolicy,\n stringifyEntityRef,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash, { keyBy } from 'lodash';\n\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntitiesSearchFilter,\n EntityProvider,\n PlaceholderResolver,\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n CodeOwnersProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../processors';\nimport { ConfigLocationEntityProvider } from '../providers/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../providers/DefaultLocationStore';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport { AuthorizedLocationAnalyzer } from './AuthorizedLocationAnalyzer';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../processors/PlaceholderProcessor';\nimport { defaultEntityDataParser } from '../util/parse';\nimport {\n CatalogProcessingEngine,\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { createRouter } from './createRouter';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport {\n Permission,\n PermissionAuthorizer,\n PermissionRuleParams,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { basicEntityFilter } from './request';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n RootConfigService,\n UrlReaderService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * This is a duplicate of the alpha `CatalogPermissionRule` type, for use in the stable API.\n *\n * @public\n */\nexport type CatalogPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<Entity, EntitiesSearchFilter, 'catalog-entity', TParams>;\n\n/**\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: DatabaseService;\n config: RootConfigService;\n reader: UrlReaderService;\n permissions: PermissionsService | PermissionAuthorizer;\n scheduler?: SchedulerService;\n discovery?: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record<string, PlaceholderResolver>;\n private fieldFormatValidators: Partial<Validators>;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array<EntityPolicy | Array<EntityPolicy>>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial<Validators>): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n CodeOwnersProcessor.fromConfig(config, { logger, reader }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array<ScmLocationAnalyzer | Array<ScmLocationAnalyzer>>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array<Permission | Array<Permission>>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n discovery = HostDiscovery.fromConfig(config),\n } = this.env;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...this.env,\n discovery,\n });\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n createConditionTransformer(this.permissionRules),\n );\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources: async (resourceRefs: string[]) => {\n const { entities } = await unauthorizedEntitiesCatalog.entities({\n credentials: await auth.getOwnServiceCredentials(),\n filter: {\n anyOf: resourceRefs.map(resourceRef => {\n const { kind, namespace, name } = parseEntityRef(resourceRef);\n\n return basicEntityFilter({\n kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n });\n }),\n },\n });\n\n const entitiesByRef = keyBy(entities, stringifyEntityRef);\n\n return resourceRefs.map(\n resourceRef =>\n entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],\n );\n },\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new AuthorizedLocationAnalyzer(\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers),\n permissionsService,\n );\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n permissionsService,\n });\n\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record<string, PlaceholderResolver> = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n // These are only added unless the user replaced them all\n if (!this.processorsReplace) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n if (!Boolean(config.get('catalog.processingInterval'))) {\n return () => {\n throw new Error(\n 'catalog.processingInterval is set to false, processing is disabled.',\n );\n };\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["catalogPermissions","catalogPermissionRules","createRandomProcessingInterval","lodash","ScmIntegrations","FileReaderProcessor","UrlReaderProcessor","CodeOwnersProcessor","AnnotateLocationEntityProcessor","HostDiscovery","createLegacyAuthAdapters","defaultEntityDataParser","applyDatabaseMigrations","DefaultStitcher","DefaultProcessingDatabase","DefaultProviderDatabase","DefaultCatalogDatabase","DefaultCatalogRulesEnforcer","DefaultEntitiesCatalog","toPermissionEvaluator","DefaultCatalogProcessingOrchestrator","AuthorizedEntitiesCatalog","createConditionTransformer","createPermissionIntegrationRouter","RESOURCE_TYPE_CATALOG_ENTITY","parseEntityRef","basicEntityFilter","keyBy","stringifyEntityRef","DefaultLocationStore","ConfigLocationEntityProvider","DefaultCatalogProcessingEngine","createHash","AuthorizedLocationAnalyzer","RepoLocationAnalyzer","AuthorizedLocationService","DefaultLocationService","AuthorizedRefreshService","DefaultRefreshService","createRouter","connectEntityProviders","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","jsonPlaceholderResolver","yamlPlaceholderResolver","textPlaceholderResolver","PlaceholderProcessor","BuiltinKindsEntityProcessor","config","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
@@ -199,10 +199,12 @@ const catalogPlugin = backendPluginApi.createBackendPlugin({
199
199
  );
200
200
  }
201
201
  const { processingEngine, router } = await builder.build();
202
- lifecycle.addStartupHook(async () => {
203
- await processingEngine.start();
204
- });
205
- lifecycle.addShutdownHook(() => processingEngine.stop());
202
+ if (config.getOptional("catalog.processingInterval") ?? true) {
203
+ lifecycle.addStartupHook(async () => {
204
+ await processingEngine.start();
205
+ });
206
+ lifecycle.addShutdownHook(() => processingEngine.stop());
207
+ }
206
208
  httpRouter.use(router);
207
209
  }
208
210
  });
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogPlugin.cjs.js","sources":["../../src/service/CatalogPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 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 */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport { Entity, Validators } from '@backstage/catalog-model';\nimport { CatalogBuilder, CatalogPermissionRuleInput } from './CatalogBuilder';\nimport {\n catalogAnalysisExtensionPoint,\n CatalogModelExtensionPoint,\n catalogModelExtensionPoint,\n CatalogPermissionExtensionPoint,\n catalogPermissionExtensionPoint,\n CatalogProcessingExtensionPoint,\n catalogProcessingExtensionPoint,\n CatalogLocationsExtensionPoint,\n catalogLocationsExtensionPoint,\n} from '@backstage/plugin-catalog-node/alpha';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntityProvider,\n LocationAnalyzer,\n PlaceholderResolver,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport { ForwardedError } from '@backstage/errors';\n\nclass CatalogLocationsExtensionPointImpl\n implements CatalogLocationsExtensionPoint\n{\n #locationTypes: string[] | undefined;\n\n setAllowedLocationTypes(locationTypes: Array<string>) {\n this.#locationTypes = locationTypes;\n }\n\n get allowedLocationTypes() {\n return this.#locationTypes;\n }\n}\n\nclass CatalogProcessingExtensionPointImpl\n implements CatalogProcessingExtensionPoint\n{\n #processors = new Array<CatalogProcessor>();\n #entityProviders = new Array<EntityProvider>();\n #placeholderResolvers: Record<string, PlaceholderResolver> = {};\n #onProcessingErrorHandler?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): void {\n this.#entityProviders.push(...providers.flat());\n }\n\n addPlaceholderResolver(key: string, resolver: PlaceholderResolver) {\n if (key in this.#placeholderResolvers)\n throw new Error(\n `A placeholder resolver for '${key}' has already been set up, please check your config.`,\n );\n this.#placeholderResolvers[key] = resolver;\n }\n\n setOnProcessingErrorHandler(\n handler: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void,\n ) {\n this.#onProcessingErrorHandler = handler;\n }\n\n get processors() {\n return this.#processors;\n }\n\n get entityProviders() {\n return this.#entityProviders;\n }\n\n get placeholderResolvers() {\n return this.#placeholderResolvers;\n }\n\n get onProcessingErrorHandler() {\n return this.#onProcessingErrorHandler;\n }\n}\n\nclass CatalogPermissionExtensionPointImpl\n implements CatalogPermissionExtensionPoint\n{\n #permissions = new Array<Permission>();\n #permissionRules = new Array<CatalogPermissionRuleInput>();\n\n addPermissions(...permission: Array<Permission | Array<Permission>>): void {\n this.#permissions.push(...permission.flat());\n }\n\n addPermissionRules(\n ...rules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ): void {\n this.#permissionRules.push(...rules.flat());\n }\n\n get permissions() {\n return this.#permissions;\n }\n\n get permissionRules() {\n return this.#permissionRules;\n }\n}\n\nclass CatalogModelExtensionPointImpl implements CatalogModelExtensionPoint {\n #fieldValidators: Partial<Validators> = {};\n\n setFieldValidators(validators: Partial<Validators>): void {\n merge(this.#fieldValidators, validators);\n }\n\n get fieldValidators() {\n return this.#fieldValidators;\n }\n\n #entityDataParser?: CatalogProcessorParser;\n\n setEntityDataParser(parser: CatalogProcessorParser): void {\n if (this.#entityDataParser) {\n throw new Error(\n 'Attempted to install second EntityDataParser. Only one can be set.',\n );\n }\n this.#entityDataParser = parser;\n }\n\n get entityDataParser() {\n return this.#entityDataParser;\n }\n}\n\n/**\n * Catalog plugin\n * @alpha\n */\nexport const catalogPlugin = createBackendPlugin({\n pluginId: 'catalog',\n register(env) {\n const processingExtensions = new CatalogProcessingExtensionPointImpl();\n // plugins depending on this API will be initialized before this plugins init method is executed.\n env.registerExtensionPoint(\n catalogProcessingExtensionPoint,\n processingExtensions,\n );\n\n let locationAnalyzerFactory:\n | ((options: {\n scmLocationAnalyzers: ScmLocationAnalyzer[];\n }) => Promise<{ locationAnalyzer: LocationAnalyzer }>)\n | undefined = undefined;\n const scmLocationAnalyzers = new Array<ScmLocationAnalyzer>();\n env.registerExtensionPoint(catalogAnalysisExtensionPoint, {\n setLocationAnalyzer(analyzerOrFactory) {\n if (locationAnalyzerFactory) {\n throw new Error('LocationAnalyzer has already been set');\n }\n if (typeof analyzerOrFactory === 'function') {\n locationAnalyzerFactory = analyzerOrFactory;\n } else {\n locationAnalyzerFactory = async () => ({\n locationAnalyzer: analyzerOrFactory,\n });\n }\n },\n addScmLocationAnalyzer(analyzer: ScmLocationAnalyzer) {\n scmLocationAnalyzers.push(analyzer);\n },\n });\n\n const permissionExtensions = new CatalogPermissionExtensionPointImpl();\n env.registerExtensionPoint(\n catalogPermissionExtensionPoint,\n permissionExtensions,\n );\n\n const modelExtensions = new CatalogModelExtensionPointImpl();\n env.registerExtensionPoint(catalogModelExtensionPoint, modelExtensions);\n\n const locationTypeExtensions = new CatalogLocationsExtensionPointImpl();\n env.registerExtensionPoint(\n catalogLocationsExtensionPoint,\n locationTypeExtensions,\n );\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n httpRouter: coreServices.httpRouter,\n lifecycle: coreServices.rootLifecycle,\n scheduler: coreServices.scheduler,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n events: eventsServiceRef,\n },\n async init({\n logger,\n config,\n reader,\n database,\n permissions,\n httpRouter,\n lifecycle,\n scheduler,\n discovery,\n auth,\n httpAuth,\n events,\n }) {\n const builder = await CatalogBuilder.create({\n config,\n reader,\n permissions,\n database,\n scheduler,\n logger,\n discovery,\n auth,\n httpAuth,\n });\n\n builder.setEventBroker(events);\n\n if (processingExtensions.onProcessingErrorHandler) {\n builder.subscribe({\n onProcessingError: processingExtensions.onProcessingErrorHandler,\n });\n }\n builder.addProcessor(...processingExtensions.processors);\n builder.addEntityProvider(...processingExtensions.entityProviders);\n\n if (modelExtensions.entityDataParser) {\n builder.setEntityDataParser(modelExtensions.entityDataParser);\n }\n\n Object.entries(processingExtensions.placeholderResolvers).forEach(\n ([key, resolver]) => builder.setPlaceholderResolver(key, resolver),\n );\n if (locationAnalyzerFactory) {\n const { locationAnalyzer } = await locationAnalyzerFactory({\n scmLocationAnalyzers,\n }).catch(e => {\n throw new ForwardedError('Failed to create LocationAnalyzer', e);\n });\n builder.setLocationAnalyzer(locationAnalyzer);\n } else {\n builder.addLocationAnalyzers(...scmLocationAnalyzers);\n }\n builder.addPermissions(...permissionExtensions.permissions);\n builder.addPermissionRules(...permissionExtensions.permissionRules);\n builder.setFieldFormatValidators(modelExtensions.fieldValidators);\n\n if (locationTypeExtensions.allowedLocationTypes) {\n builder.setAllowedLocationTypes(\n locationTypeExtensions.allowedLocationTypes,\n );\n }\n\n const { processingEngine, router } = await builder.build();\n\n lifecycle.addStartupHook(async () => {\n await processingEngine.start();\n });\n lifecycle.addShutdownHook(() => processingEngine.stop());\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["merge","createBackendPlugin","catalogProcessingExtensionPoint","catalogAnalysisExtensionPoint","catalogPermissionExtensionPoint","catalogModelExtensionPoint","catalogLocationsExtensionPoint","coreServices","eventsServiceRef","CatalogBuilder","ForwardedError"],"mappings":";;;;;;;;;AA6CA,MAAM,kCAEN,CAAA;AAAA,EACE,cAAA,CAAA;AAAA,EAEA,wBAAwB,aAA8B,EAAA;AACpD,IAAA,IAAA,CAAK,cAAiB,GAAA,aAAA,CAAA;AAAA,GACxB;AAAA,EAEA,IAAI,oBAAuB,GAAA;AACzB,IAAA,OAAO,IAAK,CAAA,cAAA,CAAA;AAAA,GACd;AACF,CAAA;AAEA,MAAM,mCAEN,CAAA;AAAA,EACE,WAAA,GAAc,IAAI,KAAwB,EAAA,CAAA;AAAA,EAC1C,gBAAA,GAAmB,IAAI,KAAsB,EAAA,CAAA;AAAA,EAC7C,wBAA6D,EAAC,CAAA;AAAA,EAC9D,yBAAA,CAAA;AAAA,EAKA,gBACK,UACG,EAAA;AACN,IAAA,IAAA,CAAK,WAAY,CAAA,IAAA,CAAK,GAAG,UAAA,CAAW,MAAM,CAAA,CAAA;AAAA,GAC5C;AAAA,EAEA,qBACK,SACG,EAAA;AACN,IAAA,IAAA,CAAK,gBAAiB,CAAA,IAAA,CAAK,GAAG,SAAA,CAAU,MAAM,CAAA,CAAA;AAAA,GAChD;AAAA,EAEA,sBAAA,CAAuB,KAAa,QAA+B,EAAA;AACjE,IAAA,IAAI,OAAO,IAAK,CAAA,qBAAA;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,+BAA+B,GAAG,CAAA,oDAAA,CAAA;AAAA,OACpC,CAAA;AACF,IAAK,IAAA,CAAA,qBAAA,CAAsB,GAAG,CAAI,GAAA,QAAA,CAAA;AAAA,GACpC;AAAA,EAEA,4BACE,OAIA,EAAA;AACA,IAAA,IAAA,CAAK,yBAA4B,GAAA,OAAA,CAAA;AAAA,GACnC;AAAA,EAEA,IAAI,UAAa,GAAA;AACf,IAAA,OAAO,IAAK,CAAA,WAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,eAAkB,GAAA;AACpB,IAAA,OAAO,IAAK,CAAA,gBAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,oBAAuB,GAAA;AACzB,IAAA,OAAO,IAAK,CAAA,qBAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,wBAA2B,GAAA;AAC7B,IAAA,OAAO,IAAK,CAAA,yBAAA,CAAA;AAAA,GACd;AACF,CAAA;AAEA,MAAM,mCAEN,CAAA;AAAA,EACE,YAAA,GAAe,IAAI,KAAkB,EAAA,CAAA;AAAA,EACrC,gBAAA,GAAmB,IAAI,KAAkC,EAAA,CAAA;AAAA,EAEzD,kBAAkB,UAAyD,EAAA;AACzE,IAAA,IAAA,CAAK,YAAa,CAAA,IAAA,CAAK,GAAG,UAAA,CAAW,MAAM,CAAA,CAAA;AAAA,GAC7C;AAAA,EAEA,sBACK,KAGG,EAAA;AACN,IAAA,IAAA,CAAK,gBAAiB,CAAA,IAAA,CAAK,GAAG,KAAA,CAAM,MAAM,CAAA,CAAA;AAAA,GAC5C;AAAA,EAEA,IAAI,WAAc,GAAA;AAChB,IAAA,OAAO,IAAK,CAAA,YAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,eAAkB,GAAA;AACpB,IAAA,OAAO,IAAK,CAAA,gBAAA,CAAA;AAAA,GACd;AACF,CAAA;AAEA,MAAM,8BAAqE,CAAA;AAAA,EACzE,mBAAwC,EAAC,CAAA;AAAA,EAEzC,mBAAmB,UAAuC,EAAA;AACxD,IAAMA,YAAA,CAAA,IAAA,CAAK,kBAAkB,UAAU,CAAA,CAAA;AAAA,GACzC;AAAA,EAEA,IAAI,eAAkB,GAAA;AACpB,IAAA,OAAO,IAAK,CAAA,gBAAA,CAAA;AAAA,GACd;AAAA,EAEA,iBAAA,CAAA;AAAA,EAEA,oBAAoB,MAAsC,EAAA;AACxD,IAAA,IAAI,KAAK,iBAAmB,EAAA;AAC1B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,oEAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,iBAAoB,GAAA,MAAA,CAAA;AAAA,GAC3B;AAAA,EAEA,IAAI,gBAAmB,GAAA;AACrB,IAAA,OAAO,IAAK,CAAA,iBAAA,CAAA;AAAA,GACd;AACF,CAAA;AAMO,MAAM,gBAAgBC,oCAAoB,CAAA;AAAA,EAC/C,QAAU,EAAA,SAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAM,MAAA,oBAAA,GAAuB,IAAI,mCAAoC,EAAA,CAAA;AAErE,IAAI,GAAA,CAAA,sBAAA;AAAA,MACFC,qCAAA;AAAA,MACA,oBAAA;AAAA,KACF,CAAA;AAEA,IAAA,IAAI,uBAIY,GAAA,KAAA,CAAA,CAAA;AAChB,IAAM,MAAA,oBAAA,GAAuB,IAAI,KAA2B,EAAA,CAAA;AAC5D,IAAA,GAAA,CAAI,uBAAuBC,mCAA+B,EAAA;AAAA,MACxD,oBAAoB,iBAAmB,EAAA;AACrC,QAAA,IAAI,uBAAyB,EAAA;AAC3B,UAAM,MAAA,IAAI,MAAM,uCAAuC,CAAA,CAAA;AAAA,SACzD;AACA,QAAI,IAAA,OAAO,sBAAsB,UAAY,EAAA;AAC3C,UAA0B,uBAAA,GAAA,iBAAA,CAAA;AAAA,SACrB,MAAA;AACL,UAAA,uBAAA,GAA0B,aAAa;AAAA,YACrC,gBAAkB,EAAA,iBAAA;AAAA,WACpB,CAAA,CAAA;AAAA,SACF;AAAA,OACF;AAAA,MACA,uBAAuB,QAA+B,EAAA;AACpD,QAAA,oBAAA,CAAqB,KAAK,QAAQ,CAAA,CAAA;AAAA,OACpC;AAAA,KACD,CAAA,CAAA;AAED,IAAM,MAAA,oBAAA,GAAuB,IAAI,mCAAoC,EAAA,CAAA;AACrE,IAAI,GAAA,CAAA,sBAAA;AAAA,MACFC,qCAAA;AAAA,MACA,oBAAA;AAAA,KACF,CAAA;AAEA,IAAM,MAAA,eAAA,GAAkB,IAAI,8BAA+B,EAAA,CAAA;AAC3D,IAAI,GAAA,CAAA,sBAAA,CAAuBC,kCAA4B,eAAe,CAAA,CAAA;AAEtE,IAAM,MAAA,sBAAA,GAAyB,IAAI,kCAAmC,EAAA,CAAA;AACtE,IAAI,GAAA,CAAA,sBAAA;AAAA,MACFC,oCAAA;AAAA,MACA,sBAAA;AAAA,KACF,CAAA;AAEA,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,MAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,UAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,SAAA;AAAA,QACrB,aAAaA,6BAAa,CAAA,WAAA;AAAA,QAC1B,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,WAAWA,6BAAa,CAAA,aAAA;AAAA,QACxB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,MAAMA,6BAAa,CAAA,IAAA;AAAA,QACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,MAAQ,EAAAC,iCAAA;AAAA,OACV;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,MAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA,UAAA;AAAA,QACA,SAAA;AAAA,QACA,SAAA;AAAA,QACA,SAAA;AAAA,QACA,IAAA;AAAA,QACA,QAAA;AAAA,QACA,MAAA;AAAA,OACC,EAAA;AACD,QAAM,MAAA,OAAA,GAAU,MAAMC,6BAAA,CAAe,MAAO,CAAA;AAAA,UAC1C,MAAA;AAAA,UACA,MAAA;AAAA,UACA,WAAA;AAAA,UACA,QAAA;AAAA,UACA,SAAA;AAAA,UACA,MAAA;AAAA,UACA,SAAA;AAAA,UACA,IAAA;AAAA,UACA,QAAA;AAAA,SACD,CAAA,CAAA;AAED,QAAA,OAAA,CAAQ,eAAe,MAAM,CAAA,CAAA;AAE7B,QAAA,IAAI,qBAAqB,wBAA0B,EAAA;AACjD,UAAA,OAAA,CAAQ,SAAU,CAAA;AAAA,YAChB,mBAAmB,oBAAqB,CAAA,wBAAA;AAAA,WACzC,CAAA,CAAA;AAAA,SACH;AACA,QAAQ,OAAA,CAAA,YAAA,CAAa,GAAG,oBAAA,CAAqB,UAAU,CAAA,CAAA;AACvD,QAAQ,OAAA,CAAA,iBAAA,CAAkB,GAAG,oBAAA,CAAqB,eAAe,CAAA,CAAA;AAEjE,QAAA,IAAI,gBAAgB,gBAAkB,EAAA;AACpC,UAAQ,OAAA,CAAA,mBAAA,CAAoB,gBAAgB,gBAAgB,CAAA,CAAA;AAAA,SAC9D;AAEA,QAAO,MAAA,CAAA,OAAA,CAAQ,oBAAqB,CAAA,oBAAoB,CAAE,CAAA,OAAA;AAAA,UACxD,CAAC,CAAC,GAAK,EAAA,QAAQ,MAAM,OAAQ,CAAA,sBAAA,CAAuB,KAAK,QAAQ,CAAA;AAAA,SACnE,CAAA;AACA,QAAA,IAAI,uBAAyB,EAAA;AAC3B,UAAA,MAAM,EAAE,gBAAA,EAAqB,GAAA,MAAM,uBAAwB,CAAA;AAAA,YACzD,oBAAA;AAAA,WACD,CAAE,CAAA,KAAA,CAAM,CAAK,CAAA,KAAA;AACZ,YAAM,MAAA,IAAIC,qBAAe,CAAA,mCAAA,EAAqC,CAAC,CAAA,CAAA;AAAA,WAChE,CAAA,CAAA;AACD,UAAA,OAAA,CAAQ,oBAAoB,gBAAgB,CAAA,CAAA;AAAA,SACvC,MAAA;AACL,UAAQ,OAAA,CAAA,oBAAA,CAAqB,GAAG,oBAAoB,CAAA,CAAA;AAAA,SACtD;AACA,QAAQ,OAAA,CAAA,cAAA,CAAe,GAAG,oBAAA,CAAqB,WAAW,CAAA,CAAA;AAC1D,QAAQ,OAAA,CAAA,kBAAA,CAAmB,GAAG,oBAAA,CAAqB,eAAe,CAAA,CAAA;AAClE,QAAQ,OAAA,CAAA,wBAAA,CAAyB,gBAAgB,eAAe,CAAA,CAAA;AAEhE,QAAA,IAAI,uBAAuB,oBAAsB,EAAA;AAC/C,UAAQ,OAAA,CAAA,uBAAA;AAAA,YACN,sBAAuB,CAAA,oBAAA;AAAA,WACzB,CAAA;AAAA,SACF;AAEA,QAAA,MAAM,EAAE,gBAAkB,EAAA,MAAA,EAAW,GAAA,MAAM,QAAQ,KAAM,EAAA,CAAA;AAEzD,QAAA,SAAA,CAAU,eAAe,YAAY;AACnC,UAAA,MAAM,iBAAiB,KAAM,EAAA,CAAA;AAAA,SAC9B,CAAA,CAAA;AACD,QAAA,SAAA,CAAU,eAAgB,CAAA,MAAM,gBAAiB,CAAA,IAAA,EAAM,CAAA,CAAA;AACvD,QAAA,UAAA,CAAW,IAAI,MAAM,CAAA,CAAA;AAAA,OACvB;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"CatalogPlugin.cjs.js","sources":["../../src/service/CatalogPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 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 */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport { Entity, Validators } from '@backstage/catalog-model';\nimport { CatalogBuilder, CatalogPermissionRuleInput } from './CatalogBuilder';\nimport {\n catalogAnalysisExtensionPoint,\n CatalogModelExtensionPoint,\n catalogModelExtensionPoint,\n CatalogPermissionExtensionPoint,\n catalogPermissionExtensionPoint,\n CatalogProcessingExtensionPoint,\n catalogProcessingExtensionPoint,\n CatalogLocationsExtensionPoint,\n catalogLocationsExtensionPoint,\n} from '@backstage/plugin-catalog-node/alpha';\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntityProvider,\n LocationAnalyzer,\n PlaceholderResolver,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport { merge } from 'lodash';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport { ForwardedError } from '@backstage/errors';\n\nclass CatalogLocationsExtensionPointImpl\n implements CatalogLocationsExtensionPoint\n{\n #locationTypes: string[] | undefined;\n\n setAllowedLocationTypes(locationTypes: Array<string>) {\n this.#locationTypes = locationTypes;\n }\n\n get allowedLocationTypes() {\n return this.#locationTypes;\n }\n}\n\nclass CatalogProcessingExtensionPointImpl\n implements CatalogProcessingExtensionPoint\n{\n #processors = new Array<CatalogProcessor>();\n #entityProviders = new Array<EntityProvider>();\n #placeholderResolvers: Record<string, PlaceholderResolver> = {};\n #onProcessingErrorHandler?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): void {\n this.#entityProviders.push(...providers.flat());\n }\n\n addPlaceholderResolver(key: string, resolver: PlaceholderResolver) {\n if (key in this.#placeholderResolvers)\n throw new Error(\n `A placeholder resolver for '${key}' has already been set up, please check your config.`,\n );\n this.#placeholderResolvers[key] = resolver;\n }\n\n setOnProcessingErrorHandler(\n handler: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void,\n ) {\n this.#onProcessingErrorHandler = handler;\n }\n\n get processors() {\n return this.#processors;\n }\n\n get entityProviders() {\n return this.#entityProviders;\n }\n\n get placeholderResolvers() {\n return this.#placeholderResolvers;\n }\n\n get onProcessingErrorHandler() {\n return this.#onProcessingErrorHandler;\n }\n}\n\nclass CatalogPermissionExtensionPointImpl\n implements CatalogPermissionExtensionPoint\n{\n #permissions = new Array<Permission>();\n #permissionRules = new Array<CatalogPermissionRuleInput>();\n\n addPermissions(...permission: Array<Permission | Array<Permission>>): void {\n this.#permissions.push(...permission.flat());\n }\n\n addPermissionRules(\n ...rules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ): void {\n this.#permissionRules.push(...rules.flat());\n }\n\n get permissions() {\n return this.#permissions;\n }\n\n get permissionRules() {\n return this.#permissionRules;\n }\n}\n\nclass CatalogModelExtensionPointImpl implements CatalogModelExtensionPoint {\n #fieldValidators: Partial<Validators> = {};\n\n setFieldValidators(validators: Partial<Validators>): void {\n merge(this.#fieldValidators, validators);\n }\n\n get fieldValidators() {\n return this.#fieldValidators;\n }\n\n #entityDataParser?: CatalogProcessorParser;\n\n setEntityDataParser(parser: CatalogProcessorParser): void {\n if (this.#entityDataParser) {\n throw new Error(\n 'Attempted to install second EntityDataParser. Only one can be set.',\n );\n }\n this.#entityDataParser = parser;\n }\n\n get entityDataParser() {\n return this.#entityDataParser;\n }\n}\n\n/**\n * Catalog plugin\n * @public\n */\nexport const catalogPlugin = createBackendPlugin({\n pluginId: 'catalog',\n register(env) {\n const processingExtensions = new CatalogProcessingExtensionPointImpl();\n // plugins depending on this API will be initialized before this plugins init method is executed.\n env.registerExtensionPoint(\n catalogProcessingExtensionPoint,\n processingExtensions,\n );\n\n let locationAnalyzerFactory:\n | ((options: {\n scmLocationAnalyzers: ScmLocationAnalyzer[];\n }) => Promise<{ locationAnalyzer: LocationAnalyzer }>)\n | undefined = undefined;\n const scmLocationAnalyzers = new Array<ScmLocationAnalyzer>();\n env.registerExtensionPoint(catalogAnalysisExtensionPoint, {\n setLocationAnalyzer(analyzerOrFactory) {\n if (locationAnalyzerFactory) {\n throw new Error('LocationAnalyzer has already been set');\n }\n if (typeof analyzerOrFactory === 'function') {\n locationAnalyzerFactory = analyzerOrFactory;\n } else {\n locationAnalyzerFactory = async () => ({\n locationAnalyzer: analyzerOrFactory,\n });\n }\n },\n addScmLocationAnalyzer(analyzer: ScmLocationAnalyzer) {\n scmLocationAnalyzers.push(analyzer);\n },\n });\n\n const permissionExtensions = new CatalogPermissionExtensionPointImpl();\n env.registerExtensionPoint(\n catalogPermissionExtensionPoint,\n permissionExtensions,\n );\n\n const modelExtensions = new CatalogModelExtensionPointImpl();\n env.registerExtensionPoint(catalogModelExtensionPoint, modelExtensions);\n\n const locationTypeExtensions = new CatalogLocationsExtensionPointImpl();\n env.registerExtensionPoint(\n catalogLocationsExtensionPoint,\n locationTypeExtensions,\n );\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n httpRouter: coreServices.httpRouter,\n lifecycle: coreServices.rootLifecycle,\n scheduler: coreServices.scheduler,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n events: eventsServiceRef,\n },\n async init({\n logger,\n config,\n reader,\n database,\n permissions,\n httpRouter,\n lifecycle,\n scheduler,\n discovery,\n auth,\n httpAuth,\n events,\n }) {\n const builder = await CatalogBuilder.create({\n config,\n reader,\n permissions,\n database,\n scheduler,\n logger,\n discovery,\n auth,\n httpAuth,\n });\n\n builder.setEventBroker(events);\n\n if (processingExtensions.onProcessingErrorHandler) {\n builder.subscribe({\n onProcessingError: processingExtensions.onProcessingErrorHandler,\n });\n }\n builder.addProcessor(...processingExtensions.processors);\n builder.addEntityProvider(...processingExtensions.entityProviders);\n\n if (modelExtensions.entityDataParser) {\n builder.setEntityDataParser(modelExtensions.entityDataParser);\n }\n\n Object.entries(processingExtensions.placeholderResolvers).forEach(\n ([key, resolver]) => builder.setPlaceholderResolver(key, resolver),\n );\n if (locationAnalyzerFactory) {\n const { locationAnalyzer } = await locationAnalyzerFactory({\n scmLocationAnalyzers,\n }).catch(e => {\n throw new ForwardedError('Failed to create LocationAnalyzer', e);\n });\n builder.setLocationAnalyzer(locationAnalyzer);\n } else {\n builder.addLocationAnalyzers(...scmLocationAnalyzers);\n }\n builder.addPermissions(...permissionExtensions.permissions);\n builder.addPermissionRules(...permissionExtensions.permissionRules);\n builder.setFieldFormatValidators(modelExtensions.fieldValidators);\n\n if (locationTypeExtensions.allowedLocationTypes) {\n builder.setAllowedLocationTypes(\n locationTypeExtensions.allowedLocationTypes,\n );\n }\n\n const { processingEngine, router } = await builder.build();\n\n if (config.getOptional('catalog.processingInterval') ?? true) {\n lifecycle.addStartupHook(async () => {\n await processingEngine.start();\n });\n lifecycle.addShutdownHook(() => processingEngine.stop());\n }\n\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["merge","createBackendPlugin","catalogProcessingExtensionPoint","catalogAnalysisExtensionPoint","catalogPermissionExtensionPoint","catalogModelExtensionPoint","catalogLocationsExtensionPoint","coreServices","eventsServiceRef","CatalogBuilder","ForwardedError"],"mappings":"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"}
@@ -1,7 +1,9 @@
1
1
  'use strict';
2
2
 
3
- function stitchingStrategyFromConfig(config) {
4
- const strategyMode = config.getOptionalString(
3
+ var config = require('@backstage/config');
4
+
5
+ function stitchingStrategyFromConfig(config$1) {
6
+ const strategyMode = config$1.getOptionalString(
5
7
  "catalog.stitchingStrategy.mode"
6
8
  );
7
9
  if (strategyMode === void 0 || strategyMode === "immediate") {
@@ -9,10 +11,18 @@ function stitchingStrategyFromConfig(config) {
9
11
  mode: "immediate"
10
12
  };
11
13
  } else if (strategyMode === "deferred") {
14
+ const pollingIntervalKey = "catalog.stitchingStrategy.pollingInterval";
15
+ const stitchTimeoutKey = "catalog.stitchingStrategy.stitchTimeout";
16
+ const pollingInterval = config$1.has(pollingIntervalKey) ? config.readDurationFromConfig(config$1, {
17
+ key: pollingIntervalKey
18
+ }) : { seconds: 1 };
19
+ const stitchTimeout = config$1.has(stitchTimeoutKey) ? config.readDurationFromConfig(config$1, {
20
+ key: stitchTimeoutKey
21
+ }) : { seconds: 60 };
12
22
  return {
13
23
  mode: "deferred",
14
- pollingInterval: { seconds: 1 },
15
- stitchTimeout: { seconds: 60 }
24
+ pollingInterval,
25
+ stitchTimeout
16
26
  };
17
27
  }
18
28
  throw new Error(
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs.js","sources":["../../src/stitching/types.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 { Config } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport interface Stitcher {\n stitch(options: {\n entityRefs?: Iterable<string>;\n entityIds?: Iterable<string>;\n }): Promise<void>;\n}\n\n/**\n * The strategies supported by the stitching process, in terms of when to\n * perform stitching.\n *\n * @remarks\n *\n * In immediate mode, stitching happens \"in-band\" (blocking) immediately when\n * each processing task finishes. When set to `'deferred'`, stitching is instead\n * deferred to happen on a separate asynchronous worker queue just like\n * processing.\n *\n * Deferred stitching should make performance smoother when ingesting large\n * amounts of entities, and reduce p99 processing times and repeated\n * over-stitching of hot spot entities when fan-out/fan-in in terms of relations\n * is very large. It does however also come with some performance cost due to\n * the queuing with how much wall-clock time some types of task take.\n */\nexport type StitchingStrategy =\n | {\n mode: 'immediate';\n }\n | {\n mode: 'deferred';\n pollingInterval: HumanDuration;\n stitchTimeout: HumanDuration;\n };\n\nexport function stitchingStrategyFromConfig(config: Config): StitchingStrategy {\n const strategyMode = config.getOptionalString(\n 'catalog.stitchingStrategy.mode',\n );\n\n if (strategyMode === undefined || strategyMode === 'immediate') {\n return {\n mode: 'immediate',\n };\n } else if (strategyMode === 'deferred') {\n // TODO(freben): Make parameters configurable\n return {\n mode: 'deferred',\n pollingInterval: { seconds: 1 },\n stitchTimeout: { seconds: 60 },\n };\n }\n\n throw new Error(\n `Invalid stitching strategy mode '${strategyMode}', expected one of 'immediate' or 'deferred'`,\n );\n}\n"],"names":[],"mappings":";;AA0DO,SAAS,4BAA4B,MAAmC,EAAA;AAC7E,EAAA,MAAM,eAAe,MAAO,CAAA,iBAAA;AAAA,IAC1B,gCAAA;AAAA,GACF,CAAA;AAEA,EAAI,IAAA,YAAA,KAAiB,KAAa,CAAA,IAAA,YAAA,KAAiB,WAAa,EAAA;AAC9D,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,WAAA;AAAA,KACR,CAAA;AAAA,GACF,MAAA,IAAW,iBAAiB,UAAY,EAAA;AAEtC,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,UAAA;AAAA,MACN,eAAA,EAAiB,EAAE,OAAA,EAAS,CAAE,EAAA;AAAA,MAC9B,aAAA,EAAe,EAAE,OAAA,EAAS,EAAG,EAAA;AAAA,KAC/B,CAAA;AAAA,GACF;AAEA,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,oCAAoC,YAAY,CAAA,4CAAA,CAAA;AAAA,GAClD,CAAA;AACF;;;;"}
1
+ {"version":3,"file":"types.cjs.js","sources":["../../src/stitching/types.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 { Config, readDurationFromConfig } from '@backstage/config';\nimport { HumanDuration } from '@backstage/types';\n\n/**\n * Performs the act of stitching - to take all of the various outputs from the\n * ingestion process, and stitching them together into the final entity JSON\n * shape.\n */\nexport interface Stitcher {\n stitch(options: {\n entityRefs?: Iterable<string>;\n entityIds?: Iterable<string>;\n }): Promise<void>;\n}\n\n/**\n * The strategies supported by the stitching process, in terms of when to\n * perform stitching.\n *\n * @remarks\n *\n * In immediate mode, stitching happens \"in-band\" (blocking) immediately when\n * each processing task finishes. When set to `'deferred'`, stitching is instead\n * deferred to happen on a separate asynchronous worker queue just like\n * processing.\n *\n * Deferred stitching should make performance smoother when ingesting large\n * amounts of entities, and reduce p99 processing times and repeated\n * over-stitching of hot spot entities when fan-out/fan-in in terms of relations\n * is very large. It does however also come with some performance cost due to\n * the queuing with how much wall-clock time some types of task take.\n */\nexport type StitchingStrategy =\n | {\n mode: 'immediate';\n }\n | {\n mode: 'deferred';\n pollingInterval: HumanDuration;\n stitchTimeout: HumanDuration;\n };\n\nexport function stitchingStrategyFromConfig(config: Config): StitchingStrategy {\n const strategyMode = config.getOptionalString(\n 'catalog.stitchingStrategy.mode',\n );\n\n if (strategyMode === undefined || strategyMode === 'immediate') {\n return {\n mode: 'immediate',\n };\n } else if (strategyMode === 'deferred') {\n const pollingIntervalKey = 'catalog.stitchingStrategy.pollingInterval';\n const stitchTimeoutKey = 'catalog.stitchingStrategy.stitchTimeout';\n\n const pollingInterval = config.has(pollingIntervalKey)\n ? readDurationFromConfig(config, {\n key: pollingIntervalKey,\n })\n : { seconds: 1 };\n const stitchTimeout = config.has(stitchTimeoutKey)\n ? readDurationFromConfig(config, {\n key: stitchTimeoutKey,\n })\n : { seconds: 60 };\n return {\n mode: 'deferred',\n pollingInterval: pollingInterval,\n stitchTimeout: stitchTimeout,\n };\n }\n\n throw new Error(\n `Invalid stitching strategy mode '${strategyMode}', expected one of 'immediate' or 'deferred'`,\n );\n}\n"],"names":["config","readDurationFromConfig"],"mappings":";;;;AA0DO,SAAS,4BAA4BA,QAAmC,EAAA;AAC7E,EAAA,MAAM,eAAeA,QAAO,CAAA,iBAAA;AAAA,IAC1B,gCAAA;AAAA,GACF,CAAA;AAEA,EAAI,IAAA,YAAA,KAAiB,KAAa,CAAA,IAAA,YAAA,KAAiB,WAAa,EAAA;AAC9D,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,WAAA;AAAA,KACR,CAAA;AAAA,GACF,MAAA,IAAW,iBAAiB,UAAY,EAAA;AACtC,IAAA,MAAM,kBAAqB,GAAA,2CAAA,CAAA;AAC3B,IAAA,MAAM,gBAAmB,GAAA,yCAAA,CAAA;AAEzB,IAAA,MAAM,kBAAkBA,QAAO,CAAA,GAAA,CAAI,kBAAkB,CAAA,GACjDC,8BAAuBD,QAAQ,EAAA;AAAA,MAC7B,GAAK,EAAA,kBAAA;AAAA,KACN,CAAA,GACD,EAAE,OAAA,EAAS,CAAE,EAAA,CAAA;AACjB,IAAA,MAAM,gBAAgBA,QAAO,CAAA,GAAA,CAAI,gBAAgB,CAAA,GAC7CC,8BAAuBD,QAAQ,EAAA;AAAA,MAC7B,GAAK,EAAA,gBAAA;AAAA,KACN,CAAA,GACD,EAAE,OAAA,EAAS,EAAG,EAAA,CAAA;AAClB,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,UAAA;AAAA,MACN,eAAA;AAAA,MACA,aAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,oCAAoC,YAAY,CAAA,4CAAA,CAAA;AAAA,GAClD,CAAA;AACF;;;;"}
@@ -0,0 +1,47 @@
1
+ /*
2
+ * Copyright 2024 The Backstage Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ // @ts-check
18
+
19
+ /**
20
+ * @param { import("knex").Knex } knex
21
+ * @returns { Promise<void> }
22
+ */
23
+ exports.up = async function up(knex) {
24
+ await knex.schema.alterTable('locations', table => {
25
+ table.text('target').alter();
26
+ });
27
+ };
28
+
29
+ /**
30
+ * @param { import("knex").Knex } knex
31
+ * @returns { Promise<void> }
32
+ */
33
+ exports.down = async function down(knex) {
34
+ const oversizedEntries = await knex('locations').where(
35
+ knex.raw('LENGTH(target) > 255'),
36
+ );
37
+
38
+ if (oversizedEntries.length > 0) {
39
+ throw new Error(
40
+ `Migration aborted: Found ${oversizedEntries.length} entries with 'target' exceeding 255 characters. Manual intervention required.`,
41
+ );
42
+ }
43
+
44
+ await knex.schema.alterTable('locations', table => {
45
+ table.string('target').alter();
46
+ });
47
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend",
3
- "version": "1.26.2-next.2",
3
+ "version": "1.27.0",
4
4
  "description": "The Backstage backend plugin that provides the Backstage catalog",
5
5
  "backstage": {
6
6
  "role": "backend-plugin",
@@ -28,6 +28,7 @@
28
28
  "license": "Apache-2.0",
29
29
  "exports": {
30
30
  ".": {
31
+ "backstage": "@backstage/BackendFeature",
31
32
  "require": "./dist/index.cjs.js",
32
33
  "types": "./dist/index.d.ts",
33
34
  "default": "./dist/index.cjs.js"
@@ -62,20 +63,20 @@
62
63
  },
63
64
  "dependencies": {
64
65
  "@backstage/backend-common": "^0.25.0",
65
- "@backstage/backend-openapi-utils": "0.2.0-next.1",
66
- "@backstage/backend-plugin-api": "1.0.1-next.1",
67
- "@backstage/catalog-client": "1.7.1-next.0",
68
- "@backstage/catalog-model": "1.7.0",
69
- "@backstage/config": "1.2.0",
70
- "@backstage/errors": "1.2.4",
71
- "@backstage/integration": "1.15.1-next.1",
72
- "@backstage/plugin-catalog-common": "1.1.0",
73
- "@backstage/plugin-catalog-node": "1.13.1-next.1",
74
- "@backstage/plugin-events-node": "0.4.1-next.1",
75
- "@backstage/plugin-permission-common": "0.8.1",
76
- "@backstage/plugin-permission-node": "0.8.4-next.1",
77
- "@backstage/plugin-search-backend-module-catalog": "0.2.3-next.2",
78
- "@backstage/types": "1.1.1",
66
+ "@backstage/backend-openapi-utils": "^0.2.0",
67
+ "@backstage/backend-plugin-api": "^1.0.1",
68
+ "@backstage/catalog-client": "^1.7.1",
69
+ "@backstage/catalog-model": "^1.7.0",
70
+ "@backstage/config": "^1.2.0",
71
+ "@backstage/errors": "^1.2.4",
72
+ "@backstage/integration": "^1.15.1",
73
+ "@backstage/plugin-catalog-common": "^1.1.0",
74
+ "@backstage/plugin-catalog-node": "^1.13.1",
75
+ "@backstage/plugin-events-node": "^0.4.1",
76
+ "@backstage/plugin-permission-common": "^0.8.1",
77
+ "@backstage/plugin-permission-node": "^0.8.4",
78
+ "@backstage/plugin-search-backend-module-catalog": "^0.2.3",
79
+ "@backstage/types": "^1.1.1",
79
80
  "@opentelemetry/api": "^1.3.0",
80
81
  "@types/express": "^4.17.6",
81
82
  "codeowners-utils": "^1.0.2",
@@ -98,11 +99,11 @@
98
99
  "zod": "^3.22.4"
99
100
  },
100
101
  "devDependencies": {
101
- "@backstage/backend-defaults": "0.5.1-next.2",
102
- "@backstage/backend-test-utils": "1.0.1-next.2",
103
- "@backstage/cli": "0.28.0-next.2",
104
- "@backstage/plugin-permission-common": "0.8.1",
105
- "@backstage/repo-tools": "0.10.0-next.2",
102
+ "@backstage/backend-defaults": "^0.5.1",
103
+ "@backstage/backend-test-utils": "^1.0.1",
104
+ "@backstage/cli": "^0.28.0",
105
+ "@backstage/plugin-permission-common": "^0.8.1",
106
+ "@backstage/repo-tools": "^0.10.0",
106
107
  "@types/core-js": "^2.5.4",
107
108
  "@types/git-url-parse": "^9.0.0",
108
109
  "@types/glob": "^8.0.0",