@backstage/plugin-catalog-backend 3.5.0-next.0 → 3.5.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/actions/createQueryCatalogEntitiesAction.cjs.js +164 -0
  3. package/dist/actions/createQueryCatalogEntitiesAction.cjs.js.map +1 -0
  4. package/dist/actions/index.cjs.js +2 -0
  5. package/dist/actions/index.cjs.js.map +1 -1
  6. package/dist/index.d.ts +8 -2
  7. package/dist/processors/AnnotateScmSlugEntityProcessor.cjs.js.map +1 -1
  8. package/dist/processors/CodeOwnersProcessor.cjs.js.map +1 -1
  9. package/dist/schema/openapi/generated/router.cjs.js +182 -36
  10. package/dist/schema/openapi/generated/router.cjs.js.map +1 -1
  11. package/dist/service/AuthorizedEntitiesCatalog.cjs.js +8 -3
  12. package/dist/service/AuthorizedEntitiesCatalog.cjs.js.map +1 -1
  13. package/dist/service/DefaultEntitiesCatalog.cjs.js +14 -22
  14. package/dist/service/DefaultEntitiesCatalog.cjs.js.map +1 -1
  15. package/dist/service/createRouter.cjs.js +67 -0
  16. package/dist/service/createRouter.cjs.js.map +1 -1
  17. package/dist/service/request/applyEntityFilterToQuery.cjs.js +16 -2
  18. package/dist/service/request/applyEntityFilterToQuery.cjs.js.map +1 -1
  19. package/dist/service/request/applyPredicateEntityFilterToQuery.cjs.js +201 -0
  20. package/dist/service/request/applyPredicateEntityFilterToQuery.cjs.js.map +1 -0
  21. package/dist/service/request/entitiesBatchRequest.cjs.js +14 -8
  22. package/dist/service/request/entitiesBatchRequest.cjs.js.map +1 -1
  23. package/dist/service/request/parseEntityFacetsQuery.cjs.js +29 -0
  24. package/dist/service/request/parseEntityFacetsQuery.cjs.js.map +1 -0
  25. package/dist/service/request/parseEntityQuery.cjs.js +68 -0
  26. package/dist/service/request/parseEntityQuery.cjs.js.map +1 -0
  27. package/dist/service/util.cjs.js +3 -1
  28. package/dist/service/util.cjs.js.map +1 -1
  29. package/package.json +8 -8
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @backstage/plugin-catalog-backend
2
2
 
3
+ ## 3.5.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - a6b2819: Added `query-catalog-entities` action to the catalog backend actions registry. Supports predicate-based filtering with `$all`, `$any`, `$not`, `$exists`, `$in`, `$contains`, and `$hasPrefix` operators.
8
+ - 972f686: Added support for predicate-based filtering on the `/entities/by-refs` endpoint via the `query` field in the request body. Supports `$all`, `$any`, `$not`, `$exists`, `$in`, `$contains`, and `$hasPrefix` operators.
9
+ - 56c908e: Added support for predicate-based filtering on the `/entity-facets` endpoint via a new `POST` method. Supports `$all`, `$any`, `$not`, `$exists`, `$in`, `$contains`, and `$hasPrefix` operators.
10
+ - 0fbcf23: Migrated OpenAPI schemas to 3.1.
11
+ - 51e23eb: Added predicate-based entity filtering via POST /entities/by-query endpoint.
12
+
13
+ Supports `$all`, `$any`, `$not`, `$exists`, `$in`, `$hasPrefix`, and (partially) `$contains` operators for expressive entity queries. Integrated into the existing `queryEntities` flow with full cursor-based pagination, permission enforcement, and `totalItems` support.
14
+
15
+ The catalog client's `queryEntities()` method automatically routes to the POST endpoint when a `query` predicate is provided.
16
+
17
+ ### Patch Changes
18
+
19
+ - 72747b4: Deprecated two processors as they have been moved to the Community Plugins repo with their own backend modules:
20
+
21
+ - `AnnotateScmSlugEntityProcessor`: Use `@backstage-community/plugin-catalog-backend-module-annotate-scm-slug` instead
22
+ - `CodeOwnersProcessor`: Use `@backstage-community/plugin-catalog-backend-module-codeowners` instead
23
+
24
+ - Updated dependencies
25
+ - @backstage/catalog-client@1.14.0-next.1
26
+ - @backstage/integration@2.0.0-next.1
27
+ - @backstage/plugin-catalog-node@2.1.0-next.1
28
+ - @backstage/backend-openapi-utils@0.6.7-next.0
29
+ - @backstage/backend-plugin-api@1.7.1-next.0
30
+ - @backstage/catalog-model@1.7.6
31
+ - @backstage/config@1.3.6
32
+ - @backstage/errors@1.2.7
33
+ - @backstage/filter-predicates@0.1.0
34
+ - @backstage/types@1.2.2
35
+ - @backstage/plugin-catalog-common@1.1.8
36
+ - @backstage/plugin-events-node@0.4.20-next.0
37
+ - @backstage/plugin-permission-common@0.9.6
38
+ - @backstage/plugin-permission-node@0.10.11-next.0
39
+
3
40
  ## 3.5.0-next.0
4
41
 
5
42
  ### Minor Changes
