@backstage/plugin-catalog-backend 1.1.0-next.1 → 1.1.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @backstage/plugin-catalog-backend
2
2
 
3
+ ## 1.1.0-next.2
4
+
5
+ ### Minor Changes
6
+
7
+ - bf82edf4c9: Added `/validate-entity` endpoint
8
+
9
+ ### Patch Changes
10
+
11
+ - 8592cacfd3: Fixed an issue where sometimes entities would have stale relations "stuck" and
12
+ not getting removed as expected, after the other end of the relation had stopped
13
+ referring to them.
14
+ - Updated dependencies
15
+ - @backstage/catalog-model@1.0.1-next.1
16
+
3
17
  ## 1.1.0-next.1
4
18
 
5
19
  ### Minor Changes
package/README.md CHANGED
@@ -27,8 +27,7 @@ restoring the plugin, if you previously removed it.
27
27
 
28
28
  ```bash
29
29
  # From your Backstage root directory
30
- cd packages/backend
31
- yarn add @backstage/plugin-catalog-backend
30
+ yarn add --cwd packages/backend @backstage/plugin-catalog-backend
32
31
  ```
33
32
 
34
33
  ### Adding the plugin to your `packages/backend`
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend",
3
- "version": "1.1.0-next.1",
3
+ "version": "1.1.0-next.2",
4
4
  "main": "../dist/index.cjs.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
package/dist/index.cjs.js CHANGED
@@ -1318,7 +1318,13 @@ class DefaultProcessingDatabase {
1318
1318
  entities: deferredEntities,
1319
1319
  sourceEntityRef: catalogModel.stringifyEntityRef(processedEntity)
1320
1320
  });
1321
- await tx("relations").where({ originating_entity_id: id }).delete();
1321
+ let previousRelationRows;
1322
+ if (tx.client.config.client.includes("sqlite3")) {
1323
+ previousRelationRows = await tx("relations").select("*").where({ originating_entity_id: id });
1324
+ await tx("relations").where({ originating_entity_id: id }).delete();
1325
+ } else {
1326
+ previousRelationRows = await tx("relations").where({ originating_entity_id: id }).delete().returning("*");
1327
+ }
1322
1328
  const relationRows = relations.map(({ source, target, type }) => ({
1323
1329
  originating_entity_id: id,
1324
1330
  source_entity_ref: catalogModel.stringifyEntityRef(source),
@@ -1326,6 +1332,11 @@ class DefaultProcessingDatabase {
1326
1332
  type
1327
1333
  }));
1328
1334
  await tx.batchInsert("relations", this.deduplicateRelations(relationRows), BATCH_SIZE$1);
1335
+ return {
1336
+ previous: {
1337
+ relations: previousRelationRows
1338
+ }
1339
+ };
1329
1340
  }
1330
1341
  async updateProcessedEntityErrors(txOpaque, options) {
1331
1342
  const tx = txOpaque;
@@ -1802,8 +1813,9 @@ class DefaultCatalogProcessingEngine {
1802
1813
  return;
1803
1814
  }
1804
1815
  result.completedEntity.metadata.uid = id;
1816
+ let oldRelationSources;
1805
1817
  await this.processingDatabase.transaction(async (tx) => {
1806
- await this.processingDatabase.updateProcessedEntity(tx, {
1818
+ const { previous } = await this.processingDatabase.updateProcessedEntity(tx, {
1807
1819
  id,
1808
1820
  processedEntity: result.completedEntity,
1809
1821
  resultHash,
@@ -1812,11 +1824,22 @@ class DefaultCatalogProcessingEngine {
1812
1824
  deferredEntities: result.deferredEntities,
1813
1825
  locationKey
1814
1826
  });
1827
+ oldRelationSources = new Set(previous.relations.map((r) => r.source_entity_ref));
1815
1828
  });
1829
+ const newRelationSources = new Set(result.relations.map((relation) => catalogModel.stringifyEntityRef(relation.source)));
1816
1830
  const setOfThingsToStitch = /* @__PURE__ */ new Set([
1817
- catalogModel.stringifyEntityRef(result.completedEntity),
1818
- ...result.relations.map((relation) => catalogModel.stringifyEntityRef(relation.source))
1831
+ catalogModel.stringifyEntityRef(result.completedEntity)
1819
1832
  ]);
1833
+ newRelationSources.forEach((r) => {
1834
+ if (!oldRelationSources.has(r)) {
1835
+ setOfThingsToStitch.add(r);
1836
+ }
1837
+ });
1838
+ oldRelationSources.forEach((r) => {
1839
+ if (!newRelationSources.has(r)) {
1840
+ setOfThingsToStitch.add(r);
1841
+ }
1842
+ });
1820
1843
  await this.stitcher.stitch(setOfThingsToStitch);
1821
1844
  track.markSuccessfulWithChanges(setOfThingsToStitch.size);
1822
1845
  } catch (error) {
@@ -2866,6 +2889,7 @@ async function createRouter(options) {
2866
2889
  entitiesCatalog,
2867
2890
  locationAnalyzer,
2868
2891
  locationService,
2892
+ orchestrator,
2869
2893
  refreshService,
2870
2894
  config,
2871
2895
  logger,
@@ -2988,6 +3012,46 @@ async function createRouter(options) {
2988
3012
  res.status(200).json(output);
2989
3013
  });
2990
3014
  }
3015
+ if (orchestrator) {
3016
+ router.post("/validate-entity", async (req, res) => {
3017
+ const bodySchema = zod.z.object({
3018
+ entity: zod.z.unknown(),
3019
+ location: zod.z.string()
3020
+ });
3021
+ let body;
3022
+ let entity;
3023
+ let location;
3024
+ try {
3025
+ body = await validateRequestBody(req, bodySchema);
3026
+ entity = validateEntityEnvelope(body.entity);
3027
+ location = catalogModel.parseLocationRef(body.location);
3028
+ if (location.type !== "url")
3029
+ throw new TypeError(`Invalid location ref ${body.location}, only 'url:<target>' is supported, e.g. url:https://host/path`);
3030
+ } catch (err) {
3031
+ return res.status(400).json({
3032
+ errors: [errors.serializeError(err)]
3033
+ });
3034
+ }
3035
+ const processingResult = await orchestrator.process({
3036
+ entity: {
3037
+ ...entity,
3038
+ metadata: {
3039
+ ...entity.metadata,
3040
+ annotations: {
3041
+ [catalogModel.ANNOTATION_LOCATION]: body.location,
3042
+ [catalogModel.ANNOTATION_ORIGIN_LOCATION]: body.location,
3043
+ ...entity.metadata.annotations
3044
+ }
3045
+ }
3046
+ }
3047
+ });
3048
+ if (!processingResult.ok)
3049
+ res.status(400).json({
3050
+ errors: processingResult.errors.map((e) => errors.serializeError(e))
3051
+ });
3052
+ return res.status(200).end();
3053
+ });
3054
+ }
2991
3055
  router.use(backendCommon.errorHandler());
2992
3056
  return router;
2993
3057
  }
@@ -3441,6 +3505,7 @@ class CatalogBuilder {
3441
3505
  entitiesCatalog,
3442
3506
  locationAnalyzer,
3443
3507
  locationService,
3508
+ orchestrator,
3444
3509
  refreshService,
3445
3510
  logger,
3446
3511
  config,