@@ -0,0 +1,164 @@
1
+ 'use strict';
2
+
3
+ var filterPredicates = require('@backstage/filter-predicates');
4
+
5
+ const createQueryCatalogEntitiesAction = ({
6
+ catalog,
7
+ actionsRegistry
8
+ }) => {
9
+ actionsRegistry.register({
10
+ name: "query-catalog-entities",
11
+ title: "Query Catalog Entities",
12
+ attributes: {
13
+ destructive: false,
14
+ readOnly: true,
15
+ idempotent: true
16
+ },
17
+ description: `
18
+ Query entities from the Backstage Software Catalog using predicate filters.
19
+
20
+ ## Catalog Model
21
+
22
+ The catalog contains entities of different kinds. Every entity has "kind", "apiVersion", "metadata", and optionally "spec" and "relations". Fields use dot notation for querying.
23
+
24
+ Common metadata fields on all entities: name, namespace (default: "default"), title, description, labels, annotations, tags (string array), links.
25
+
26
+ Entity references use the format "kind:namespace/name", e.g. "component:default/my-service" or "user:default/jane.doe".
27
+
28
+ ### Entity Kinds
29
+
30
+ **Component** - A piece of software such as a service, website, or library.
31
+ spec fields: type (e.g. "service", "website", "library"), lifecycle (e.g. "production", "experimental", "deprecated"), owner (entity ref), system, subcomponentOf, providesApis, consumesApis, dependsOn, dependencyOf.
32
+
33
+ **API** - An interface that components expose, such as REST APIs or event streams.
34
+ spec fields: type (e.g. "openapi", "asyncapi", "graphql", "grpc"), lifecycle, owner (entity ref), definition (the API spec content), system.
35
+
36
+ **System** - A collection of components, APIs, and resources that together expose some functionality.
37
+ spec fields: owner (entity ref), domain, type.
38
+
39
+ **Domain** - A grouping of systems that share terminology, domain models, and business purpose.
40
+ spec fields: owner (entity ref), subdomainOf, type.
41
+
42
+ **Resource** - Infrastructure required to operate a component, such as databases or storage buckets.
43
+ spec fields: type, owner (entity ref), system, dependsOn, dependencyOf.
44
+
45
+ **Group** - An organizational entity such as a team or business unit.
46
+ spec fields: type (e.g. "team", "business-unit"), children (entity refs), parent (entity ref), members (entity refs), profile (displayName, email, picture).
47
+
48
+ **User** - A person, such as an employee or contractor.
49
+ spec fields: memberOf (entity refs), profile (displayName, email, picture).
50
+
51
+ **Location** - A marker that references other catalog descriptor files to be ingested.
52
+ spec fields: type, target, targets, presence.
53
+
54
+ ### Relations
55
+
56
+ Entities have bidirectional relations stored in the "relations" array. Common relation types: ownedBy/ownerOf, dependsOn/dependencyOf, providesApi/apiProvidedBy, consumesApi/apiConsumedBy, parentOf/childOf, memberOf/hasMember, partOf/hasPart.
57
+
58
+ Relations can be queried via "relations.<type>" e.g. "relations.ownedby: user:default/jane-doe". The value there must always be a valid entity reference.
59
+
60
+ When querying for entity relationships, prefer using relations over spec fields. For example, use "relations.ownedby" instead of "spec.owner" to find entities owned by a particular group or user.
61
+
62
+ ## Query Syntax
63
+
64
+ The query uses predicate expressions with dot-notation field paths.
65
+
66
+ Simple matching:
67
+ { query: { kind: "Component" } }
68
+ { query: { kind: "Component", "spec.type": "service" } }
69
+
70
+ Value operators:
71
+ { query: { kind: { "$in": ["API", "Component"] } } }
72
+ { query: { "metadata.annotations.backstage.io/techdocs-ref": { "$exists": true } } }
73
+ { query: { "metadata.tags": { "$contains": "java" } } }
74
+ { query: { "metadata.name": { "$hasPrefix": "team-" } } }
75
+
76
+ Logical operators:
77
+ { query: { "$all": [{ kind: "Component" }, { "spec.lifecycle": "production" }] } }
78
+ { query: { "$any": [{ "spec.type": "service" }, { "spec.type": "website" }] } }
79
+ { query: { "$not": { kind: "Group" } } }
80
+
81
+ Querying relations - find all entities owned by a specific group:
82
+ { query: { "relations.ownedby": "group:default/team-alpha" } }
83
+
84
+ Combined example - find production services or websites with TechDocs:
85
+ { query: { "$all": [
86
+ { kind: "Component", "spec.lifecycle": "production" },
87
+ { "$any": [{ "spec.type": "service" }, { "spec.type": "website" }] },
88
+ { "metadata.annotations.backstage.io/techdocs-ref": { "$exists": true } }
89
+ ] } }
90
+
91
+ ## Other Options
92
+
93
+ Limit returned fields: { fields: ["kind", "metadata.name", "metadata.namespace"] }
94
+ Sort results: { orderFields: { field: "metadata.name", order: "asc" } }
95
+ Full text search: { fullTextFilter: { term: "auth", fields: ["metadata.name", "metadata.title"] } }
96
+ Pagination: Use limit (e.g. 20) and the returned nextPageCursor for subsequent requests via cursor.
97
+ `,
98
+ schema: {
99
+ input: (z) => z.object({
100
+ query: filterPredicates.createZodV3FilterPredicateSchema(z).optional().describe(
101
+ "Entity predicate query. Supports field matching, $all, $any, $not, $exists, $in, $contains, and $hasPrefix operators."
102
+ ),
103
+ fields: z.array(z.string()).optional().describe(
104
+ "Specific fields to include in the response. If not provided, all fields are returned. Each entry is a dot separated path into an entity, e.g. `spec.type`."
105
+ ),
106
+ limit: z.number().int().positive().optional().describe("Maximum number of entities to return at a time."),
107
+ offset: z.number().int().min(0).optional().describe("Number of entities to skip before returning results."),
108
+ orderFields: z.union([
109
+ z.object({
110
+ field: z.string().describe(
111
+ "Field to order by. The format is a dot separated path into an entity, e.g. `spec.type`."
112
+ ),
113
+ order: z.enum(["asc", "desc"]).describe("Sort order")
114
+ }),
115
+ z.array(
116
+ z.object({
117
+ field: z.string().describe(
118
+ "Field to order by. The format is a dot separated path into an entity, e.g. `spec.type`."
119
+ ),
120
+ order: z.enum(["asc", "desc"]).describe("Sort order")
121
+ })
122
+ )
123
+ ]).optional().describe(
124
+ "Ordering criteria for the results. Can be a single order directive or an array for multi-field sorting."
125
+ ),
126
+ fullTextFilter: z.object({
127
+ term: z.string().describe("Full text search term"),
128
+ fields: z.array(z.string()).optional().describe(
129
+ "Fields to search within. Each entry is a dot separated path into an entity, e.g. `spec.type`."
130
+ )
131
+ }).optional().describe("Full text search criteria"),
132
+ cursor: z.string().optional().describe(
133
+ "Cursor for pagination. This can be used only after the first request with a response containing a cursor. If a cursor is given it takes precedence over `offset`."
134
+ )
135
+ }),
136
+ output: (z) => z.object({
137
+ items: z.array(z.object({}).passthrough()).describe("List of entities"),
138
+ totalItems: z.number().describe("Total number of entities"),
139
+ hasMoreEntities: z.boolean().describe("Whether more entities are available"),
140
+ nextPageCursor: z.string().optional().describe("Next page cursor used to fetch next page of entities")
141
+ })
142
+ },
143
+ action: async ({ input, credentials }) => {
144
+ const response = await catalog.queryEntities(
145
+ {
146
+ ...input,
147
+ query: input.query
148
+ },
149
+ { credentials }
150
+ );
151
+ return {
152
+ output: {
153
+ items: response.items,
154
+ totalItems: response.totalItems,
155
+ hasMoreEntities: !!response.pageInfo.nextCursor,
156
+ nextPageCursor: response.pageInfo.nextCursor
157
+ }
158
+ };
159
+ }
160
+ });
161
+ };
162
+
163
+ exports.createQueryCatalogEntitiesAction = createQueryCatalogEntitiesAction;
164
+ //# sourceMappingURL=createQueryCatalogEntitiesAction.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createQueryCatalogEntitiesAction.cjs.js","sources":["../../src/actions/createQueryCatalogEntitiesAction.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\nimport { createZodV3FilterPredicateSchema } from '@backstage/filter-predicates';\n\nexport const createQueryCatalogEntitiesAction = ({\n catalog,\n actionsRegistry,\n}: {\n catalog: CatalogService;\n actionsRegistry: ActionsRegistryService;\n}) => {\n actionsRegistry.register({\n name: 'query-catalog-entities',\n title: 'Query Catalog Entities',\n attributes: {\n destructive: false,\n readOnly: true,\n idempotent: true,\n },\n description: `\nQuery entities from the Backstage Software Catalog using predicate filters.\n\n## Catalog Model\n\nThe catalog contains entities of different kinds. Every entity has \"kind\", \"apiVersion\", \"metadata\", and optionally \"spec\" and \"relations\". Fields use dot notation for querying.\n\nCommon metadata fields on all entities: name, namespace (default: \"default\"), title, description, labels, annotations, tags (string array), links.\n\nEntity references use the format \"kind:namespace/name\", e.g. \"component:default/my-service\" or \"user:default/jane.doe\".\n\n### Entity Kinds\n\n**Component** - A piece of software such as a service, website, or library.\n spec fields: type (e.g. \"service\", \"website\", \"library\"), lifecycle (e.g. \"production\", \"experimental\", \"deprecated\"), owner (entity ref), system, subcomponentOf, providesApis, consumesApis, dependsOn, dependencyOf.\n\n**API** - An interface that components expose, such as REST APIs or event streams.\n spec fields: type (e.g. \"openapi\", \"asyncapi\", \"graphql\", \"grpc\"), lifecycle, owner (entity ref), definition (the API spec content), system.\n\n**System** - A collection of components, APIs, and resources that together expose some functionality.\n spec fields: owner (entity ref), domain, type.\n\n**Domain** - A grouping of systems that share terminology, domain models, and business purpose.\n spec fields: owner (entity ref), subdomainOf, type.\n\n**Resource** - Infrastructure required to operate a component, such as databases or storage buckets.\n spec fields: type, owner (entity ref), system, dependsOn, dependencyOf.\n\n**Group** - An organizational entity such as a team or business unit.\n spec fields: type (e.g. \"team\", \"business-unit\"), children (entity refs), parent (entity ref), members (entity refs), profile (displayName, email, picture).\n\n**User** - A person, such as an employee or contractor.\n spec fields: memberOf (entity refs), profile (displayName, email, picture).\n\n**Location** - A marker that references other catalog descriptor files to be ingested.\n spec fields: type, target, targets, presence.\n\n### Relations\n\nEntities have bidirectional relations stored in the \"relations\" array. Common relation types: ownedBy/ownerOf, dependsOn/dependencyOf, providesApi/apiProvidedBy, consumesApi/apiConsumedBy, parentOf/childOf, memberOf/hasMember, partOf/hasPart.\n\nRelations can be queried via \"relations.<type>\" e.g. \"relations.ownedby: user:default/jane-doe\". The value there must always be a valid entity reference.\n\nWhen querying for entity relationships, prefer using relations over spec fields. For example, use \"relations.ownedby\" instead of \"spec.owner\" to find entities owned by a particular group or user.\n\n## Query Syntax\n\nThe query uses predicate expressions with dot-notation field paths.\n\nSimple matching:\n { query: { kind: \"Component\" } }\n { query: { kind: \"Component\", \"spec.type\": \"service\" } }\n\nValue operators:\n { query: { kind: { \"$in\": [\"API\", \"Component\"] } } }\n { query: { \"metadata.annotations.backstage.io/techdocs-ref\": { \"$exists\": true } } }\n { query: { \"metadata.tags\": { \"$contains\": \"java\" } } }\n { query: { \"metadata.name\": { \"$hasPrefix\": \"team-\" } } }\n\nLogical operators:\n { query: { \"$all\": [{ kind: \"Component\" }, { \"spec.lifecycle\": \"production\" }] } }\n { query: { \"$any\": [{ \"spec.type\": \"service\" }, { \"spec.type\": \"website\" }] } }\n { query: { \"$not\": { kind: \"Group\" } } }\n\nQuerying relations - find all entities owned by a specific group:\n { query: { \"relations.ownedby\": \"group:default/team-alpha\" } }\n\nCombined example - find production services or websites with TechDocs:\n { query: { \"$all\": [\n { kind: \"Component\", \"spec.lifecycle\": \"production\" },\n { \"$any\": [{ \"spec.type\": \"service\" }, { \"spec.type\": \"website\" }] },\n { \"metadata.annotations.backstage.io/techdocs-ref\": { \"$exists\": true } }\n ] } }\n\n## Other Options\n\nLimit returned fields: { fields: [\"kind\", \"metadata.name\", \"metadata.namespace\"] }\nSort results: { orderFields: { field: \"metadata.name\", order: \"asc\" } }\nFull text search: { fullTextFilter: { term: \"auth\", fields: [\"metadata.name\", \"metadata.title\"] } }\nPagination: Use limit (e.g. 20) and the returned nextPageCursor for subsequent requests via cursor.\n `,\n schema: {\n input: z =>\n z.object({\n query: createZodV3FilterPredicateSchema(z)\n .optional()\n .describe(\n 'Entity predicate query. Supports field matching, $all, $any, $not, $exists, $in, $contains, and $hasPrefix operators.',\n ),\n fields: z\n .array(z.string())\n .optional()\n .describe(\n 'Specific fields to include in the response. If not provided, all fields are returned. Each entry is a dot separated path into an entity, e.g. `spec.type`.',\n ),\n limit: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Maximum number of entities to return at a time.'),\n offset: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe('Number of entities to skip before returning results.'),\n orderFields: z\n .union([\n z.object({\n field: z\n .string()\n .describe(\n 'Field to order by. The format is a dot separated path into an entity, e.g. `spec.type`.',\n ),\n order: z.enum(['asc', 'desc']).describe('Sort order'),\n }),\n z.array(\n z.object({\n field: z\n .string()\n .describe(\n 'Field to order by. The format is a dot separated path into an entity, e.g. `spec.type`.',\n ),\n order: z.enum(['asc', 'desc']).describe('Sort order'),\n }),\n ),\n ])\n .optional()\n .describe(\n 'Ordering criteria for the results. Can be a single order directive or an array for multi-field sorting.',\n ),\n fullTextFilter: z\n .object({\n term: z.string().describe('Full text search term'),\n fields: z\n .array(z.string())\n .optional()\n .describe(\n 'Fields to search within. Each entry is a dot separated path into an entity, e.g. `spec.type`.',\n ),\n })\n .optional()\n .describe('Full text search criteria'),\n cursor: z\n .string()\n .optional()\n .describe(\n 'Cursor for pagination. This can be used only after the first request with a response containing a cursor. If a cursor is given it takes precedence over `offset`.',\n ),\n }),\n output: z =>\n z.object({\n items: z\n .array(z.object({}).passthrough())\n .describe('List of entities'),\n totalItems: z.number().describe('Total number of entities'),\n hasMoreEntities: z\n .boolean()\n .describe('Whether more entities are available'),\n nextPageCursor: z\n .string()\n .optional()\n .describe('Next page cursor used to fetch next page of entities'),\n }),\n },\n action: async ({ input, credentials }) => {\n const response = await catalog.queryEntities(\n {\n ...input,\n query: input.query,\n },\n { credentials },\n );\n\n return {\n output: {\n items: response.items,\n totalItems: response.totalItems,\n hasMoreEntities: !!response.pageInfo.nextCursor,\n nextPageCursor: response.pageInfo.nextCursor,\n },\n };\n },\n });\n};\n"],"names":["createZodV3FilterPredicateSchema"],"mappings":"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"}
@@ -4,12 +4,14 @@ var createGetCatalogEntityAction = require('./createGetCatalogEntityAction.cjs.j
4
4
  var createValidateEntityAction = require('./createValidateEntityAction.cjs.js');
5
5
  var createRegisterCatalogEntitiesAction = require('./createRegisterCatalogEntitiesAction.cjs.js');
6
6
  var createUnregisterCatalogEntitiesAction = require('./createUnregisterCatalogEntitiesAction.cjs.js');
7
+ var createQueryCatalogEntitiesAction = require('./createQueryCatalogEntitiesAction.cjs.js');
7
8
 
8
9
  const createCatalogActions = (options) => {
9
10
  createGetCatalogEntityAction.createGetCatalogEntityAction(options);
10
11
  createValidateEntityAction.createValidateEntityAction(options);
11
12
  createRegisterCatalogEntitiesAction.createRegisterCatalogEntitiesAction(options);
12
13
  createUnregisterCatalogEntitiesAction.createUnregisterCatalogEntitiesAction(options);
14
+ createQueryCatalogEntitiesAction.createQueryCatalogEntitiesAction(options);
13
15
  };
14
16
 
15
17
  exports.createCatalogActions = createCatalogActions;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../../src/actions/index.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\nimport { createGetCatalogEntityAction } from './createGetCatalogEntityAction.ts';\nimport { createValidateEntityAction } from './createValidateEntityAction.ts';\nimport { createRegisterCatalogEntitiesAction } from './createRegisterCatalogEntitiesAction.ts';\nimport { createUnregisterCatalogEntitiesAction } from './createUnregisterCatalogEntitiesAction.ts';\n\nexport const createCatalogActions = (options: {\n actionsRegistry: ActionsRegistryService;\n catalog: CatalogService;\n}) => {\n createGetCatalogEntityAction(options);\n createValidateEntityAction(options);\n createRegisterCatalogEntitiesAction(options);\n createUnregisterCatalogEntitiesAction(options);\n};\n"],"names":["createGetCatalogEntityAction","createValidateEntityAction","createRegisterCatalogEntitiesAction","createUnregisterCatalogEntitiesAction"],"mappings":";;;;;;;AAsBO,MAAM,oBAAA,GAAuB,CAAC,OAAA,KAG/B;AACJ,EAAAA,yDAAA,CAA6B,OAAO,CAAA;AACpC,EAAAC,qDAAA,CAA2B,OAAO,CAAA;AAClC,EAAAC,uEAAA,CAAoC,OAAO,CAAA;AAC3C,EAAAC,2EAAA,CAAsC,OAAO,CAAA;AAC/C;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../../src/actions/index.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\nimport { createGetCatalogEntityAction } from './createGetCatalogEntityAction.ts';\nimport { createValidateEntityAction } from './createValidateEntityAction.ts';\nimport { createRegisterCatalogEntitiesAction } from './createRegisterCatalogEntitiesAction.ts';\nimport { createUnregisterCatalogEntitiesAction } from './createUnregisterCatalogEntitiesAction.ts';\nimport { createQueryCatalogEntitiesAction } from './createQueryCatalogEntitiesAction.ts';\n\nexport const createCatalogActions = (options: {\n actionsRegistry: ActionsRegistryService;\n catalog: CatalogService;\n}) => {\n createGetCatalogEntityAction(options);\n createValidateEntityAction(options);\n createRegisterCatalogEntitiesAction(options);\n createUnregisterCatalogEntitiesAction(options);\n createQueryCatalogEntitiesAction(options);\n};\n"],"names":["createGetCatalogEntityAction","createValidateEntityAction","createRegisterCatalogEntitiesAction","createUnregisterCatalogEntitiesAction","createQueryCatalogEntitiesAction"],"mappings":";;;;;;;;AAuBO,MAAM,oBAAA,GAAuB,CAAC,OAAA,KAG/B;AACJ,EAAAA,yDAAA,CAA6B,OAAO,CAAA;AACpC,EAAAC,qDAAA,CAA2B,OAAO,CAAA;AAClC,EAAAC,uEAAA,CAAoC,OAAO,CAAA;AAC3C,EAAAC,2EAAA,CAAsC,OAAO,CAAA;AAC7C,EAAAC,iEAAA,CAAiC,OAAO,CAAA;AAC1C;;;;"}
package/dist/index.d.ts CHANGED
@@ -22,7 +22,10 @@ declare class AnnotateLocationEntityProcessor implements CatalogProcessor {
22
22
  preProcessEntity(entity: Entity, location: LocationSpec, _: CatalogProcessorEmit, originLocation: LocationSpec): Promise<Entity>;
23
23
  }
24
24
 
25
- /** @public */
25
+ /**
26
+ * @public
27
+ * @deprecated Use `@backstage-community/plugin-catalog-backend-module-annotate-scm-slug` instead, this will be removed in a future release
28
+ */
26
29
  declare class AnnotateScmSlugEntityProcessor implements CatalogProcessor {
27
30
  private readonly opts;
28
31
  constructor(opts: {
@@ -45,7 +48,10 @@ declare class BuiltinKindsEntityProcessor implements CatalogProcessor {
45
48
  postProcessEntity(entity: Entity, _location: LocationSpec, emit: CatalogProcessorEmit): Promise<Entity>;
46
49
  }
47
50
 
48
- /** @public */
51
+ /**
52
+ * @public
53
+ * @deprecated Use `@backstage-community/plugin-catalog-backend-module-codeowners` instead, this will be removed in a future release
54
+ */
49
55
  declare class CodeOwnersProcessor implements CatalogProcessor {
50
56
  private readonly integrations;
51
57
  private readonly logger;
@@ -1 +1 @@
1
- {"version":3,"file":"AnnotateScmSlugEntityProcessor.cjs.js","sources":["../../src/processors/AnnotateScmSlugEntityProcessor.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 { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport parseGitUrl from 'git-url-parse';\nimport { identity, merge, pickBy } from 'lodash';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\n\nconst GITHUB_ACTIONS_ANNOTATION = 'github.com/project-slug';\nconst GITLAB_ACTIONS_ANNOTATION = 'gitlab.com/project-slug';\nconst AZURE_ACTIONS_ANNOTATION = 'dev.azure.com/project-repo';\n\n/** @public */\nexport class AnnotateScmSlugEntityProcessor implements CatalogProcessor {\n private readonly opts: {\n scmIntegrationRegistry: ScmIntegrationRegistry;\n kinds?: string[];\n };\n\n constructor(opts: {\n scmIntegrationRegistry: ScmIntegrationRegistry;\n kinds?: string[];\n }) {\n this.opts = opts;\n }\n\n getProcessorName(): string {\n return 'AnnotateScmSlugEntityProcessor';\n }\n\n static fromConfig(\n config: Config,\n options?: { kinds?: string[] },\n ): AnnotateScmSlugEntityProcessor {\n return new AnnotateScmSlugEntityProcessor({\n scmIntegrationRegistry: ScmIntegrations.fromConfig(config),\n kinds: options?.kinds,\n });\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise<Entity> {\n const applicableKinds = (this.opts.kinds ?? ['Component']).map(k =>\n k.toLocaleLowerCase('en-US'),\n );\n if (\n !applicableKinds.includes(entity.kind.toLocaleLowerCase('en-US')) ||\n location.type !== 'url'\n ) {\n return entity;\n }\n\n const scmIntegration = this.opts.scmIntegrationRegistry.byUrl(\n location.target,\n );\n\n if (!scmIntegration) {\n return entity;\n }\n\n let annotation;\n switch (scmIntegration.type) {\n case 'github':\n annotation = GITHUB_ACTIONS_ANNOTATION;\n break;\n case 'gitlab':\n annotation = GITLAB_ACTIONS_ANNOTATION;\n break;\n case 'azure':\n annotation = AZURE_ACTIONS_ANNOTATION;\n break;\n default:\n return entity;\n }\n\n let projectSlug = entity.metadata.annotations?.[annotation];\n if (!projectSlug) {\n const gitUrl = parseGitUrl(location.target);\n projectSlug = `${gitUrl.owner}/${gitUrl.name}`;\n }\n\n return merge(\n {\n metadata: {\n annotations: pickBy(\n {\n [annotation]: projectSlug,\n },\n identity,\n ),\n },\n },\n entity,\n );\n }\n}\n"],"names":["ScmIntegrations","parseGitUrl","merge","pickBy","identity"],"mappings":";;;;;;;;;;AA2BA,MAAM,yBAAA,GAA4B,yBAAA;AAClC,MAAM,yBAAA,GAA4B,yBAAA;AAClC,MAAM,wBAAA,GAA2B,4BAAA;AAG1B,MAAM,8BAAA,CAA2D;AAAA,EACrD,IAAA;AAAA,EAKjB,YAAY,IAAA,EAGT;AACD,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,gBAAA,GAA2B;AACzB,IAAA,OAAO,gCAAA;AAAA,EACT;AAAA,EAEA,OAAO,UAAA,CACL,MAAA,EACA,OAAA,EACgC;AAChC,IAAA,OAAO,IAAI,8BAAA,CAA+B;AAAA,MACxC,sBAAA,EAAwBA,2BAAA,CAAgB,UAAA,CAAW,MAAM,CAAA;AAAA,MACzD,OAAO,OAAA,EAAS;AAAA,KACjB,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,gBAAA,CACJ,MAAA,EACA,QAAA,EACiB;AACjB,IAAA,MAAM,mBAAmB,IAAA,CAAK,IAAA,CAAK,KAAA,IAAS,CAAC,WAAW,CAAA,EAAG,GAAA;AAAA,MAAI,CAAA,CAAA,KAC7D,CAAA,CAAE,iBAAA,CAAkB,OAAO;AAAA,KAC7B;AACA,IAAA,IACE,CAAC,eAAA,CAAgB,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,OAAO,CAAC,CAAA,IAChE,QAAA,CAAS,IAAA,KAAS,KAAA,EAClB;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,IAAA,CAAK,sBAAA,CAAuB,KAAA;AAAA,MACtD,QAAA,CAAS;AAAA,KACX;AAEA,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,UAAA;AACJ,IAAA,QAAQ,eAAe,IAAA;AAAM,MAC3B,KAAK,QAAA;AACH,QAAA,UAAA,GAAa,yBAAA;AACb,QAAA;AAAA,MACF,KAAK,QAAA;AACH,QAAA,UAAA,GAAa,yBAAA;AACb,QAAA;AAAA,MACF,KAAK,OAAA;AACH,QAAA,UAAA,GAAa,wBAAA;AACb,QAAA;AAAA,MACF;AACE,QAAA,OAAO,MAAA;AAAA;AAGX,IAAA,IAAI,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,WAAA,GAAc,UAAU,CAAA;AAC1D,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,MAAM,MAAA,GAASC,4BAAA,CAAY,QAAA,CAAS,MAAM,CAAA;AAC1C,MAAA,WAAA,GAAc,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA,CAAA,EAAI,OAAO,IAAI,CAAA,CAAA;AAAA,IAC9C;AAEA,IAAA,OAAOC,YAAA;AAAA,MACL;AAAA,QACE,QAAA,EAAU;AAAA,UACR,WAAA,EAAaC,aAAA;AAAA,YACX;AAAA,cACE,CAAC,UAAU,GAAG;AAAA,aAChB;AAAA,YACAC;AAAA;AACF;AACF,OACF;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACF;;;;"}
1
+ {"version":3,"file":"AnnotateScmSlugEntityProcessor.cjs.js","sources":["../../src/processors/AnnotateScmSlugEntityProcessor.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 { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport parseGitUrl from 'git-url-parse';\nimport { identity, merge, pickBy } from 'lodash';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\n\nconst GITHUB_ACTIONS_ANNOTATION = 'github.com/project-slug';\nconst GITLAB_ACTIONS_ANNOTATION = 'gitlab.com/project-slug';\nconst AZURE_ACTIONS_ANNOTATION = 'dev.azure.com/project-repo';\n\n/**\n * @public\n * @deprecated Use `@backstage-community/plugin-catalog-backend-module-annotate-scm-slug` instead, this will be removed in a future release\n */\nexport class AnnotateScmSlugEntityProcessor implements CatalogProcessor {\n private readonly opts: {\n scmIntegrationRegistry: ScmIntegrationRegistry;\n kinds?: string[];\n };\n\n constructor(opts: {\n scmIntegrationRegistry: ScmIntegrationRegistry;\n kinds?: string[];\n }) {\n this.opts = opts;\n }\n\n getProcessorName(): string {\n return 'AnnotateScmSlugEntityProcessor';\n }\n\n static fromConfig(\n config: Config,\n options?: { kinds?: string[] },\n ): AnnotateScmSlugEntityProcessor {\n return new AnnotateScmSlugEntityProcessor({\n scmIntegrationRegistry: ScmIntegrations.fromConfig(config),\n kinds: options?.kinds,\n });\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise<Entity> {\n const applicableKinds = (this.opts.kinds ?? ['Component']).map(k =>\n k.toLocaleLowerCase('en-US'),\n );\n if (\n !applicableKinds.includes(entity.kind.toLocaleLowerCase('en-US')) ||\n location.type !== 'url'\n ) {\n return entity;\n }\n\n const scmIntegration = this.opts.scmIntegrationRegistry.byUrl(\n location.target,\n );\n\n if (!scmIntegration) {\n return entity;\n }\n\n let annotation;\n switch (scmIntegration.type) {\n case 'github':\n annotation = GITHUB_ACTIONS_ANNOTATION;\n break;\n case 'gitlab':\n annotation = GITLAB_ACTIONS_ANNOTATION;\n break;\n case 'azure':\n annotation = AZURE_ACTIONS_ANNOTATION;\n break;\n default:\n return entity;\n }\n\n let projectSlug = entity.metadata.annotations?.[annotation];\n if (!projectSlug) {\n const gitUrl = parseGitUrl(location.target);\n projectSlug = `${gitUrl.owner}/${gitUrl.name}`;\n }\n\n return merge(\n {\n metadata: {\n annotations: pickBy(\n {\n [annotation]: projectSlug,\n },\n identity,\n ),\n },\n },\n entity,\n );\n }\n}\n"],"names":["ScmIntegrations","parseGitUrl","merge","pickBy","identity"],"mappings":";;;;;;;;;;AA2BA,MAAM,yBAAA,GAA4B,yBAAA;AAClC,MAAM,yBAAA,GAA4B,yBAAA;AAClC,MAAM,wBAAA,GAA2B,4BAAA;AAM1B,MAAM,8BAAA,CAA2D;AAAA,EACrD,IAAA;AAAA,EAKjB,YAAY,IAAA,EAGT;AACD,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,gBAAA,GAA2B;AACzB,IAAA,OAAO,gCAAA;AAAA,EACT;AAAA,EAEA,OAAO,UAAA,CACL,MAAA,EACA,OAAA,EACgC;AAChC,IAAA,OAAO,IAAI,8BAAA,CAA+B;AAAA,MACxC,sBAAA,EAAwBA,2BAAA,CAAgB,UAAA,CAAW,MAAM,CAAA;AAAA,MACzD,OAAO,OAAA,EAAS;AAAA,KACjB,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,gBAAA,CACJ,MAAA,EACA,QAAA,EACiB;AACjB,IAAA,MAAM,mBAAmB,IAAA,CAAK,IAAA,CAAK,KAAA,IAAS,CAAC,WAAW,CAAA,EAAG,GAAA;AAAA,MAAI,CAAA,CAAA,KAC7D,CAAA,CAAE,iBAAA,CAAkB,OAAO;AAAA,KAC7B;AACA,IAAA,IACE,CAAC,eAAA,CAAgB,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,OAAO,CAAC,CAAA,IAChE,QAAA,CAAS,IAAA,KAAS,KAAA,EAClB;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,IAAA,CAAK,sBAAA,CAAuB,KAAA;AAAA,MACtD,QAAA,CAAS;AAAA,KACX;AAEA,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,UAAA;AACJ,IAAA,QAAQ,eAAe,IAAA;AAAM,MAC3B,KAAK,QAAA;AACH,QAAA,UAAA,GAAa,yBAAA;AACb,QAAA;AAAA,MACF,KAAK,QAAA;AACH,QAAA,UAAA,GAAa,yBAAA;AACb,QAAA;AAAA,MACF,KAAK,OAAA;AACH,QAAA,UAAA,GAAa,wBAAA;AACb,QAAA;AAAA,MACF;AACE,QAAA,OAAO,MAAA;AAAA;AAGX,IAAA,IAAI,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,WAAA,GAAc,UAAU,CAAA;AAC1D,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,MAAM,MAAA,GAASC,4BAAA,CAAY,QAAA,CAAS,MAAM,CAAA;AAC1C,MAAA,WAAA,GAAc,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA,CAAA,EAAI,OAAO,IAAI,CAAA,CAAA;AAAA,IAC9C;AAEA,IAAA,OAAOC,YAAA;AAAA,MACL;AAAA,QACE,QAAA,EAAU;AAAA,UACR,WAAA,EAAaC,aAAA;AAAA,YACX;AAAA,cACE,CAAC,UAAU,GAAG;AAAA,aAChB;AAAA,YACAC;AAAA;AACF;AACF,OACF;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"CodeOwnersProcessor.cjs.js","sources":["../../src/processors/CodeOwnersProcessor.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 { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\nimport { findCodeOwnerByTarget } from './codeowners';\nimport { LoggerService, UrlReaderService } from '@backstage/backend-plugin-api';\n\nconst ALLOWED_KINDS = ['API', 'Component', 'Domain', 'Resource', 'System'];\nconst ALLOWED_LOCATION_TYPES = ['url'];\n\n/** @public */\nexport class CodeOwnersProcessor implements CatalogProcessor {\n private readonly integrations: ScmIntegrationRegistry;\n private readonly logger: LoggerService;\n private readonly reader: UrlReaderService;\n\n static fromConfig(\n config: Config,\n options: { logger: LoggerService; reader: UrlReaderService },\n ) {\n const integrations = ScmIntegrations.fromConfig(config);\n\n return new CodeOwnersProcessor({\n ...options,\n integrations,\n });\n }\n\n constructor(options: {\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n reader: UrlReaderService;\n }) {\n this.integrations = options.integrations;\n this.logger = options.logger;\n this.reader = options.reader;\n }\n\n getProcessorName(): string {\n return 'CodeOwnersProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise<Entity> {\n // Only continue if the owner is not set\n if (\n !entity ||\n !ALLOWED_KINDS.includes(entity.kind) ||\n !ALLOWED_LOCATION_TYPES.includes(location.type) ||\n (entity.spec && entity.spec.owner)\n ) {\n return entity;\n }\n\n const scmIntegration = this.integrations.byUrl(location.target);\n if (!scmIntegration) {\n return entity;\n }\n\n const owner = await findCodeOwnerByTarget(\n this.reader,\n location.target,\n scmIntegration,\n );\n\n if (!owner) {\n this.logger.debug(\n `CodeOwnerProcessor could not resolve owner for ${location.target}`,\n );\n return entity;\n }\n\n return {\n ...entity,\n spec: { ...entity.spec, owner },\n };\n }\n}\n"],"names":["ScmIntegrations","findCodeOwnerByTarget"],"mappings":";;;;;;;AA2BA,MAAM,gBAAgB,CAAC,KAAA,EAAO,WAAA,EAAa,QAAA,EAAU,YAAY,QAAQ,CAAA;AACzE,MAAM,sBAAA,GAAyB,CAAC,KAAK,CAAA;AAG9B,MAAM,mBAAA,CAAgD;AAAA,EAC1C,YAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EAEjB,OAAO,UAAA,CACL,MAAA,EACA,OAAA,EACA;AACA,IAAA,MAAM,YAAA,GAAeA,2BAAA,CAAgB,UAAA,CAAW,MAAM,CAAA;AAEtD,IAAA,OAAO,IAAI,mBAAA,CAAoB;AAAA,MAC7B,GAAG,OAAA;AAAA,MACH;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,YAAY,OAAA,EAIT;AACD,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA;AAC5B,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AAAA,EACxB;AAAA,EAEA,gBAAA,GAA2B;AACzB,IAAA,OAAO,qBAAA;AAAA,EACT;AAAA,EAEA,MAAM,gBAAA,CACJ,MAAA,EACA,QAAA,EACiB;AAEjB,IAAA,IACE,CAAC,MAAA,IACD,CAAC,cAAc,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA,IACnC,CAAC,sBAAA,CAAuB,QAAA,CAAS,SAAS,IAAI,CAAA,IAC7C,OAAO,IAAA,IAAQ,MAAA,CAAO,KAAK,KAAA,EAC5B;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM,SAAS,MAAM,CAAA;AAC9D,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,QAAQ,MAAMC,0BAAA;AAAA,MAClB,IAAA,CAAK,MAAA;AAAA,MACL,QAAA,CAAS,MAAA;AAAA,MACT;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA;AAAA,QACV,CAAA,+CAAA,EAAkD,SAAS,MAAM,CAAA;AAAA,OACnE;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAO;AAAA,MACL,GAAG,MAAA;AAAA,MACH,IAAA,EAAM,EAAE,GAAG,MAAA,CAAO,MAAM,KAAA;AAAM,KAChC;AAAA,EACF;AACF;;;;"}
1
+ {"version":3,"file":"CodeOwnersProcessor.cjs.js","sources":["../../src/processors/CodeOwnersProcessor.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 { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { CatalogProcessor } from '@backstage/plugin-catalog-node';\nimport { findCodeOwnerByTarget } from './codeowners';\nimport { LoggerService, UrlReaderService } from '@backstage/backend-plugin-api';\n\nconst ALLOWED_KINDS = ['API', 'Component', 'Domain', 'Resource', 'System'];\nconst ALLOWED_LOCATION_TYPES = ['url'];\n\n/**\n * @public\n * @deprecated Use `@backstage-community/plugin-catalog-backend-module-codeowners` instead, this will be removed in a future release\n */\nexport class CodeOwnersProcessor implements CatalogProcessor {\n private readonly integrations: ScmIntegrationRegistry;\n private readonly logger: LoggerService;\n private readonly reader: UrlReaderService;\n\n static fromConfig(\n config: Config,\n options: { logger: LoggerService; reader: UrlReaderService },\n ) {\n const integrations = ScmIntegrations.fromConfig(config);\n\n return new CodeOwnersProcessor({\n ...options,\n integrations,\n });\n }\n\n constructor(options: {\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n reader: UrlReaderService;\n }) {\n this.integrations = options.integrations;\n this.logger = options.logger;\n this.reader = options.reader;\n }\n\n getProcessorName(): string {\n return 'CodeOwnersProcessor';\n }\n\n async preProcessEntity(\n entity: Entity,\n location: LocationSpec,\n ): Promise<Entity> {\n // Only continue if the owner is not set\n if (\n !entity ||\n !ALLOWED_KINDS.includes(entity.kind) ||\n !ALLOWED_LOCATION_TYPES.includes(location.type) ||\n (entity.spec && entity.spec.owner)\n ) {\n return entity;\n }\n\n const scmIntegration = this.integrations.byUrl(location.target);\n if (!scmIntegration) {\n return entity;\n }\n\n const owner = await findCodeOwnerByTarget(\n this.reader,\n location.target,\n scmIntegration,\n );\n\n if (!owner) {\n this.logger.debug(\n `CodeOwnerProcessor could not resolve owner for ${location.target}`,\n );\n return entity;\n }\n\n return {\n ...entity,\n spec: { ...entity.spec, owner },\n };\n }\n}\n"],"names":["ScmIntegrations","findCodeOwnerByTarget"],"mappings":";;;;;;;AA2BA,MAAM,gBAAgB,CAAC,KAAA,EAAO,WAAA,EAAa,QAAA,EAAU,YAAY,QAAQ,CAAA;AACzE,MAAM,sBAAA,GAAyB,CAAC,KAAK,CAAA;AAM9B,MAAM,mBAAA,CAAgD;AAAA,EAC1C,YAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EAEjB,OAAO,UAAA,CACL,MAAA,EACA,OAAA,EACA;AACA,IAAA,MAAM,YAAA,GAAeA,2BAAA,CAAgB,UAAA,CAAW,MAAM,CAAA;AAEtD,IAAA,OAAO,IAAI,mBAAA,CAAoB;AAAA,MAC7B,GAAG,OAAA;AAAA,MACH;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,YAAY,OAAA,EAIT;AACD,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA;AAC5B,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AAAA,EACxB;AAAA,EAEA,gBAAA,GAA2B;AACzB,IAAA,OAAO,qBAAA;AAAA,EACT;AAAA,EAEA,MAAM,gBAAA,CACJ,MAAA,EACA,QAAA,EACiB;AAEjB,IAAA,IACE,CAAC,MAAA,IACD,CAAC,cAAc,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA,IACnC,CAAC,sBAAA,CAAuB,QAAA,CAAS,SAAS,IAAI,CAAA,IAC7C,OAAO,IAAA,IAAQ,MAAA,CAAO,KAAK,KAAA,EAC5B;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM,SAAS,MAAM,CAAA;AAC9D,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,MAAM,QAAQ,MAAMC,0BAAA;AAAA,MAClB,IAAA,CAAK,MAAA;AAAA,MACL,QAAA,CAAS,MAAA;AAAA,MACT;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA;AAAA,QACV,CAAA,+CAAA,EAAkD,SAAS,MAAM,CAAA;AAAA,OACnE;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAO;AAAA,MACL,GAAG,MAAA;AAAA,MACH,IAAA,EAAM,EAAE,GAAG,MAAA,CAAO,MAAM,KAAA;AAAM,KAChC;AAAA,EACF;AACF;;;;"}
@@ -3,7 +3,7 @@
3
3
  var backendOpenapiUtils = require('@backstage/backend-openapi-utils');
4
4
 
5
5
  const spec = {
6
- openapi: "3.0.3",
6
+ openapi: "3.1.0",
7
7
  info: {
8
8
  title: "catalog",
9
9
  version: "1",
@@ -27,7 +27,6 @@ const spec = {
27
27
  name: "kind",
28
28
  in: "path",
29
29
  required: true,
30
- allowReserved: true,
31
30
  schema: {
32
31
  type: "string"
33
32
  }
@@ -36,7 +35,6 @@ const spec = {
36
35
  name: "namespace",
37
36
  in: "path",
38
37
  required: true,
39
- allowReserved: true,
40
38
  schema: {
41
39
  type: "string"
42
40
  }
@@ -45,7 +43,6 @@ const spec = {
45
43
  name: "name",
46
44
  in: "path",
47
45
  required: true,
48
- allowReserved: true,
49
46
  schema: {
50
47
  type: "string"
51
48
  }
@@ -54,7 +51,6 @@ const spec = {
54
51
  name: "uid",
55
52
  in: "path",
56
53
  required: true,
57
- allowReserved: true,
58
54
  schema: {
59
55
  type: "string"
60
56
  }
@@ -368,33 +364,39 @@ const spec = {
368
364
  description: "The parts of the format that's common to all versions/kinds of entity."
369
365
  },
370
366
  NullableEntity: {
371
- type: "object",
372
- properties: {
373
- relations: {
374
- type: "array",
375
- items: {
376
- $ref: "#/components/schemas/EntityRelation"
367
+ anyOf: [
368
+ {
369
+ type: "object",
370
+ properties: {
371
+ relations: {
372
+ type: "array",
373
+ items: {
374
+ $ref: "#/components/schemas/EntityRelation"
375
+ },
376
+ description: "The relations that this entity has with other entities."
377
+ },
378
+ spec: {
379
+ $ref: "#/components/schemas/JsonObject"
380
+ },
381
+ metadata: {
382
+ $ref: "#/components/schemas/EntityMeta"
383
+ },
384
+ kind: {
385
+ type: "string",
386
+ description: "The high level entity type being described."
387
+ },
388
+ apiVersion: {
389
+ type: "string",
390
+ description: "The version of specification format for this particular entity that\nthis is written against."
391
+ }
377
392
  },
378
- description: "The relations that this entity has with other entities."
379
- },
380
- spec: {
381
- $ref: "#/components/schemas/JsonObject"
393
+ required: ["metadata", "kind", "apiVersion"],
394
+ description: "The parts of the format that's common to all versions/kinds of entity."
382
395
  },
383
- metadata: {
384
- $ref: "#/components/schemas/EntityMeta"
385
- },
386
- kind: {
387
- type: "string",
388
- description: "The high level entity type being described."
389
- },
390
- apiVersion: {
391
- type: "string",
392
- description: "The version of specification format for this particular entity that\nthis is written against."
396
+ {
397
+ type: "null"
393
398
  }
394
- },
395
- required: ["metadata", "kind", "apiVersion"],
396
- description: "The parts of the format that's common to all versions/kinds of entity.",
397
- nullable: true
399
+ ]
398
400
  },
399
401
  EntityAncestryResponse: {
400
402
  type: "object",
@@ -650,8 +652,14 @@ const spec = {
650
652
  description: 'A text to show to the user to inform about the choices made. Like, it could say\n"Found a CODEOWNERS file that covers this target, so we suggest leaving this\nfield empty; which would currently make it owned by X" where X is taken from the\ncodeowners file.'
651
653
  },
652
654
  value: {
653
- type: "string",
654
- nullable: true
655
+ oneOf: [
656
+ {
657
+ type: "string"
658
+ },
659
+ {
660
+ type: "null"
661
+ }
662
+ ]
655
663
  },
656
664
  state: {
657
665
  type: "string",
@@ -1064,6 +1072,9 @@ const spec = {
1064
1072
  items: {
1065
1073
  type: "string"
1066
1074
  }
1075
+ },
1076
+ query: {
1077
+ $ref: "#/components/schemas/JsonObject"
1067
1078
  }
1068
1079
  }
1069
1080
  },
@@ -1167,6 +1178,95 @@ const spec = {
1167
1178
  style: "form"
1168
1179
  }
1169
1180
  ]
1181
+ },
1182
+ post: {
1183
+ operationId: "QueryEntitiesByPredicate",
1184
+ tags: ["Entity"],
1185
+ description: "Query entities using predicate-based filters.",
1186
+ responses: {
1187
+ "200": {
1188
+ description: "Ok",
1189
+ content: {
1190
+ "application/json": {
1191
+ schema: {
1192
+ $ref: "#/components/schemas/EntitiesQueryResponse"
1193
+ }
1194
+ }
1195
+ }
1196
+ },
1197
+ "400": {
1198
+ $ref: "#/components/responses/ErrorResponse"
1199
+ },
1200
+ default: {
1201
+ $ref: "#/components/responses/ErrorResponse"
1202
+ }
1203
+ },
1204
+ security: [
1205
+ {},
1206
+ {
1207
+ JWT: []
1208
+ }
1209
+ ],
1210
+ requestBody: {
1211
+ required: false,
1212
+ content: {
1213
+ "application/json": {
1214
+ schema: {
1215
+ type: "object",
1216
+ properties: {
1217
+ cursor: {
1218
+ type: "string"
1219
+ },
1220
+ limit: {
1221
+ type: "number"
1222
+ },
1223
+ offset: {
1224
+ type: "number"
1225
+ },
1226
+ orderBy: {
1227
+ type: "array",
1228
+ items: {
1229
+ type: "object",
1230
+ required: ["field", "order"],
1231
+ properties: {
1232
+ field: {
1233
+ type: "string"
1234
+ },
1235
+ order: {
1236
+ type: "string",
1237
+ enum: ["asc", "desc"]
1238
+ }
1239
+ }
1240
+ }
1241
+ },
1242
+ fullTextFilter: {
1243
+ type: "object",
1244
+ properties: {
1245
+ term: {
1246
+ type: "string"
1247
+ },
1248
+ fields: {
1249
+ type: "array",
1250
+ items: {
1251
+ type: "string"
1252
+ }
1253
+ }
1254
+ }
1255
+ },
1256
+ fields: {
1257
+ type: "array",
1258
+ items: {
1259
+ type: "string"
1260
+ }
1261
+ },
1262
+ query: {
1263
+ $ref: "#/components/schemas/JsonObject"
1264
+ }
1265
+ }
1266
+ }
1267
+ }
1268
+ }
1269
+ }
1170
1270
  }
1171
1271
  },
1172
1272
  "/entity-facets": {
@@ -1223,6 +1323,57 @@ const spec = {
1223
1323
  $ref: "#/components/parameters/filter"
1224
1324
  }
1225
1325
  ]
1326
+ },
1327
+ post: {
1328
+ operationId: "QueryEntityFacetsByPredicate",
1329
+ tags: ["Entity"],
1330
+ description: "Get entity facets using predicate-based filters.",
1331
+ responses: {
1332
+ "200": {
1333
+ description: "Ok",
1334
+ content: {
1335
+ "application/json": {
1336
+ schema: {
1337
+ $ref: "#/components/schemas/EntityFacetsResponse"
1338
+ }
1339
+ }
1340
+ }
1341
+ },
1342
+ "400": {
1343
+ $ref: "#/components/responses/ErrorResponse"
1344
+ },
1345
+ default: {
1346
+ $ref: "#/components/responses/ErrorResponse"
1347
+ }
1348
+ },
1349
+ security: [
1350
+ {},
1351
+ {
1352
+ JWT: []
1353
+ }
1354
+ ],
1355
+ requestBody: {
1356
+ required: true,
1357
+ content: {
1358
+ "application/json": {
1359
+ schema: {
1360
+ type: "object",
1361
+ required: ["facets"],
1362
+ properties: {
1363
+ facets: {
1364
+ type: "array",
1365
+ items: {
1366
+ type: "string"
1367
+ }
1368
+ },
1369
+ query: {
1370
+ $ref: "#/components/schemas/JsonObject"
1371
+ }
1372
+ }
1373
+ }
1374
+ }
1375
+ }
1376
+ }
1226
1377
  }
1227
1378
  },
1228
1379
  "/locations": {
@@ -1417,7 +1568,6 @@ const spec = {
1417
1568
  in: "path",
1418
1569
  name: "id",
1419
1570
  required: true,
1420
- allowReserved: true,
1421
1571
  schema: {
1422
1572
  type: "string"
1423
1573
  }
@@ -1450,7 +1600,6 @@ const spec = {
1450
1600
  in: "path",
1451
1601
  name: "id",
1452
1602
  required: true,
1453
- allowReserved: true,
1454
1603
  schema: {
1455
1604
  type: "string"
1456
1605
  }
@@ -1489,7 +1638,6 @@ const spec = {
1489
1638
  in: "path",
1490
1639
  name: "kind",
1491
1640
  required: true,
1492
- allowReserved: true,
1493
1641
  schema: {
1494
1642
  type: "string"
1495
1643
  }
@@ -1498,7 +1646,6 @@ const spec = {
1498
1646
  in: "path",
1499
1647
  name: "namespace",
1500
1648
  required: true,
1501
- allowReserved: true,
1502
1649
  schema: {
1503
1650
  type: "string"
1504
1651
  }
@@ -1507,7 +1654,6 @@ const spec = {
1507
1654
  in: "path",
1508
1655
  name: "name",
1509
1656
  required: true,
1510
- allowReserved: true,
1511
1657
  schema: {
1512
1658
  type: "string"
1513
1659
  }